Merge branch 'evk1100-prep'
diff --git a/CHANGELOG b/CHANGELOG
index febff5d..a830c38 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,1075 @@
+commit 9e78dae2b276c5bf9ab92cd85173f6cb92b1b7d5
+Author: Vivek Kutal <vivek.kutal@azingo.com>
+Date:	Mon Feb 23 21:35:11 2009 +0530
+
+    Replaced endpoint numbers with appropriate macros in usbtty.c.
+
+    Signed-off-by: Vivek Kutal <vivek.kutal@azingo.com>
+    Signed-off-by: Remy Bohmer <linux@bohmer.net>
+
+commit a43ea5cc6d612471fbc74f0a26b2bea5864aa1d6
+Author: Jon Smirl <jonsmirl@gmail.com>
+Date:	Thu Mar 19 23:04:18 2009 -0400
+
+    .gitignore for generated files in api_examples directory
+
+    Add .gitignore for generated files in api_examples directory
+
+    Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
+commit 40281a9ca21a6b6d7b996b4d4eeaa19026337231
+Author: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+Date:	Wed Mar 18 12:27:04 2009 +0900
+
+    net: sh_eth: Remove sh_eth_reset() from halt function
+
+    sh_eth_reset is function to reset Ether IP.
+    The MAC address is stored in IP, but it is initialized by this function.
+    OS (e.g. Linux Kernel) can not use this device when initialized.
+    This revises this problem.
+
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+
+commit f8853d105da7d69bc92a5b4578f9b85234e558ec
+Author: Anatolij Gustschin <agust@denx.de>
+Date:	Fri Mar 20 12:45:50 2009 +0100
+
+    ppc4xx: Fix bug in PCI outbound map configuration for canyonlands
+
+    PCI outbound address map configuration doesn't match the
+    PCI memory address range covered by appropriate TLB entry
+    configuration for canyonlands causing machine check
+    exceptions while accessing PCI memory regions. This patch
+    provides a fix for this issue.
+
+    Kazuaki Ichinohe observed and reported this issue while
+    testing display output with PCI ATI video card on canyonlands.
+
+    Signed-off-by: Anatolij Gustschin <agust@denx.de>
+    Signed-off-by: Stefan Roese <sr@denx.de>
+
+commit 7a88601a34132548c3c591ea87ab3468b51121b0
+Author: Richard Retanubun <RichardRetanubun@RuggedCom.com>
+Date:	Fri Mar 6 10:09:37 2009 -0500
+
+    CFI: geometry reversal for STMicro M29W320DT
+
+    Follow up to the flash_fixup_stm to fix geometry reversal
+    on STMicro M29W320ET flash chip. The M29W320DT has 4 erase region.
+
+    Signed-off-by: Richard Retanubun <RichardRetanubun@RuggedCom.com>
+    Signed-off-by: Stefan Roese <sr@denx.de>
+
+commit 069f4364d807d7fdea3de7385ad2f8d83c587aec
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:	Wed Feb 25 17:29:40 2009 -0500
+
+    smc911x_eeprom: update register API
+
+    The smc911x driver changed the naming convention for its register funcs,
+    so update the eeprom code accordingly.
+
+    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+    CC: Ben Warren <biggerbadderben@gmail.com>
+
+commit 6a397ef0e6c58caab8bf427d447714bc9b3bb9d4
+Author: Grzegorz Bernacki <gjb@semihalf.com>
+Date:	Tue Mar 17 10:06:39 2009 +0100
+
+    mpc52xx: Get rid of board-specific #ifdef's in cpu/mpc5xxx/ide.c
+
+    Total5200 and digsy MTC use I2C port 2 pins as a ATA chip select.
+    To avoid adding board-specific ifdefs to cpu/mpc5xxx/ide.c new
+    define CONFIG_SYS_ATA_CS_ON_I2C2 was introduced. It is used by
+    Total5200 and will be used by digsy MTC and other boards with
+    ATA CS on I2C pins.
+
+    Signed-off-by: Grzegorz Bernacki <gjb@semihalf.com>
+
+commit 1b6275dfb173bd2edb8f208dd050d6f47ae39654
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:34 2009 +0100
+
+    8xx: add support for new keymile kmsupx4 board.
+
+    This patch adds support for the kmsupx4 board from Keymile,
+    based on a Freescale MPC852T CPU
+
+    - serial console on SMC1
+    - 32 MB SDRAM
+    - 32 MB NOR Flash
+    - Ethernet over SCC3
+    - I2C Bitbang
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit d044954fe2a7e7a3dd104eb9c9d2104e38da2911
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:28 2009 +0100
+
+    8xx, mgsuvd: rename board to a more generic name
+
+    renaming the "mgsuvd" board port into "km8xx", because
+    there come more similar boards from keymile.
+    Compiling the mgsuvd board with "make mgsuvd_config"
+    remains.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit 18b2f35bde1672e074a3d5048383cb56fda745cb
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:23 2009 +0100
+
+    8xx, mgsuvd: Coding Style cleanup config file
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit 364123db6730d32330f818b65360d2cd27396667
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:18 2009 +0100
+
+    powerpc: common updates for keymile boards
+
+    - added to keymile-common.h:
+      - bootcount support
+      - COMMAND HISTORY
+      - CONFIG_AUTO_COMPLETE
+      - CONFIG_SYS_FLASH_PROTECTION
+      - JFFS2 support
+      - CONFIG_VERSION_VARIABLE
+    - extracted common I2C settings for all boards
+    - common default environment settings summarized
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit 506f391888b82d1b83bdd749c3cea9eb2fd64df8
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:15 2009 +0100
+
+    8xx, icache: enabling ICache not before running from RAM
+
+    with the new CONFIG_SYS_DELAYED_ICACHE config option, ICache
+    is not enabled before code runs from RAM.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit cabf7b9c83bd780a5805ddbb4c0ce431d5b9f9f3
+Author: Heiko Schocher <hs@denx.de>
+Date:	Thu Mar 12 07:37:11 2009 +0100
+
+    82xx, mgcoge: fix environment sector size
+
+    Size of one environment sector is 0x20000.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit 27057d416c7cc9eb1860953da8836352c07f13e9
+Author: Ladislav Michl <ladis@linux-mips.org>
+Date:	Mon Mar 16 23:27:31 2009 +0100
+
+    NetStar: config reindentation
+
+    Fix indentation broken by symbol renames. "Sort" driver related definitons.
+
+    Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
+
+commit 8d8235f84d3ef3f29b7d14e741369b5824b5bb4a
+Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+Date:	Tue Mar 17 11:21:43 2009 +0000
+
+    ColdFire: Fix incorrect definition
+
+    Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+
+commit 9017d9325a5067b2ab0d70a2d3c907620c9ab7f8
+Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+Date:	Mon Mar 2 19:16:45 2009 +0000
+
+    ColdFire: Fix M5329EVB and M5373EVB nand issue
+
+    The Nand flash was unable to read and write properly
+    due to Nand Chip Select (nCE) setup was in reverse
+    order. Also, increase the Nand time out value to 60.
+
+    Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+
+commit 42b68af1062f75bb4a91cf47e329a7e8100cd815
+Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+Date:	Tue Jan 27 15:19:35 2009 +0000
+
+    ColdFire: PLATFORM_CPPFLAGS updates for new compiler
+
+    Update PLATFORM_CPPFLAGS to accept 4.3.x version of
+    ColdFire compiler.
+
+    Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+
+commit d6e4baf49987fc6f75e8574c0c27301a828b3132
+Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+Date:	Tue Jan 27 12:57:47 2009 +0000
+
+    ColdFire: Provide gzip image size V2 & V3 platforms
+
+    Default gzip bootm size is 8MB. Some platforms require
+    more than 8MB
+
+    Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+
+commit c3a9e6374210679a81f611c1bcf968988bc20e41
+Author: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+Date:	Wed Feb 18 11:49:31 2009 +0000
+
+    ColdFire: Fix M54451 serial boot dram setup
+
+    The serial boot dram extended/standard mode register was not
+    setup and was using default DRAM setup causing the U-boot was
+    unstable to boot up in serial mode.
+
+    Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
+
+commit 32d11d58159a575f08a982cad8a5a941ffe5cc3d
+Author: arun c <arun.edarath@gmail.com>
+Date:	Thu Dec 4 15:57:15 2008 +0530
+
+    Coldfire: XL Bus minor fixes
+
+    According to coldfire manual data timeout > address time out
+    also use correct macro to program XARB_CFG
+
+    Signed-off-by: Arun C <arunedarath@mistralsolutions.com>
+
+commit 65d8bc94d8214812ccdf3372d3fef845cf4ec2e5
+Author: Scott Wood <scottwood@freescale.com>
+Date:	Tue Mar 17 12:06:04 2009 -0500
+
+    NAND: Have nboot accept .e and .i as legacy no-ops.
+
+    This was intended to happen before, but a trivial bug prevented it.
+
+    Signed-off-by: Scott Wood <scottwood@freescale.com>
+
+commit 0987505540918b2464b73069af3a5b766dbd3ceb
+Author: Ladislav Michl <ladis@linux-mips.org>
+Date:	Fri Mar 13 14:38:19 2009 +0100
+
+    NAND: Make nboot skip bad blocks
+
+    nboot command currently does not skip bad blocks and gives read error when
+    loading image stored over bad block. With patch applied, nboot works as
+    expected:
+
+    Device 0 bad blocks:
+      00780000
+      014a0000
+      02000000
+      02cc0000
+      04aa0000
+
+    Loading from NAND 128MiB 3,3V 8-bit, offset 0x2c00000
+       Image Name:   Linux-2.6.22-omap1
+       Created:      2008-11-20  23:44:32 UTC
+       Image Type:   ARM Linux Kernel Image (uncompressed)
+       Data Size:    1052520 Bytes =  1 MB
+       Load Address: 10008000
+       Entry Point:  10008000
+    Skipping bad block 0x02cc0000
+    Automatic boot of image at addr 0x10400000 ...
+    ...
+
+    Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
+    Signed-off-by: Scott Wood <scottwood@freescale.com>
+
+commit 0b2f38fe3c4555dd2b81c69880403c13ad723153
+Author: Stefan Roese <sr@denx.de>
+Date:	Thu Mar 12 07:27:25 2009 +0100
+
+    ppc4xx: lwmon5: Only use one CS (rank) in DDR2 configuration
+
+    This patch fixes a problem spotted by Mikhail Zolotaryov on Sequoia with
+    the DDR2 configuration to only use one CS (rank). As this code is most
+    likely copied from the original Sequoia version, this error was copied
+    as well.
+
+    This patch also removes some dead code.
+
+    Signed-off-by: Stefan Roese <sr@denx.de>
+
+commit 9199b9cc8f56aca26504b48cf702176208f46e54
+Author: Stefan Roese <sr@denx.de>
+Date:	Thu Mar 12 07:24:40 2009 +0100
+
+    ppc4xx: PMC440: Only use one CS (rank) in DDR2 configuration
+
+    This patch fixes a problem spotted by Mikhail Zolotaryov on Sequoia with
+    the DDR2 configuration to only use one CS (rank). As this code is most
+    likely copied from the original Sequoia version, this error was copied
+    as well.
+
+    Signed-off-by: Stefan Roese <sr@denx.de>
+
+commit ee86fd15e1ccda4be41f1dba82b8c9efea9a3145
+Author: Mikhail Zolotaryov <lebon@lebon.org.ua>
+Date:	Wed Mar 11 10:54:46 2009 +0200
+
+    Fix AMCC Sequoia board DDR memory configuration
+
+    Sequoia board schematics (DES0211_11_SCH_11.pdf, page 5, unit U1D)
+    specifies that BankSel#1 is not connected, while bootloader memory
+    configuration is (board/amcc/sequoia/sdram.c):
+	   mtsdram(DDR0_10, 0x00000300);
+    i.e. both Chip Selects used - not correct.
+
+    If we change to correct value here:
+	   mtsdram(DDR0_10, 0x00000100);
+    memory is accessible OK also.
+
+    Signed-off-by: Mikhail Zolotaryov <lebon@lebon.org.ua>
+    Signed-off-by: Stefan Roese <sr@denx.de>
+
+commit b3dd629e78870ba2dc9f8032978721c0fa02a856
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Sun Mar 15 22:40:09 2009 +0100
+
+    Prepare 2009.03-rc2
+
+    Update CHANEGLOG, fix minor coding style issue.
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
+commit 394d30dd1ee23b80fd5e59e17ebe0feca927ab31
+Author: Jerry Van Baren <gvb.uboot@gmail.com>
+Date:	Fri Mar 13 11:40:10 2009 -0400
+
+    mpc83xx: Add bank configuration to FSL spd_sdram.c
+
+    The routine assumed 4 bank SDRAMs, enhance to configure for 4 or 8
+    bank SDRAMs.
+
+    Signed-off-by: Gerald Van Baren <vanbaren@cideas.com>
+    Acked-by: Dave Liu <daveliu@freescale.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit b581626c1e2474a3dadf69d4f0e0582eccbc4235
+Author: Norbert van Bolhuis <nvbolhuis@aimvalley.nl>
+Date:	Fri Mar 13 08:58:14 2009 +0100
+
+    mpc83xx: correctly set encryption and I2C bus 0 clock
+
+    This patch makes sure the correct mask is applied when setting
+    the encryption and I2C bus 0 clock in SCCR.
+    Failing to do so may lead to ENCCM being 0 in which case I2C bus 0
+    won't function.
+
+    Signed-off-by: Norbert van Bolhuis <nvbolhuis@aimvalley.nl>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit e6a6a704151c2d7e4a7b485545b48a6020ccca17
+Author: Dirk Behme <dirk.behme@googlemail.com>
+Date:	Thu Mar 12 19:30:50 2009 +0100
+
+    OMAP3: Add support for OMAP3 die ID
+
+    Read and store OMAP3 die ID in U-Boot environment.
+
+    Signed-off-by: Dirk Behme <dirk.behme@googlemail.com>
+
+commit f949bd8d089ec3059c460ac829c0d919e1d7af0e
+Author: Jon Smirl <jonsmirl@gmail.com>
+Date:	Wed Mar 11 15:08:56 2009 -0400
+
+    MPC5200 FEC MII speed register
+
+    Set a non-zero speed in the MII register so that MII commands will work.
+
+    Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
+
+commit 94a353611b93ac4cb4434a5f7e98aa0902da919e
+Author: Yusuke.Goda <goda.yusuke@renesas.com>
+Date:	Fri Mar 13 16:08:18 2009 +0900
+
+    sh: ap325rxa: Change the wait cycle in the area 5
+
+    Signed-off-by: Yusuke Goda <goda.yusuke@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 2db0e1278b9f11263e0a13326b57d4f99781f7ac
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Wed Feb 25 16:04:26 2009 +0900
+
+    sh: Fix cannot work rtl8139 on r2dplus
+
+    The rtl8139 driver use pci_mem_to_phys. So it need PCI system memory
+    registration.
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 64f3c0b8ba99d6651db59273e497ab5e857c8d4f
+Author: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+Date:	Fri Feb 27 18:35:41 2009 +0900
+
+    sh: Add netdev header fixing of warning/build
+
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit ada9318252f51c2626e9837c623f9812b0308dea
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Tue Mar 3 15:11:17 2009 +0900
+
+    sh: Add support 32-Bit Extended Address Mode to sh7785lcr
+
+    We can built 'make sh7785lcr_32bit_config'. And add new command "pmb"
+    for this mode. This command changes PMB for using 512MB system memory.
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 06b18163b57e6b0349b0c299222d50e7b1e41e50
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Wed Feb 25 14:26:42 2009 +0900
+
+    sh: Add some register value configurable to PCI of SH7780
+
+    Some register value was hardcoded for System memory size 128MB and
+    memory offset 0x08000000. This patch fixed the problem.
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 06e2735eb85cbea7cecb3c308d6d078b3651b22c
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Wed Feb 25 14:26:52 2009 +0900
+
+    sh: Add system memory registration to PCI for SH4
+
+    It is necessary for some pci device driver.
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit b3061b40db691245a7bb9a55354b4edacbf3902d
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Wed Feb 25 14:26:55 2009 +0900
+
+    sh: Add value for PCI system memory registration of sh7785lcr
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 6d84ae3956a6cd7aebd86f661130752594e60124
+Author: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+Date:	Tue Mar 3 15:11:08 2009 +0900
+
+    sh: Add macros for SH-4A 32-Bit Address Extended Mode
+
+    Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 3e3eec39de8fe0ae62e6e4d4e3fa4442ee9ed6b1
+Author: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+Date:	Tue Feb 3 13:35:05 2009 +0900
+
+    sh: use write{8,16,32} in ms7720se lowlevel_init
+
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+
+commit 0452352df118bc9dd684a056aaaa5fb4aed1178a
+Author: Paul Gortmaker <paul.gortmaker@windriver.com>
+Date:	Mon Mar 9 18:07:53 2009 -0500
+
+    tsec: report when there is no vendor specific PHY support
+
+    Commit af1c2b84 added a generic phy support, with an ID of zero
+    and a 32 bit mask; meaning that it will match on any PHY ID.
+
+    The problem is that there is a test that checked if a matching
+    PHY was found, and if not, it printed the non-matching ID.
+    But since there will always be a match (on the generic PHY,
+    worst case), this test will never trip.
+
+    In the case of a misconfigured PHY address, or of a PHY that
+    isn't explicitly supported outside of the generic support,
+    you will never see the ID of 0xffffffff, or the ID of the
+    real (but unsupported) chip.  It will silently fall through
+    onto the generic support.
+
+    This change makes that test useful again, and ensures that
+    the selection of generic PHY support doesn't happen without
+    some sort of notice.  It also makes it explicitly clear that
+    the generic PHY must be last in the PHY table.
+
+    Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+    Acked-by: Andy Fleming <afleming@freescale.com>
+
+commit c279dfc10186ceba78d3862036f158750e86599a
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Mon Mar 9 10:53:05 2009 +0100
+
+    SIMPC8313 board: fix out of tree building.
+
+    Fix typo in makefile which broke out of tree builds.
+
+    Also use expolicit "rm" instead of "ln -sf" which is known to be
+    unreliable.
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 49b5aff491bd574935ecaf8545152066a25eff3d
+Author: ksi@koi8.net <ksi@koi8.net>
+Date:	Mon Feb 23 10:53:13 2009 -0800
+
+    Add eTSEC 1/2 IO override control (corrected)
+
+    This adds tsec12ioovcr to include/asm-ppc/immap_85xx.h (was reserved.)
+
+    Signed-off-by: Sergey Kubushyn <ksi@koi8.net>
+
+commit 48c2b7bb432da84fcce05b4db6efad0be73a93dc
+Author: Andy Fleming <afleming@freescale.com>
+Date:	Fri Mar 6 19:05:52 2009 -0600
+
+    fsl: Remove unnecessary debug printfs
+
+    These were left in accidentally, and are not really useful unless the
+    code is as broken as it was when it was being developed.
+
+    Signed-off-by: Andy Fleming <afleming@freescale.com>
+
+commit 0ee84b88b78bce425190d8cd7adf4c30cba0c2f0
+Author: Ed Swarthout <Ed.Swarthout@freescale.com>
+Date:	Tue Feb 24 02:37:59 2009 -0600
+
+    Fix mpc85xx ddr-gen3 ddr_sdram_cfg.
+
+    Commit e1be0d25, "32bit BUg fix for DDR2 on 8572" prevented other
+    sdram_cfg bits (such as ecc and self_refresh_in_sleep) from being set.
+
+    Signed-off-by: Ed Swarthout <Ed.Swarthout@freescale.com>
+
+commit a922fdb87af25c25c032424908dcf60fbf3250ea
+Author: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date:	Tue Feb 24 06:13:10 2009 +0100
+
+    PXA: timer use do_div and simplify it
+
+    Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+commit 4b00d1aa82b6af9b4e628a5729a12086e44558b3
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Mon Mar 9 10:51:39 2009 +0100
+
+    SIMPC8313 board: fix out of tree building.
+
+    Fix typo in makefile which broke out of tree builds.
+
+    Also use expolicit "rm" instead of "ln -sf" which is known to be
+    unreliable.
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
+commit f70fd13e2fe4cf58e251271c27f9c06e141d7f9a
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:51 2009 +0100
+
+    8360, kmeter1: added bootcount feature.
+
+    add CONFIG_BOOTCOUNT_LIMIT feature for 8360 CPU.
+
+    The bootcounter uses 8 bytes from the muram,
+    because no other memory was found on this
+    CPU for the bootcount feature. So we must
+    correct the muram size in DTS before booting
+    Linux.
+
+    This feature is actual only implemented for
+    MPC8360, because not all 83xx CPU have qe,
+    and therefore no muram, which this feature
+    uses.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 1e7ed2565031e01abc18c713030a0a9829c07684
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:48 2009 +0100
+
+    83xx, kmeter: QE_ENET10 errata for Silicon Revision 2.1
+
+    old code implemented the QE_ENET10 errata only for Silicon
+    Revision 2.0. New code reads now the Silicon Revision
+    register and sets dependend on the Silicon Revision the
+    values as advised in the QE_ENET10 errata.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 605f78e34a3f0103693b891f2573edd352e7d495
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:44 2009 +0100
+
+    83xx, kmeter1: updates for 2009.03
+
+    - HRCW update
+      HRCWH_BOOTSEQ_DISABLE not HRCWH_BOOTSEQ_NORMAL
+      HRCWH_LALE_EARLY added
+    - DDR-SDRAM settings modified. This solves sporadically
+      problems with this memory.
+    - CS1 now 128 MB window size
+    - CS3 now 512 MB window size
+    - PRAM activated
+    - MTDPARTS_DEFAULT defined
+    - CONFIG_HOSTNAME added
+    - MONITOR_LEN now 384 KB
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 118cbe3c35c898f8d020b29d6dc180307cacf147
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:40 2009 +0100
+
+    83xx, kmeter1: autodetect size of DDR II RAM
+
+    it is possible that some board variants have different DDR II
+    RAM sizes. So we autodetect the size of the assembled RAM.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit c1bce4fff750d734b1fa7467eb08f93902c97ca6
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:37 2009 +0100
+
+    83xx, i2c: add mux support for fsl_i2c
+
+    This patch adds I2C mux support for the fsl_i2c driver. This
+    allows you to add "new" i2c busses, which are reached over
+    i2c muxes. For more infos, please look in the README and
+    search for CONFIG_I2C_MUX.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 19f0e93041dbfe22f8d39b98e4f7f9ea87b77803
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:34 2009 +0100
+
+    83xx, kmeter1: add I2C, dtt, eeprom support
+
+    This patch adds I2C support for the Keymile kmeter1 board.
+    It uses the First I2C Controller from the CPU, for
+    accessing 4 temperature sensors, an eeprom with IVM data
+    and the booteeprom over a pca9547 mux.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit db1d72afd77287bc8577210f3f71ab249dcf146f
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 24 11:30:30 2009 +0100
+
+    i2c, dtt: move dtt_init () to board_init_r ()
+
+    In case where a board not uses CONFIG_POST, it is not
+    necessary to init the DTTs when running from flash.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 5b0055547f0246908b79cc300170d87380b69e18
+Author: Dave Liu <daveliu@freescale.com>
+Date:	Wed Feb 25 12:31:32 2009 +0800
+
+    83xx: Fix some bugs in spd sdram code
+
+    1. RD_TO_PRE missed to add the AL, and need min 2 clocks for
+      tRTP according to DDR2 JEDEC spec.
+    2. WRTORD - tWTR need min 2 clocks according to DDR2 JEDEC spec.
+    3. add the support of DDR2-533,667,800 DIMMs
+    4. cpo
+    5. make the AL to min to gain better performance.
+
+    The Micron MT9HTF6472CHY-667D1 DIMMs test passed on
+    MPC837xEMDS platform at 266MHz/333MHz/400MHz data rate.
+
+    items 1, 2 and 5:
+    Acked-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
+
+    Reported-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit b7be63abec45858c044f0fbd6aeef524c4663f9b
+Author: Valeriy Glushkov <gvv@lstec.com>
+Date:	Wed Feb 4 18:27:49 2009 +0200
+
+    MPC8349ITX: several config issues fixed
+
+    The previous version rebooted forever with DDR bigger than 256MB.
+    Access the DS1339 RTC chip is on I2C1 bus.
+    Allow DHCP.
+
+    Signed-off-by: Valeriy Glushkov <gvv@lstec.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 7e2ec1de1d2d723b59d7dd2fb85ff71b952d63af
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:39 2009 +0300
+
+    mpc83xx: MPC837XEMDS: Initialize SerDes before negating PCIE reset signal
+
+    The SerDes initialization should be finished before negating the reset
+    signal according to the reference manual. This isn't an issue on real
+    hardware, but we'd better stick to the specifications anyway.
+
+    Suggested-by: Liu Dave <DaveLiu@freescale.com>
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 9c2d63ec0e9520948b6d598ea32e9aa4e0de847f
+Author: Heiko Schocher <hs@denx.de>
+Date:	Wed Feb 25 12:28:32 2009 +0100
+
+    i2c, dtt: move dtt_init () to board_init_r ()
+
+    it is not necessary to init the DTTs so early,
+    so move this init to board_init_r ().
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+
+commit 00cc5595a7caac8066b408774383a956c2e26797
+Author: Anatolij Gustschin <agust@denx.de>
+Date:	Wed Feb 25 20:28:13 2009 +0100
+
+    lcd: Fix compilation warning in common/lcd.c
+
+    Fix following warning while compilation for mcc200 board:
+
+    lcd.c: In function 'lcd_display_bitmap':
+    lcd.c:625: warning: unused variable 'cmap'
+
+    Signed-off-by: Anatolij Gustschin <agust@denx.de>
+
+commit f5a77a09c93fe7f04c0c56f64ea436f7d318d674
+Author: Graeme Russ <graeme.russ@gmail.com>
+Date:	Tue Feb 24 21:11:24 2009 +1100
+
+    Moved SC520 Files (fix commit 407976185e0dda2c90e89027121a1071b9c77bfb)
+
+    Fixes commit 407976185e0dda2c90e89027121a1071b9c77bfb
+
+    Signed-off-by: Graeme Russ <graeme.russ at gmail.com>
+
+commit 75ba6d693b8f6247aa4b81323a2ee2fa28222215
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:	Mon Feb 23 10:29:47 2009 -0500
+
+    smc911x: split out useful defines/functions into local header
+
+    The smc911x driver has a lot of useful defines/functions which can be used
+    by pieces of code (such as example eeprom programmers).  Rather than
+    forcing each place to duplicate these defines/functions, split them out
+    of the smdc911x driver into a local header.
+
+    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+    Acked-by: Ben Warren <biggerbadderben@gmail.com>
+    CC: Sascha Hauer <s.hauer@pengutronix.de>
+    CC: Guennadi Liakhovetski <lg@denx.de>
+    CC: Magnus Lilja <lilja.magnus@gmail.com>
+    CC: Ben Warren <biggerbadderben@gmail.com>
+
+commit a2bb7105a79af8f2ffa9f87256fce6c1cbcbd8e1
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Tue Feb 24 10:44:02 2009 +0100
+
+    ARM: add an "eet" variant of the imx31_phycore board
+
+    The "eet" variant of the imx31_phycore board has an OLED display, using a
+    s6e63d6 display controller on the first SPI interface, using GPIO57 as a
+    chip-select for it. With this configuration you can display 256 colour BMP
+    images in 16-bit RGB (RGB565) LCD mode.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+commit 0c99f6ab31c5635874ba7a2e8d37791bfbf02f8f
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Fri Feb 6 10:37:57 2009 +0100
+
+    video: add an i.MX31 framebuffer driver
+
+    Add a driver for the Synchronous Display Controller and the Display
+    Interface on i.MX31, using IPU for DMA channel setup. So far only
+    displaying of bitmaps is supported, no text output.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Anatolij Gustschin <agust@denx.de>
+
+commit b245e65ee3c4cce3ccf008a21f4528239655876c
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Fri Feb 6 10:37:53 2009 +0100
+
+    LCD: support 8bpp BMPs on 16bpp displays
+
+    This patch also simplifies some ifdefs in lcd.c, introduces a generic
+    vidinfo_t, which new drivers are encouraged to use and old drivers to switch
+    over to.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Anatolij Gustschin <agust@denx.de>
+
+commit a303dfb0e9a93e516ea9427b5c09543d5f74ade1
+Author: Mark Jackson <mpfj@mimc.co.uk>
+Date:	Fri Feb 6 10:37:49 2009 +0100
+
+    Add 16bpp BMP support
+
+    This patch adds 16bpp BMP support to the common lcd code.
+
+    Use CONFIG_BMP_16BPP and set LCD_BPP to LCD_COLOR16 to enable the code.
+
+    At the moment it's only been tested on the MIMC200 AVR32 board, but extending
+    this to other platforms should be a simple task !!
+
+    Signed-off-by: Mark Jackson <mpfj@mimc.co.uk>
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Anatolij Gustschin <agust@denx.de>
+
+commit 689551c5ff1b394b88412f3df22144e79468d3a9
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Fri Feb 6 10:37:41 2009 +0100
+
+    A driver for the S6E63D6 SPI display controller from Samsung
+
+    This is a driver for the S6E63D6 SPI OLED display controller from Samsung.
+    It only provides access to controller's registers so the client can freely
+    configure it.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Anatolij Gustschin <agust@denx.de>
+
+commit fc7a93c84f3f134484811a0d9ad751fbc1a7da6d
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Fri Feb 13 09:26:40 2009 +0100
+
+    i.MX31: support GPIO as a chip-select in the mxc_spi driver
+
+    Some SPI devices have special requirements on chip-select handling.
+    With this patch we can use a GPIO as a chip-select and strictly follow
+    the SPI_XFER_BEGIN and SPI_XFER_END flags.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+commit b30de3cccf8867566cd314e7c7033904afa5dc9d
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Sat Feb 7 01:18:07 2009 +0100
+
+    i.MX31: add a simple gpio driver
+
+    This is a minimal driver, so far only managing output. It will
+    be used by the mxc_spi.c driver.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+commit f9b6a1575d9f1ca192e4cb60e547aa66f08baa3f
+Author: Guennadi Liakhovetski <lg@denx.de>
+Date:	Sat Feb 7 00:09:12 2009 +0100
+
+    i.MX31: fix SPI driver for shorter than 32 bit
+
+    Fix setting the SPI Control register, 8 and 16-bit transfers
+    and a wrong pointer in the free routine in the mxc_spi driver.
+
+    Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
+    Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+commit 7e91558032a0c1932dd7f4f562f9c7cc55efc496
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:52 2009 +0300
+
+    mpc83xx: MPC837XERDB: Add PCIe support
+
+    On MPC8377E-RDB and MPC8378E-RDB boards we have PCIe and mini-PCIe
+    slots. Let's support them.
+
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit 50a4d08e8f31debbd4ea12caf1265f3643c38d5b
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:50 2009 +0300
+
+    mpc83xx: PCI: Fix hard-coded first_busno value
+
+    We should use pci_last_busno() in pci_init_bus(), otherwise we'll
+    erroneously re-use PCI0's first_busno for PCI1 hoses.
+
+    NOTE: The patch is untested. All MPC83xx FSL boards I have have
+    PCI1 in miniPCI form, for which I don't have any cards handy.
+
+    But looking in cpu/mpc85xx/pci.c:
+    ...
+    #ifdef CONFIG_MPC85XX_PCI2
+	    hose = &pci_hose[1];
+
+	    hose->first_busno = pci_hose[0].last_busno + 1;
+
+    And considering that we do the same for MPC83xx PCI-E support,
+    I think this patch is correct.
+
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit a5878d427128c1a9226045ebe05fbadaa02eb9dd
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:46 2009 +0300
+
+    mpc83xx: PCI: Fix bus-range fdt fixups for PCI1 controllers
+
+    This patch fixes copy-paste issue: pci_hose[0]'s first and last
+    busnos were used to fixup pci1's nodes.
+
+    We don't see this bug triggering only because Linux reenumerate
+    buses anyway.
+
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit b24a99f6666ac278ec9f9c1334518af828833d19
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:44 2009 +0300
+
+    mpc83xx: PCIe: Fix CONFIG_PCI_SCAN_SHOW reporting bogus values
+
+    This patch fixes an issue in config space read accessors: we should
+    fill-in the value even if we fail (e.g. skipping devices), otherwise
+    CONFIG_PCI_SCAN_SHOW reports bogus values during boot up.
+
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit e2d72ba543c7b6924b5b5d393dcd80b2b9c3a022
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:42 2009 +0300
+
+    mpc83xx: PCIe: Don't start bus enumeration at 0
+
+    Currently we assign first_busno = 0 for the first PCIe hose, but this
+    scheme won't work if we have ordinary PCI hose already registered (its
+    first_busno value is 0 too).
+
+    The old code worked fine only because we have PCI disabled on
+    MPC837XEMDS boards in stand-alone mode (see commit 00f7bbae92e3b13f2b3
+    "mpc83xx: fix PCI scan hang on the standalone MPC837xE-MDS boards").
+    But on MPC837XERDB boards we have PCI and PCIe, so the bug actually
+    triggers.
+
+    So, to fix the issue, we should use pci_last_busno() + 1 for the
+    first_busno (i.e. last available busno).
+
+    Reported-by: Huang Changming <Chang-Ming.Huang@freescale.com>
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit cc2a8c7751ddbae3116660064f446888538b93e9
+Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+Date:	Thu Feb 19 18:20:41 2009 +0300
+
+    PCI: Add pci_last_busno() helper
+
+    This is just a handy routine that reports last PCI busno: we walk
+    down all the hoses and return last hose's last_busno.
+
+    Will be used by PCI/PCIe initialization code.
+
+    Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit bd76729bcbfd64b5d016a9b936f058931fc06eaf
+Author: Becky Bruce <beckyb@kernel.crashing.org>
+Date:	Mon Feb 23 13:56:51 2009 -0600
+
+    MPC86xx: set CONFIG_MAX_MEM_MAPPED to 2G by default
+
+    Currently, we get 256MB as the default, but since all the 86xx
+    board configs define a 2G BAT mapping for RAM, raise default
+    to 2G.
+
+    Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
+    Acked-by: Jon Loeliger <jdl@freescale.com>
+
+commit 2331e18b9df0ab98ebf3ab44c0efea1311949aaa
+Author: Becky Bruce <beckyb@kernel.crashing.org>
+Date:	Thu Feb 12 10:43:32 2009 -0600
+
+    mpc8641hpcn: Indicate 36-bit addr map in boot messages
+
+    If 36-bit addressing is enabled, print a message on the console
+    when we boot.
+
+    Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
+
+commit 2f70c49e5b9813635ad73666aa30f304c7fdeda9
+Author: Heiko Schocher <hs@denx.de>
+Date:	Tue Feb 10 09:38:52 2009 +0100
+
+    netloop: speed up NetLoop
+
+    NetLoop polls every cycle with getenv some environment variables.
+    This is horribly slow, especially when the environment is big.
+
+    This patch reads only the environment variables in NetLoop,
+    when they were changed.
+
+    Also moved the init part of the NetLoop function in a seperate
+    function.
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
+
+commit ad2d16393e9f684e4a9255f42e8bfdd819b67a87
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:	Mon Dec 22 02:56:07 2008 -0500
+
+    smc911x_eeprom: new example app for managing newer SMC parts
+
+    A forward port of the last version to work with the newer smc911x driver.
+    I only have a board with a LAN9218 part on it, so that is the only one
+    I've tested.  But there isn't anything in this that would make it terribly
+    chip specific afaik.
+
+    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+    CC: Sascha Hauer <s.hauer@pengutronix.de>
+    CC: Guennadi Liakhovetski <lg@denx.de>
+    CC: Magnus Lilja <lilja.magnus@gmail.com>
+    Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
+
+commit 736323a490b664ec0edc3ddb2c1c4a6824db45c6
+Author: Pieter Henning <phenning@vastech.co.za>
+Date:	Sun Feb 22 23:17:15 2009 -0800
+
+    Added Vitesse VSC8211 definitions to TSEC driver
+
+    Added the struct containing PHY settings for the Vitesse VSC8211 phy to
+    the phy_info list in tsec.c
+
+    Signed-off-by: Pieter Henning <phenning@vastech.co.za>
+    Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
+
+commit 32688e572ff96715b41420e9a7f280db6c399b65
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Mon Feb 23 00:22:21 2009 +0100
+
+    Update CHANGELOG;  Prepare 2009.03-rc1
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
 commit 80b827c2b78329c6503b271e43d9eb693d644710
 Author: Wolfgang Denk <wd@denx.de>
 Date:	Sun Feb 22 23:45:40 2009 +0100
@@ -775,6 +1847,27 @@
 
     Signed-off-by: Wolfgang Denk <wd@denx.de>
 
+commit 2b68b23373f96199a0cafbfd7a9f79ed62381ebb
+Author: Heiko Schocher <hs@denx.de>
+Date:	Wed Feb 11 19:26:15 2009 +0100
+
+    83xx: add missing TIMING_CFG1_CASLAT_* defines
+
+    Signed-off-by: Heiko Schocher <hs@denx.de>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
+commit c9e34fe2e86f7b6cc8260f4b24cbdc7dd81e04c5
+Author: Valeriy Glushkov <gvv@lstec.com>
+Date:	Thu Feb 5 14:35:21 2009 +0200
+
+    mpc8349itx: allow SATA boot from the onboard SIL1334
+
+    This patch allows using of SATA devices connected
+    to the onboard PCI SIL1334 SATA controller.
+
+    Signed-off-by: Valeriy Glushkov <gvv@lstec.com>
+    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
+
 commit e1ac387f4645499746856adc1aeaa9787da2eca6
 Author: Andy Fleming <afleming@freescale.com>
 Date:	Thu Oct 30 16:50:14 2008 -0500
diff --git a/MAINTAINERS b/MAINTAINERS
index c3157d9..ce25c1b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -380,6 +380,7 @@
 	ids8247		MPC8247
 	jupiter		MPC5200
 	kmeter1		MPC8360
+	kmsupx4		MPC852T
 	mgcoge		MPC8247
 	mgsuvd		MPC852
 	mucmc52		MPC5200
diff --git a/MAKEALL b/MAKEALL
index f8c912b..32d95db 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -47,6 +47,7 @@
 	BC3450		\
 	cm5200		\
 	cpci5200	\
+	digsy_mtc	\
 	EVAL5200	\
 	fo300		\
 	icecube_5100	\
@@ -117,6 +118,7 @@
 	KUP4X		\
 	LANTEC		\
 	lwmon		\
+	kmsupx4		\
 	MBX		\
 	MBX860T		\
 	mgsuvd		\
diff --git a/Makefile b/Makefile
index 3d0b986..63b9909 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@
 VERSION = 2009
 PATCHLEVEL = 03
 SUBLEVEL =
-EXTRAVERSION = -rc1
+EXTRAVERSION =
 ifneq "$(SUBLEVEL)" ""
 U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 else
@@ -210,6 +210,7 @@
 
 LIBS  = lib_generic/libgeneric.a
 LIBS += lib_generic/lzma/liblzma.a
+LIBS += lib_generic/lzo/liblzo.a
 LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
 	"board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
 LIBS += cpu/$(CPU)/lib$(CPU).a
@@ -221,7 +222,8 @@
 endif
 LIBS += lib_$(ARCH)/lib$(ARCH).a
 LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
-	fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a
+	fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a \
+	fs/ubifs/libubifs.a
 LIBS += net/libnet.a
 LIBS += disk/libdisk.a
 LIBS += drivers/bios_emulator/libatibiosemu.a
@@ -527,6 +529,22 @@
 cpci5200_config:  unconfig
 	@$(MKCONFIG) -a cpci5200  ppc mpc5xxx cpci5200 esd
 
+digsy_mtc_config \
+digsy_mtc_LOWBOOT_config	\
+digsy_mtc_RAMBOOT_config:	unconfig
+	@mkdir -p $(obj)include
+	@mkdir -p $(obj)board/digsy_mtc
+	@ >$(obj)include/config.h
+	@[ -z "$(findstring LOWBOOT_,$@)" ] || \
+		{ echo "TEXT_BASE = 0xFF000000" >$(obj)board/digsy_mtc/config.tmp ; \
+		  echo "... with LOWBOOT configuration" ; \
+		}
+	@[ -z "$(findstring RAMBOOT_,$@)" ] || \
+		{ echo "TEXT_BASE = 0x00100000" >$(obj)board/digsy_mtc/config.tmp ; \
+		  echo "... with RAMBOOT configuration" ; \
+		}
+	@$(MKCONFIG) -a digsy_mtc  ppc mpc5xxx digsy_mtc
+
 hmi1001_config:	unconfig
 	@$(MKCONFIG) hmi1001 ppc mpc5xxx hmi1001
 
@@ -921,6 +939,9 @@
 		 }
 	@$(MKCONFIG) -a IVMS8 ppc mpc8xx ivm
 
+kmsupx4_config:		unconfig
+	@$(MKCONFIG) $(@:_config=) ppc mpc8xx km8xx keymile
+
 KUP4K_config	:	unconfig
 	@$(MKCONFIG) $(@:_config=) ppc mpc8xx kup4k kup
 
@@ -938,7 +959,7 @@
 	@$(MKCONFIG) $(@:_config=) ppc mpc8xx mbx8xx
 
 mgsuvd_config:		unconfig
-	@$(MKCONFIG) $(@:_config=) ppc mpc8xx mgsuvd keymile
+	@$(MKCONFIG) $(@:_config=) ppc mpc8xx km8xx keymile
 
 MHPC_config:		unconfig
 	@$(MKCONFIG) $(@:_config=) ppc mpc8xx mhpc eltec
@@ -3029,8 +3050,12 @@
 imx31_litekit_config	: unconfig
 	@$(MKCONFIG) $(@:_config=) arm arm1136 imx31_litekit NULL mx31
 
+imx31_phycore_eet_config \
 imx31_phycore_config	: unconfig
-	@$(MKCONFIG) $(@:_config=) arm arm1136 imx31_phycore NULL mx31
+	@if [ -n "$(findstring _eet_,$@)" ]; then			\
+		echo "#define CONFIG_IMX31_PHYCORE_EET" >> $(obj)include/config.h;	\
+	fi
+	@$(MKCONFIG) -a imx31_phycore arm arm1136 imx31_phycore NULL mx31
 
 mx31ads_config		: unconfig
 	@$(MKCONFIG) $(@:_config=) arm arm1136 mx31ads freescale mx31
@@ -3394,10 +3419,23 @@
 	@echo "#define CONFIG_SH7763RDP 1" > $(obj)include/config.h
 	@$(MKCONFIG) -a $(@:_config=) sh sh4 sh7763rdp renesas
 
+xtract_sh7785lcr = $(subst _32bit,,$(subst _config,,$1))
+sh7785lcr_32bit_config \
 sh7785lcr_config  :   unconfig
 	@ >include/config.h
 	@echo "#define CONFIG_SH7785LCR 1" >> include/config.h
-	@$(MKCONFIG) -a $(@:_config=) sh sh4 sh7785lcr renesas
+	@if [ "$(findstring 32bit, $@)" ] ; then \
+		echo "#define CONFIG_SH_32BIT 1" >> $(obj)include/config.h ; \
+		cp $(obj)board/renesas/sh7785lcr/u-boot_32bit \
+			$(obj)board/renesas/sh7785lcr/u-boot.lds ; \
+		echo "TEXT_BASE = 0x8ff80000" > \
+			$(obj)board/renesas/sh7785lcr/config.tmp ; \
+		  $(XECHO) " ... enable 32-Bit Address Extended Mode" ; \
+	else \
+		cp $(obj)board/renesas/sh7785lcr/u-boot_29bit \
+			$(obj)board/renesas/sh7785lcr/u-boot.lds ; \
+	fi
+	@$(MKCONFIG) -a $(call xtract_sh7785lcr,$@) sh sh4 sh7785lcr renesas
 
 ap325rxa_config  :   unconfig
 	@mkdir -p $(obj)include
diff --git a/README b/README
index 43fb1c0..32d9acd 100644
--- a/README
+++ b/README
@@ -318,6 +318,11 @@
 		that this requires a (stable) reference clock (32 kHz
 		RTC clock or CONFIG_SYS_8XX_XIN)
 
+		CONFIG_SYS_DELAYED_ICACHE
+
+		Define this option if you want to enable the
+		ICache only when Code runs from RAM.
+
 - Intel Monahans options:
 		CONFIG_SYS_MONAHANS_RUN_MODE_OSC_RATIO
 
@@ -631,6 +636,7 @@
 		CONFIG_CMD_MISC		  Misc functions like sleep etc
 		CONFIG_CMD_MMC		* MMC memory mapped support
 		CONFIG_CMD_MII		* MII utility commands
+		CONFIG_CMD_MTDPARTS	* MTD partition support
 		CONFIG_CMD_NAND		* NAND support
 		CONFIG_CMD_NET		  bootp, tftpboot, rarpboot
 		CONFIG_CMD_PCA953X	* PCA953x I2C gpio commands
diff --git a/api_examples/.gitignore b/api_examples/.gitignore
new file mode 100644
index 0000000..272816f
--- /dev/null
+++ b/api_examples/.gitignore
@@ -0,0 +1,7 @@
+crc32.c
+ctype.c
+demo
+demo.bin
+ppcstring.S
+string.c
+vsprintf.c
diff --git a/board/AtmarkTechno/suzaku/u-boot.lds b/board/AtmarkTechno/suzaku/u-boot.lds
index b38f648..5a08680 100644
--- a/board/AtmarkTechno/suzaku/u-boot.lds
+++ b/board/AtmarkTechno/suzaku/u-boot.lds
@@ -38,7 +38,7 @@
 	.rodata ALIGN(0x4):
 	{
 		__rodata_start = .;
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		__rodata_end = .;
 	}
 
diff --git a/board/BuS/EB+MCF-EV123/u-boot.lds b/board/BuS/EB+MCF-EV123/u-boot.lds
index b22b332..3450793 100644
--- a/board/BuS/EB+MCF-EV123/u-boot.lds
+++ b/board/BuS/EB+MCF-EV123/u-boot.lds
@@ -73,8 +73,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/LEOX/elpt860/u-boot.lds b/board/LEOX/elpt860/u-boot.lds
index 9b9b980..c6b1f94 100644
--- a/board/LEOX/elpt860/u-boot.lds
+++ b/board/LEOX/elpt860/u-boot.lds
@@ -87,10 +87,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/MAI/AmigaOneG3SE/enet.c b/board/MAI/AmigaOneG3SE/enet.c
index 0b4dfe6..ac969a9 100644
--- a/board/MAI/AmigaOneG3SE/enet.c
+++ b/board/MAI/AmigaOneG3SE/enet.c
@@ -600,7 +600,7 @@
 	ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
 	ias_cmd->status = cpu_to_le32 (1 << 31);	/* set DnIndicate bit.                  */
 	ias_cmd->next = 0;
-	ias_cmd->addr = cpu_to_le32 ((u32) & bis->bi_enetaddr[0]);
+	ias_cmd->addr = cpu_to_le32 ((u32) dev->enetaddr);
 	ias_cmd->length = cpu_to_le32 (6 | LAST_FRAG);
 
 	/* Tell the adapter where the TX ring is located */
@@ -787,6 +787,10 @@
 	unsigned int checksum = 0;
 	int i, j, timer;
 
+	/* First, try the env ... if that works, we're all done! */
+	if (eth_getenv_enetaddr("ethaddr", hw_addr))
+		goto Done;
+
 	/* Read the station address from the EEPROM. */
 
 	EL3WINDOW (dev, 0);
@@ -827,40 +831,10 @@
 		hw_addr[j + 1] = (u8) ((ETH_INW (dev, j) >> 8) & 0xff);
 	}
 
-	for (i = 0; i < ETH_ALEN; i++) {
-		if (hw_addr[i] != bis->bi_enetaddr[i]) {
-/*			printf("Warning: HW address don't match:\n"); */
-/*			printf("Address in 3Com Window 2 is	    " */
-/*			       "%02X:%02X:%02X:%02X:%02X:%02X\n", */
-/*			       hw_addr[0], hw_addr[1], hw_addr[2], */
-/*			       hw_addr[3], hw_addr[4], hw_addr[5]); */
-/*			printf("Address used by U-Boot is " */
-/*			       "%02X:%02X:%02X:%02X:%02X:%02X\n", */
-/*			       bis->bi_enetaddr[0], bis->bi_enetaddr[1],  */
-/*			       bis->bi_enetaddr[2], bis->bi_enetaddr[3],  */
-/*			       bis->bi_enetaddr[4], bis->bi_enetaddr[5]); */
-/*			goto Done; */
-			char buffer[256];
-
-			if (bis->bi_enetaddr[0] == 0
-			    && bis->bi_enetaddr[1] == 0
-			    && bis->bi_enetaddr[2] == 0
-			    && bis->bi_enetaddr[3] == 0
-			    && bis->bi_enetaddr[4] == 0
-			    && bis->bi_enetaddr[5] == 0) {
-
-				sprintf (buffer,
-					 "%02X:%02X:%02X:%02X:%02X:%02X",
-					 hw_addr[0], hw_addr[1], hw_addr[2],
-					 hw_addr[3], hw_addr[4], hw_addr[5]);
-				setenv ("ethaddr", buffer);
-			}
-		}
-	}
-
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->enetaddr[i] = hw_addr[i];
+	/* Save the result in the environment */
+	eth_setenv_enetaddr("ethaddr", hw_addr);
 
 Done:
+	memcpy(dev->enetaddr, hw_addr, 6);
 	return;
 }
diff --git a/board/MAI/AmigaOneG3SE/u-boot.lds b/board/MAI/AmigaOneG3SE/u-boot.lds
index e107b47..66440da 100644
--- a/board/MAI/AmigaOneG3SE/u-boot.lds
+++ b/board/MAI/AmigaOneG3SE/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/Marvell/db64360/u-boot.lds b/board/Marvell/db64360/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/Marvell/db64360/u-boot.lds
+++ b/board/Marvell/db64360/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/Marvell/db64460/u-boot.lds b/board/Marvell/db64460/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/Marvell/db64460/u-boot.lds
+++ b/board/Marvell/db64460/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/RPXClassic/RPXClassic.c b/board/RPXClassic/RPXClassic.c
index 9fdf700..5aa713f 100644
--- a/board/RPXClassic/RPXClassic.c
+++ b/board/RPXClassic/RPXClassic.c
@@ -105,7 +105,7 @@
  * board_get_enetaddr -- Read the MAC Address in the I2C EEPROM
  *-----------------------------------------------------------------------------
  */
-void board_get_enetaddr (uchar * enet)
+static void board_get_enetaddr(uchar *enet)
 {
 	int i;
 	char buff[256], *cp;
@@ -142,9 +142,19 @@
 	enet[3] |= 0x80;
 #endif
 
-	printf ("MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n",
-		enet[0], enet[1], enet[2], enet[3], enet[4], enet[5]);
+	printf("MAC address = %pM\n", enet);
+}
 
+int misc_init_r(void)
+{
+	uchar enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+
+	return 0;
 }
 
 void rpxclassic_init (void)
diff --git a/board/RPXClassic/u-boot.lds b/board/RPXClassic/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/RPXClassic/u-boot.lds
+++ b/board/RPXClassic/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/RPXlite/u-boot.lds b/board/RPXlite/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/RPXlite/u-boot.lds
+++ b/board/RPXlite/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/RPXlite_dw/u-boot.lds b/board/RPXlite_dw/u-boot.lds
index 8d17894..7b7b83b 100644
--- a/board/RPXlite_dw/u-boot.lds
+++ b/board/RPXlite_dw/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/RRvision/u-boot.lds b/board/RRvision/u-boot.lds
index 9fd77f8..17e6fa0 100644
--- a/board/RRvision/u-boot.lds
+++ b/board/RRvision/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/actux1/u-boot.lds b/board/actux1/u-boot.lds
index ccdb78e..836775f 100644
--- a/board/actux1/u-boot.lds
+++ b/board/actux1/u-boot.lds
@@ -43,7 +43,7 @@
 
 	. = ALIGN (4);
 	.rodata : {
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN (4);
 	.data : {
diff --git a/board/actux2/u-boot.lds b/board/actux2/u-boot.lds
index 1131936..0752656 100644
--- a/board/actux2/u-boot.lds
+++ b/board/actux2/u-boot.lds
@@ -45,7 +45,7 @@
 
 	. = ALIGN (4);
 	.rodata : {
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN (4);
diff --git a/board/actux3/u-boot.lds b/board/actux3/u-boot.lds
index e861955..a69e7db 100644
--- a/board/actux3/u-boot.lds
+++ b/board/actux3/u-boot.lds
@@ -45,7 +45,7 @@
 
 	. = ALIGN (4);
 	.rodata : {
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN (4);
diff --git a/board/actux4/u-boot.lds b/board/actux4/u-boot.lds
index 0e1155a..10a5da9 100644
--- a/board/actux4/u-boot.lds
+++ b/board/actux4/u-boot.lds
@@ -36,7 +36,7 @@
 
 	. = ALIGN (4);
 	.rodata : {
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN (4);
diff --git a/board/adder/u-boot.lds b/board/adder/u-boot.lds
index d97c049..186dfe6 100644
--- a/board/adder/u-boot.lds
+++ b/board/adder/u-boot.lds
@@ -57,10 +57,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ads5121/u-boot.lds b/board/ads5121/u-boot.lds
index a059033..dae3269 100644
--- a/board/ads5121/u-boot.lds
+++ b/board/ads5121/u-boot.lds
@@ -54,10 +54,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/altera/dk1c20/u-boot.lds b/board/altera/dk1c20/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/altera/dk1c20/u-boot.lds
+++ b/board/altera/dk1c20/u-boot.lds
@@ -38,7 +38,7 @@
 	. = ALIGN(4);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	__rodata_end = .;
 
diff --git a/board/altera/dk1s10/u-boot.lds b/board/altera/dk1s10/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/altera/dk1s10/u-boot.lds
+++ b/board/altera/dk1s10/u-boot.lds
@@ -38,7 +38,7 @@
 	. = ALIGN(4);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	__rodata_end = .;
 
diff --git a/board/altera/ep1c20/u-boot.lds b/board/altera/ep1c20/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1c20/u-boot.lds
+++ b/board/altera/ep1c20/u-boot.lds
@@ -34,8 +34,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/board/altera/ep1s10/u-boot.lds b/board/altera/ep1s10/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1s10/u-boot.lds
+++ b/board/altera/ep1s10/u-boot.lds
@@ -34,8 +34,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/board/altera/ep1s40/u-boot.lds b/board/altera/ep1s40/u-boot.lds
index 73dfe9d..e2eb3aa 100644
--- a/board/altera/ep1s40/u-boot.lds
+++ b/board/altera/ep1s40/u-boot.lds
@@ -34,8 +34,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/board/amcc/acadia/u-boot-nand.lds b/board/amcc/acadia/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/acadia/u-boot-nand.lds
+++ b/board/amcc/acadia/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/acadia/u-boot.lds b/board/amcc/acadia/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/acadia/u-boot.lds
+++ b/board/amcc/acadia/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/bamboo/u-boot-nand.lds b/board/amcc/bamboo/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/bamboo/u-boot-nand.lds
+++ b/board/amcc/bamboo/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/bamboo/u-boot.lds b/board/amcc/bamboo/u-boot.lds
index 113418d..997d844 100644
--- a/board/amcc/bamboo/u-boot.lds
+++ b/board/amcc/bamboo/u-boot.lds
@@ -77,10 +77,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/bubinga/u-boot.lds b/board/amcc/bubinga/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/bubinga/u-boot.lds
+++ b/board/amcc/bubinga/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/canyonlands/u-boot-nand.lds b/board/amcc/canyonlands/u-boot-nand.lds
index 9f13d03..d18c536 100644
--- a/board/amcc/canyonlands/u-boot-nand.lds
+++ b/board/amcc/canyonlands/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/canyonlands/u-boot.lds b/board/amcc/canyonlands/u-boot.lds
index f0db0b2..b768532 100644
--- a/board/amcc/canyonlands/u-boot.lds
+++ b/board/amcc/canyonlands/u-boot.lds
@@ -76,9 +76,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/ebony/u-boot.lds b/board/amcc/ebony/u-boot.lds
index 17d1ba8..d569a14 100644
--- a/board/amcc/ebony/u-boot.lds
+++ b/board/amcc/ebony/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/katmai/u-boot.lds b/board/amcc/katmai/u-boot.lds
index 464bc6e..71a8b69 100644
--- a/board/amcc/katmai/u-boot.lds
+++ b/board/amcc/katmai/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/kilauea/u-boot-nand.lds b/board/amcc/kilauea/u-boot-nand.lds
index 799c28f..b769e94 100644
--- a/board/amcc/kilauea/u-boot-nand.lds
+++ b/board/amcc/kilauea/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/kilauea/u-boot.lds b/board/amcc/kilauea/u-boot.lds
index 0ac21e3..a44613d 100644
--- a/board/amcc/kilauea/u-boot.lds
+++ b/board/amcc/kilauea/u-boot.lds
@@ -71,9 +71,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/luan/u-boot.lds b/board/amcc/luan/u-boot.lds
index b66c768..7c1bc82 100644
--- a/board/amcc/luan/u-boot.lds
+++ b/board/amcc/luan/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/makalu/u-boot.lds b/board/amcc/makalu/u-boot.lds
index 0ac21e3..a44613d 100644
--- a/board/amcc/makalu/u-boot.lds
+++ b/board/amcc/makalu/u-boot.lds
@@ -71,9 +71,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/ocotea/u-boot.lds b/board/amcc/ocotea/u-boot.lds
index 8f61873..95cac85 100644
--- a/board/amcc/ocotea/u-boot.lds
+++ b/board/amcc/ocotea/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/redwood/u-boot.lds b/board/amcc/redwood/u-boot.lds
index 8362c9b..32eff52 100644
--- a/board/amcc/redwood/u-boot.lds
+++ b/board/amcc/redwood/u-boot.lds
@@ -80,10 +80,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/sequoia/sdram.c b/board/amcc/sequoia/sdram.c
index 64eb063..c26e6ee 100644
--- a/board/amcc/sequoia/sdram.c
+++ b/board/amcc/sequoia/sdram.c
@@ -72,7 +72,7 @@
 	mtsdram(DDR0_07, 0x000D0100);
 	mtsdram(DDR0_08, 0x02430001);
 	mtsdram(DDR0_09, 0x00011D5F);
-	mtsdram(DDR0_10, 0x00000300);
+	mtsdram(DDR0_10, 0x00000100);
 	mtsdram(DDR0_11, 0x0027C800);
 	mtsdram(DDR0_12, 0x00000003);
 	mtsdram(DDR0_14, 0x00000000);
diff --git a/board/amcc/sequoia/u-boot-nand.lds b/board/amcc/sequoia/u-boot-nand.lds
index 6e1e169..b580e0b 100644
--- a/board/amcc/sequoia/u-boot-nand.lds
+++ b/board/amcc/sequoia/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/sequoia/u-boot.lds b/board/amcc/sequoia/u-boot.lds
index 05152b7..7798722 100644
--- a/board/amcc/sequoia/u-boot.lds
+++ b/board/amcc/sequoia/u-boot.lds
@@ -75,9 +75,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/taihu/u-boot.lds b/board/amcc/taihu/u-boot.lds
index fd5f3df..b7aa160 100644
--- a/board/amcc/taihu/u-boot.lds
+++ b/board/amcc/taihu/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/taishan/u-boot.lds b/board/amcc/taishan/u-boot.lds
index e620808..75b7fc9 100644
--- a/board/amcc/taishan/u-boot.lds
+++ b/board/amcc/taishan/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/walnut/u-boot.lds b/board/amcc/walnut/u-boot.lds
index c9472f9..f6cbe13 100644
--- a/board/amcc/walnut/u-boot.lds
+++ b/board/amcc/walnut/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/yosemite/u-boot.lds b/board/amcc/yosemite/u-boot.lds
index ccb510e..e31f071 100644
--- a/board/amcc/yosemite/u-boot.lds
+++ b/board/amcc/yosemite/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amcc/yucca/u-boot.lds b/board/amcc/yucca/u-boot.lds
index adfa28b..60135b9 100644
--- a/board/amcc/yucca/u-boot.lds
+++ b/board/amcc/yucca/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/amirix/ap1000/u-boot.lds b/board/amirix/ap1000/u-boot.lds
index 27a6f8b..a4c48d6 100644
--- a/board/amirix/ap1000/u-boot.lds
+++ b/board/amirix/ap1000/u-boot.lds
@@ -79,10 +79,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/apollon/u-boot.lds b/board/apollon/u-boot.lds
index 0aeb437..7fb7e04 100644
--- a/board/apollon/u-boot.lds
+++ b/board/apollon/u-boot.lds
@@ -43,7 +43,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/armadillo/u-boot.lds b/board/armadillo/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/armadillo/u-boot.lds
+++ b/board/armadillo/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/armltd/versatile/u-boot.lds b/board/armltd/versatile/u-boot.lds
index 6e6e29b..48c2613 100644
--- a/board/armltd/versatile/u-boot.lds
+++ b/board/armltd/versatile/u-boot.lds
@@ -33,7 +33,7 @@
 	  cpu/arm926ejs/start.o	(.text)
 	  *(.text)
 	}
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/assabet/u-boot.lds b/board/assabet/u-boot.lds
index 5507dd3..bd97436 100644
--- a/board/assabet/u-boot.lds
+++ b/board/assabet/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/atmel/at91rm9200dk/u-boot.lds b/board/atmel/at91rm9200dk/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/atmel/at91rm9200dk/u-boot.lds
+++ b/board/atmel/at91rm9200dk/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/atmel/atngw100/u-boot.lds b/board/atmel/atngw100/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/atmel/atngw100/u-boot.lds
+++ b/board/atmel/atngw100/u-boot.lds
@@ -36,8 +36,7 @@
 	_etext = .;
 
 	.rodata : {
-		*(.rodata)
-		*(.rodata.*)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/board/atmel/atstk1000/u-boot.lds b/board/atmel/atstk1000/u-boot.lds
index 0d3b19c..86ef939 100644
--- a/board/atmel/atstk1000/u-boot.lds
+++ b/board/atmel/atstk1000/u-boot.lds
@@ -36,8 +36,7 @@
 	_etext = .;
 
 	.rodata : {
-		*(.rodata)
-		*(.rodata.*)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/board/atum8548/u-boot.lds b/board/atum8548/u-boot.lds
index 650cb9e..3067846 100644
--- a/board/atum8548/u-boot.lds
+++ b/board/atum8548/u-boot.lds
@@ -78,10 +78,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/c2mon/u-boot.lds b/board/c2mon/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/c2mon/u-boot.lds
+++ b/board/c2mon/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/cerf250/u-boot.lds b/board/cerf250/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/cerf250/u-boot.lds
+++ b/board/cerf250/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/cm4008/u-boot.lds b/board/cm4008/u-boot.lds
index e1febe1..e96c45f 100644
--- a/board/cm4008/u-boot.lds
+++ b/board/cm4008/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/cm41xx/u-boot.lds b/board/cm41xx/u-boot.lds
index e1febe1..e96c45f 100644
--- a/board/cm41xx/u-boot.lds
+++ b/board/cm41xx/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/cm5200/u-boot.lds b/board/cm5200/u-boot.lds
index 7bd6d4d..3a72bd3 100644
--- a/board/cm5200/u-boot.lds
+++ b/board/cm5200/u-boot.lds
@@ -55,10 +55,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/cmc_pu2/load_sernum_ethaddr.c b/board/cmc_pu2/load_sernum_ethaddr.c
index 354566c..5ef9f20 100644
--- a/board/cmc_pu2/load_sernum_ethaddr.c
+++ b/board/cmc_pu2/load_sernum_ethaddr.c
@@ -66,14 +66,13 @@
  * Internal structure: see struct definition
  */
 
-void load_sernum_ethaddr (void)
+void misc_init_r(void)
 {
 	struct manufacturer_data data;
-	char  ethaddr[18];
 	char  serial [9];
 	unsigned short chksum;
 	unsigned char *p;
-	unsigned short i, is, id;
+	unsigned short i;
 
 #if !defined(CONFIG_HARD_I2C) && !defined(CONFIG_SOFT_I2C)
 #error you must define some I2C support (CONFIG_HARD_I2C or CONFIG_SOFT_I2C)
@@ -97,17 +96,6 @@
 		return;
 	}
 
-	/* copy MAC address */
-	is = 0;
-	id = 0;
-	for (i = 0; i < 6; i++) {
-		sprintf (&ethaddr[id], "%02x", data.macadr[is++]);
-		id += 2;
-		if (is < 6)
-			ethaddr[id++] = ':';
-	}
-	ethaddr[id] = '\0';	/* just to be sure */
-
 	/* copy serial number */
 	sprintf (serial, "%d", data.serial_number);
 
@@ -117,6 +105,6 @@
 	}
 
 	if (getenv("ethaddr") == NULL) {
-		setenv ("ethaddr", ethaddr);
+		eth_setenv_enetaddr("ethaddr", data.macadr);
 	}
 }
diff --git a/board/cmc_pu2/u-boot.lds b/board/cmc_pu2/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/cmc_pu2/u-boot.lds
+++ b/board/cmc_pu2/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/cobra5272/u-boot.lds b/board/cobra5272/u-boot.lds
index bed1177..7e716bb 100644
--- a/board/cobra5272/u-boot.lds
+++ b/board/cobra5272/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/cogent/u-boot.lds b/board/cogent/u-boot.lds
index 5fd9f79..3ea6f1c 100644
--- a/board/cogent/u-boot.lds
+++ b/board/cogent/u-boot.lds
@@ -61,10 +61,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/cradle/u-boot.lds b/board/cradle/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/cradle/u-boot.lds
+++ b/board/cradle/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/cray/L1/u-boot.lds b/board/cray/L1/u-boot.lds
index d278866..86c8ecb 100644
--- a/board/cray/L1/u-boot.lds
+++ b/board/cray/L1/u-boot.lds
@@ -85,10 +85,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/csb226/u-boot.lds b/board/csb226/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/csb226/u-boot.lds
+++ b/board/csb226/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/csb272/u-boot.lds b/board/csb272/u-boot.lds
index af87188..0aa6f8f 100644
--- a/board/csb272/u-boot.lds
+++ b/board/csb272/u-boot.lds
@@ -86,10 +86,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/csb472/u-boot.lds b/board/csb472/u-boot.lds
index 3736377..565e021 100644
--- a/board/csb472/u-boot.lds
+++ b/board/csb472/u-boot.lds
@@ -86,10 +86,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/csb637/u-boot.lds b/board/csb637/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/csb637/u-boot.lds
+++ b/board/csb637/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/dave/B2/u-boot.lds b/board/dave/B2/u-boot.lds
index a6fc6d7..1690b6e 100644
--- a/board/dave/B2/u-boot.lds
+++ b/board/dave/B2/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/dave/PPChameleonEVB/u-boot.lds b/board/dave/PPChameleonEVB/u-boot.lds
index d3e6df9..b36827d 100644
--- a/board/dave/PPChameleonEVB/u-boot.lds
+++ b/board/dave/PPChameleonEVB/u-boot.lds
@@ -80,10 +80,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/davinci/dvevm/u-boot.lds b/board/davinci/dvevm/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/dvevm/u-boot.lds
+++ b/board/davinci/dvevm/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/davinci/schmoogie/u-boot.lds b/board/davinci/schmoogie/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/schmoogie/u-boot.lds
+++ b/board/davinci/schmoogie/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/davinci/sffsdr/u-boot.lds b/board/davinci/sffsdr/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/sffsdr/u-boot.lds
+++ b/board/davinci/sffsdr/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/davinci/sonata/u-boot.lds b/board/davinci/sonata/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/davinci/sonata/u-boot.lds
+++ b/board/davinci/sonata/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/dbau1x00/u-boot.lds b/board/dbau1x00/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/dbau1x00/u-boot.lds
+++ b/board/dbau1x00/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/delta/u-boot.lds b/board/delta/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/delta/u-boot.lds
+++ b/board/delta/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/digsy_mtc/Makefile b/board/digsy_mtc/Makefile
new file mode 100644
index 0000000..7d659e5
--- /dev/null
+++ b/board/digsy_mtc/Makefile
@@ -0,0 +1,32 @@
+
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb@semihalf.com
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).a
+
+COBJS	:= $(BOARD).o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+clean:
+	rm -f $(SOBJS) $(OBJS)
+
+distclean:	clean
+	rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/digsy_mtc/config.mk b/board/digsy_mtc/config.mk
new file mode 100644
index 0000000..e2f14b0
--- /dev/null
+++ b/board/digsy_mtc/config.mk
@@ -0,0 +1,24 @@
+#
+# Author: Grzegorz Bernacki, Semihalf, gjb@semihalf.com
+#
+
+#
+# digsyMTC board:
+#
+#	Valid values for TEXT_BASE are:
+#
+#	0xFFF00000   boot high (standard configuration)
+#	0xFE000000   boot low
+#	0x00100000   boot from RAM (for testing only)
+#
+
+sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
+
+ifndef TEXT_BASE
+## Standard: boot high
+TEXT_BASE = 0xFFF00000
+## For testing: boot from RAM
+# TEXT_BASE = 0x00100000
+endif
+
+PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board
diff --git a/board/digsy_mtc/digsy_mtc.c b/board/digsy_mtc/digsy_mtc.c
new file mode 100644
index 0000000..e231c10
--- /dev/null
+++ b/board/digsy_mtc/digsy_mtc.c
@@ -0,0 +1,307 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2004
+ * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com.
+ *
+ * (C) Copyright 2005-2009
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ *                 frank.bodammer@gcd-solutions.de
+ *
+ * (C) Copyright 2009
+ * Grzegorz Bernacki, Semihalf, gjb@semihalf.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
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <net.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "eeprom.h"
+#include "is42s16800a-7t.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern int usb_cpu_init(void);
+
+#ifndef CONFIG_SYS_RAMBOOT
+static void sdram_start(int hi_addr)
+{
+	long hi_addr_bit = hi_addr ? 0x01000000 : 0;
+	long control = SDRAM_CONTROL | hi_addr_bit;
+
+	/* unlock mode register */
+	out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000000);
+
+	/* precharge all banks */
+	out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000002);
+
+	/* auto refresh */
+	out_be32((void *)MPC5XXX_SDRAM_CTRL, control | 0x80000004);
+
+	/* set mode register */
+	out_be32((void *)MPC5XXX_SDRAM_MODE, SDRAM_MODE);
+
+	/* normal operation */
+	out_be32((void *)MPC5XXX_SDRAM_CTRL, control);
+}
+#endif
+
+/*
+ * ATTENTION: Although partially referenced initdram does NOT make real use
+ *            use of CONFIG_SYS_SDRAM_BASE. The code does not work if
+ *            CONFIG_SYS_SDRAM_BASE is something else than 0x00000000.
+ */
+
+phys_size_t initdram(int board_type)
+{
+	ulong dramsize = 0;
+	ulong dramsize2 = 0;
+	uint svr, pvr;
+#ifndef CONFIG_SYS_RAMBOOT
+	ulong test1, test2;
+
+	/* setup SDRAM chip selects */
+	out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0x0000001C); /* 512MB at 0x0 */
+	out_be32((void *)MPC5XXX_SDRAM_CS1CFG, 0x80000000); /* disabled */
+
+	/* setup config registers */
+	out_be32((void *)MPC5XXX_SDRAM_CONFIG1, SDRAM_CONFIG1);
+	out_be32((void *)MPC5XXX_SDRAM_CONFIG2, SDRAM_CONFIG2);
+
+	/* find RAM size using SDRAM CS0 only */
+	sdram_start(0);
+	test1 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+	sdram_start(1);
+	test2 = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 0x08000000);
+	if (test1 > test2) {
+		sdram_start(0);
+		dramsize = test1;
+	} else {
+		dramsize = test2;
+	}
+
+	/* memory smaller than 1MB is impossible */
+	if (dramsize < (1 << 20))
+		dramsize = 0;
+
+	/* set SDRAM CS0 size according to the amount of RAM found */
+	if (dramsize > 0) {
+		out_be32((void *)MPC5XXX_SDRAM_CS0CFG,
+			(0x13 + __builtin_ffs(dramsize >> 20) - 1));
+	} else {
+		out_be32((void *)MPC5XXX_SDRAM_CS0CFG, 0); /* disabled */
+	}
+
+	/* let SDRAM CS1 start right after CS0 */
+	out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize + 0x0000001C);
+
+	/* find RAM size using SDRAM CS1 only */
+	test1 = get_ram_size((long *)(CONFIG_SYS_SDRAM_BASE + dramsize),
+			0x08000000);
+		dramsize2 = test1;
+
+	/* memory smaller than 1MB is impossible */
+	if (dramsize2 < (1 << 20))
+		dramsize2 = 0;
+
+	/* set SDRAM CS1 size according to the amount of RAM found */
+	if (dramsize2 > 0) {
+		out_be32((void *)MPC5XXX_SDRAM_CS1CFG, (dramsize |
+			(0x13 + __builtin_ffs(dramsize2 >> 20) - 1)));
+	} else {
+		out_be32((void *)MPC5XXX_SDRAM_CS1CFG, dramsize); /* disabled */
+	}
+
+#else /* CONFIG_SYS_RAMBOOT */
+
+	/* retrieve size of memory connected to SDRAM CS0 */
+	dramsize = in_be32((void *)MPC5XXX_SDRAM_CS0CFG) & 0xFF;
+	if (dramsize >= 0x13)
+		dramsize = (1 << (dramsize - 0x13)) << 20;
+	else
+		dramsize = 0;
+
+	/* retrieve size of memory connected to SDRAM CS1 */
+	dramsize2 = in_be32((void *)MPC5XXX_SDRAM_CS1CFG) & 0xFF;
+	if (dramsize2 >= 0x13)
+		dramsize2 = (1 << (dramsize2 - 0x13)) << 20;
+	else
+		dramsize2 = 0;
+
+#endif /* CONFIG_SYS_RAMBOOT */
+
+	/*
+	 * On MPC5200B we need to set the special configuration delay in the
+	 * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM
+	 * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190:
+	 *
+	 * "The SDelay should be written to a value of 0x00000004. It is
+	 * required to account for changes caused by normal wafer processing
+	 * parameters."
+	 */
+	svr = get_svr();
+	pvr = get_pvr();
+	if ((SVR_MJREV(svr) >= 2) &&
+	    (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4))
+		out_be32((void *)MPC5XXX_SDRAM_SDELAY, 0x04);
+
+	return dramsize + dramsize2;
+}
+
+int checkboard(void)
+{
+	char *s = getenv("serial#");
+
+	puts ("Board: InterControl digsyMTC");
+	if (s != NULL) {
+		puts(", ");
+		puts(s);
+	}
+	putc('\n');
+
+	return 0;
+}
+
+int board_early_init_r(void)
+{
+	/*
+	 * Now, when we are in RAM, enable flash write access for detection
+	 * process.  Note that CS_BOOT cannot be cleared when executing in
+	 * flash.
+	 */
+	/* disable CS_BOOT */
+	clrbits_be32((void *)MPC5XXX_ADDECR, (1 << 25));
+	/* enable CS1 */
+	setbits_be32((void *)MPC5XXX_ADDECR, (1 << 17));
+	/* enable CS0 */
+	setbits_be32((void *)MPC5XXX_ADDECR, (1 << 16));
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+	/* Low level USB init, required for proper kernel operation */
+	usb_cpu_init();
+#endif
+	return (0);
+}
+
+void board_get_enetaddr (uchar * enet)
+{
+	ushort read = 0;
+	ushort addr_of_eth_addr = 0;
+	ushort len_sys = 0;
+	ushort len_sys_cfg = 0;
+
+	/* check identification word */
+	eeprom_read(EEPROM_ADDR, EEPROM_ADDR_IDENT, (uchar *)&read, 2);
+	if (read != EEPROM_IDENT)
+		return;
+
+	/* calculate offset of config area */
+	eeprom_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYS, (uchar *)&len_sys, 2);
+	eeprom_read(EEPROM_ADDR, EEPROM_ADDR_LEN_SYSCFG,
+		(uchar *)&len_sys_cfg, 2);
+	addr_of_eth_addr = (len_sys + len_sys_cfg + EEPROM_ADDR_ETHADDR) << 1;
+	if (addr_of_eth_addr >= EEPROM_LEN)
+		return;
+
+	eeprom_read(EEPROM_ADDR, addr_of_eth_addr, enet, 6);
+}
+
+int misc_init_r(void)
+{
+	uchar enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(enetaddr);
+		eth_setenv_enetaddr("ethaddr", enetaddr);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PCI
+static struct pci_controller hose;
+
+extern void pci_mpc5xxx_init(struct pci_controller *);
+
+void pci_init_board(void)
+{
+	pci_mpc5xxx_init(&hose);
+}
+#endif
+
+#ifdef CONFIG_CMD_IDE
+
+#ifdef CONFIG_IDE_RESET
+
+void init_ide_reset(void)
+{
+	debug ("init_ide_reset\n");
+
+	/* set gpio output value to 1 */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+	/* open drain output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+	/* direction output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+	/* enable gpio */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+
+}
+
+void ide_set_reset(int idereset)
+{
+	debug ("ide_reset(%d)\n", idereset);
+
+	/* set gpio output value to 0 */
+	clrbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+	/* open drain output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+	/* direction output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+	/* enable gpio */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+
+	udelay(10000);
+
+	/* set gpio output value to 1 */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_DATA_O, (1 << 25));
+	/* open drain output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ODE, (1 << 25));
+	/* direction output */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_DIR, (1 << 25));
+	/* enable gpio */
+	setbits_be32((void *)MPC5XXX_WU_GPIO_ENABLE, (1 << 25));
+}
+#endif /* CONFIG_IDE_RESET */
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+void ft_board_setup(void *blob, bd_t *bd)
+{
+	ft_cpu_setup(blob, bd);
+}
+#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */
+
+#endif /* CONFIG_CMD_IDE */
+
diff --git a/board/digsy_mtc/eeprom.h b/board/digsy_mtc/eeprom.h
new file mode 100644
index 0000000..39e0378
--- /dev/null
+++ b/board/digsy_mtc/eeprom.h
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2009 Semihalf.
+ * Written by: Grzegorz Bernacki <gjb@semihalf.com>
+ *
+ * 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 anty 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 CMD_EEPROM_H
+#define CMD_EEPROM_H
+
+#define EEPROM_ADDR		CONFIG_SYS_I2C_EEPROM_ADDR
+#define EEPROM_LEN		1024	/* eeprom length */
+#define EEPROM_IDENT		2408	/* identification word */
+#define EEPROM_ADDR_IDENT	0	/* identification word offset */
+#define EEPROM_ADDR_LEN_SYS	2	/* system area lenght offset */
+#define EEPROM_ADDR_LEN_SYSCFG	4	/* system config area length offset */
+#define EEPROM_ADDR_ETHADDR	23	/* ethernet addres offset */
+
+#endif
diff --git a/board/digsy_mtc/is42s16800a-7t.h b/board/digsy_mtc/is42s16800a-7t.h
new file mode 100644
index 0000000..1873ea7
--- /dev/null
+++ b/board/digsy_mtc/is42s16800a-7t.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2004-2009
+ * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.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
+ */
+
+#define SDRAM_MODE	0x00CD0000
+#define SDRAM_CONTROL	0x505F0000
+#define SDRAM_CONFIG1	0xD2322900
+#define SDRAM_CONFIG2	0x8AD70000
+
diff --git a/board/dnp1110/u-boot.lds b/board/dnp1110/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/dnp1110/u-boot.lds
+++ b/board/dnp1110/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds
index 671305a..4ea424d 100644
--- a/board/eNET/u-boot.lds
+++ b/board/eNET/u-boot.lds
@@ -31,7 +31,7 @@
 	.text  : { *(.text); }
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) *(.rodata.str1.1) *(.rodata.str1.32) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	_i386boot_text_size = SIZEOF(.text) + SIZEOF(.rodata);
 
diff --git a/board/earthlcd/favr-32-ezkit/u-boot.lds b/board/earthlcd/favr-32-ezkit/u-boot.lds
index ad056b3..0d413a0 100644
--- a/board/earthlcd/favr-32-ezkit/u-boot.lds
+++ b/board/earthlcd/favr-32-ezkit/u-boot.lds
@@ -34,8 +34,7 @@
 	_etext = .;
 
 	.rodata : {
-		*(.rodata)
-		*(.rodata.*)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/board/eltec/bab7xx/u-boot.lds b/board/eltec/bab7xx/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/eltec/bab7xx/u-boot.lds
+++ b/board/eltec/bab7xx/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/eltec/elppc/u-boot.lds b/board/eltec/elppc/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/eltec/elppc/u-boot.lds
+++ b/board/eltec/elppc/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/eltec/mhpc/u-boot.lds b/board/eltec/mhpc/u-boot.lds
index 759b412..ee74eb9 100644
--- a/board/eltec/mhpc/u-boot.lds
+++ b/board/eltec/mhpc/u-boot.lds
@@ -63,10 +63,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/emk/top860/u-boot.lds b/board/emk/top860/u-boot.lds
index da23fff..b4e093c 100644
--- a/board/emk/top860/u-boot.lds
+++ b/board/emk/top860/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ep7312/u-boot.lds b/board/ep7312/u-boot.lds
index a79bb8c..8c9f624 100644
--- a/board/ep7312/u-boot.lds
+++ b/board/ep7312/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/ep88x/u-boot.lds b/board/ep88x/u-boot.lds
index 1b6e417..dd62e58 100644
--- a/board/ep88x/u-boot.lds
+++ b/board/ep88x/u-boot.lds
@@ -57,9 +57,7 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/eric/u-boot.lds b/board/eric/u-boot.lds
index bf46e18..e62896f 100644
--- a/board/eric/u-boot.lds
+++ b/board/eric/u-boot.lds
@@ -85,10 +85,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/adciop/u-boot.lds b/board/esd/adciop/u-boot.lds
index e918163..2645e84 100644
--- a/board/esd/adciop/u-boot.lds
+++ b/board/esd/adciop/u-boot.lds
@@ -57,11 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
 
     *(.text)
     *(.fixup)
@@ -71,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/apc405/apc405.c b/board/esd/apc405/apc405.c
index ac9bbb3..5a02155 100644
--- a/board/esd/apc405/apc405.c
+++ b/board/esd/apc405/apc405.c
@@ -93,7 +93,7 @@
 int board_revision(void)
 {
 	unsigned long cntrl0Reg;
-	volatile unsigned long value;
+	unsigned long value;
 
 	/*
 	 * Get version of APC405 board from GPIO's
diff --git a/board/esd/apc405/u-boot.lds b/board/esd/apc405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/apc405/u-boot.lds
+++ b/board/esd/apc405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/ar405/ar405.c b/board/esd/ar405/ar405.c
index c4b4b67..14520e1 100644
--- a/board/esd/ar405/ar405.c
+++ b/board/esd/ar405/ar405.c
@@ -24,6 +24,7 @@
 #include <common.h>
 #include "ar405.h"
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -137,18 +138,14 @@
 	mtdcr (uicvcr, 0x00000001);	/* set vect base=0,INT0 highest priority */
 	mtdcr (uicsr, 0xFFFFFFFF);	/* clear all ints */
 
-	*(ushort *) 0xf03000ec = 0x0fff;	/* enable all interrupts in fpga */
+	out_be16((void *)0xf03000ec, 0x0fff); /* enable interrupts in fpga */
 
 	return 0;
 }
 
-
-/* ------------------------------------------------------------------------- */
-
 /*
  * Check Board Identity:
  */
-
 int checkboard (void)
 {
 	int index;
@@ -192,14 +189,15 @@
 
 
 #if 1 /* test-only: some internal test routines... */
+#define DIGEN	((void *)0xf03000b4) /* u8 */
+#define DIGOUT	((void *)0xf03000b0) /* u16 */
+#define DIGIN	((void *)0xf03000a0) /* u16 */
+
 /*
  * Some test routines
  */
 int do_digtest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	volatile uchar *digen = (volatile uchar *)0xf03000b4;
-	volatile ushort *digout = (volatile ushort *)0xf03000b0;
-	volatile ushort *digin = (volatile ushort *)0xf03000a0;
 	int i;
 	int k;
 	int start;
@@ -216,7 +214,7 @@
 	/*
 	 * Enable digital outputs
 	 */
-	*digen = 0x08;
+	out_8(DIGEN, 0x08);
 
 	printf("\nStarting digital In-/Out Test from I/O %d to %d (Cntrl-C to abort)...\n",
 	       start, end);
@@ -226,12 +224,13 @@
 	 */
 	for (;;) {
 		for (i=start; i<=end; i++) {
-			*digout = 0x0001 << i;
+			out_be16(DIGOUT, 0x0001 << i);
 			for (k=0; k<200; k++)
 				udelay(1000);
 
-			if (*digin != (0x0001 << i)) {
-				printf("ERROR: OUT=0x%04X, IN=0x%04X\n", 0x0001 << i, *digin);
+			if (in_be16(DIGIN) != (0x0001 << i)) {
+				printf("ERROR: OUT=0x%04X, IN=0x%04X\n",
+				       0x0001 << i, in_be16(DIGIN));
 				return 0;
 			}
 
@@ -255,13 +254,13 @@
 #define ERROR_DELTA     256
 
 struct io {
-	volatile short val;
+	short val;
 	short dummy;
 };
 
 int do_anatest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	volatile short val;
+	short val;
 	int i;
 	int volt;
 	struct io *out;
@@ -274,9 +273,9 @@
 
 	volt = 0;
 	printf("Setting Channel %d to %dV...\n", i, volt);
-	out[i].val = (volt * 0x7fff) / 10;
+	out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
 	udelay(10000);
-	val = in[i*2].val;
+	val = in_be16((void *)&(in[i*2].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -284,7 +283,7 @@
 		       ((volt * 0x7fff) / 40) + ERROR_DELTA);
 		return -1;
 	}
-	val = in[i*2+1].val;
+	val = in_be16((void *)&(in[i*2+1].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -295,9 +294,9 @@
 
 	volt = 5;
 	printf("Setting Channel %d to %dV...\n", i, volt);
-	out[i].val = (volt * 0x7fff) / 10;
+	out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
 	udelay(10000);
-	val = in[i*2].val;
+	val = in_be16((void *)&(in[i*2].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -305,7 +304,7 @@
 		       ((volt * 0x7fff) / 40) + ERROR_DELTA);
 		return -1;
 	}
-	val = in[i*2+1].val;
+	val = in_be16((void *)&(in[i*2+1].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -316,9 +315,9 @@
 
 	volt = 10;
 	printf("Setting Channel %d to %dV...\n", i, volt);
-	out[i].val = (volt * 0x7fff) / 10;
+	out_be16((void *)&(out[i].val), (volt * 0x7fff) / 10);
 	udelay(10000);
-	val = in[i*2].val;
+	val = in_be16((void *)&(in[i*2].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -326,7 +325,7 @@
 		       ((volt * 0x7fff) / 40) + ERROR_DELTA);
 		return -1;
 	}
-	val = in[i*2+1].val;
+	val = in_be16((void *)&(in[i*2+1].val));
 	printf("-> InChannel %d: 0x%04x=%dV\n", i*2+1, val, (val * 4000) / 0x7fff);
 	if ((val < ((volt * 0x7fff) / 40) - ERROR_DELTA) ||
 	    (val > ((volt * 0x7fff) / 40) + ERROR_DELTA)) {
@@ -350,28 +349,27 @@
 
 void cyclicInt(void *ptr)
 {
-	*(ushort *)0xf03000e8 = 0x0800; /* ack int */
+	out_be16((void *)0xf03000e8, 0x0800); /* ack int */
 	counter++;
 }
 
 
 int do_inctest(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	volatile uchar *digout = (volatile uchar *)0xf03000b4;
-	volatile ulong *incin;
+	ulong *incin;
 	int i;
 
-	incin = (volatile ulong *)0xf0300040;
+	incin = (ulong *)0xf0300040;
 
 	/*
 	 * Clear inc counter
 	 */
-	incin[0] = 0;
-	incin[1] = 0;
-	incin[2] = 0;
-	incin[3] = 0;
+	out_be32((void *)&incin[0], 0);
+	out_be32((void *)&incin[1], 0);
+	out_be32((void *)&incin[2], 0);
+	out_be32((void *)&incin[3], 0);
 
-	incin = (volatile ulong *)0xf0300050;
+	incin = (ulong *)0xf0300050;
 
 	/*
 	 * Inc a little
@@ -379,28 +377,29 @@
 	for (i=0; i<10000; i++) {
 		switch (i & 0x03) {
 		case 0:
-			*digout = 0x02;
+			out_8(DIGEN, 0x02);
 			break;
 		case 1:
-			*digout = 0x03;
+			out_8(DIGEN, 0x03);
 			break;
 		case 2:
-			*digout = 0x01;
+			out_8(DIGEN, 0x01);
 			break;
 		case 3:
-			*digout = 0x00;
+			out_8(DIGEN, 0x00);
 			break;
 		}
 		udelay(10);
 	}
 
-	printf("Inc 0 = %ld\n", incin[0]);
-	printf("Inc 1 = %ld\n", incin[1]);
-	printf("Inc 2 = %ld\n", incin[2]);
-	printf("Inc 3 = %ld\n", incin[3]);
+	printf("Inc 0 = %d\n", in_be32((void *)&incin[0]));
+	printf("Inc 1 = %d\n", in_be32((void *)&incin[1]));
+	printf("Inc 2 = %d\n", in_be32((void *)&incin[2]));
+	printf("Inc 3 = %d\n", in_be32((void *)&incin[3]));
 
-	*(ushort *)0xf03000e0 = 0x0c80-1; /* set counter */
-	*(ushort *)0xf03000ec |= 0x0800; /* enable int */
+	out_be16((void *)0xf03000e0, 0x0c80-1); /* set counter */
+	out_be16((void *)0xf03000ec,
+		 in_be16((void *)0xf03000ec) | 0x0800); /* enable int */
 	irq_install_handler (30, (interrupt_handler_t *) cyclicInt, NULL);
 	printf("counter=%d\n", counter);
 
diff --git a/board/esd/ar405/u-boot.lds b/board/esd/ar405/u-boot.lds
index 2c1cf92..0221e30 100644
--- a/board/esd/ar405/u-boot.lds
+++ b/board/esd/ar405/u-boot.lds
@@ -57,35 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o		(.text)
-    cpu/ppc4xx/traps.o		(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o		(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o		(.text)
-    drivers/net/4xx_enet.o	(.text)
-    common/dlmalloc.o		(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o		(.text)
-    lib_ppc/board.o		(.text)
-    lib_generic/zlib.o		(.text)
-
-    common/cmd_boot.o		(.text)
-    common/cmd_bootm.o		(.text)
-    common/cmd_flash.o		(.text)
-    common/cmd_mem.o		(.text)
-    common/cmd_nvedit.o		(.text)
-    common/console.o		(.text)
-    common/main.o		(.text)
-
-/*
-    . = DEFINED(env_offset) ? env_offset : .;
-    common/env_embedded.o	(.ppcenv)
-*/
-    common/env_embedded.o	(.text)
 
     *(.text)
     *(.fixup)
@@ -95,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/ash405/ash405.c b/board/esd/ash405/ash405.c
index dd1e2ec..074fe08 100644
--- a/board/esd/ash405/ash405.c
+++ b/board/esd/ash405/ash405.c
@@ -84,10 +84,6 @@
 
 int misc_init_r (void)
 {
-	volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
-	volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
-	volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
-	volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
 	unsigned char *dst;
 	ulong len = sizeof(fpgadata);
 	int status;
@@ -165,10 +161,10 @@
 	/*
 	 * Enable interrupts in exar duart mcr[3]
 	 */
-	*duart0_mcr = 0x08;
-	*duart1_mcr = 0x08;
-	*duart2_mcr = 0x08;
-	*duart3_mcr = 0x08;
+	out_8((void *)(DUART0_BA + 4), 0x08);
+	out_8((void *)(DUART1_BA + 4), 0x08);
+	out_8((void *)(DUART2_BA + 4), 0x08);
+	out_8((void *)(DUART3_BA + 4), 0x08);
 
 	return (0);
 }
diff --git a/board/esd/ash405/u-boot.lds b/board/esd/ash405/u-boot.lds
index e2e2512..005957e 100644
--- a/board/esd/ash405/u-boot.lds
+++ b/board/esd/ash405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/canbt/canbt.c b/board/esd/canbt/canbt.c
index 30fa605..2fe6b7b 100644
--- a/board/esd/canbt/canbt.c
+++ b/board/esd/canbt/canbt.c
@@ -24,6 +24,7 @@
 #include <common.h>
 #include "canbt.h"
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -117,9 +118,9 @@
 	/*
 	 * Setup port pins for normal operation
 	 */
-	out32 (GPIO0_ODR, 0x00000000);	/* no open drain pins */
-	out32 (GPIO0_TCR, 0x07038100);	/* setup for output */
-	out32 (GPIO0_OR, 0x07030100);	/* set output pins to high (default) */
+	out_be32 ((void *)GPIO0_ODR, 0x00000000);	/* no open drain pins */
+	out_be32 ((void *)GPIO0_TCR, 0x07038100);	/* setup for output */
+	out_be32 ((void *)GPIO0_OR, 0x07030100);	/* set output pins to high (default) */
 
 	/*
 	 * IRQ 0-15  405GP internally generated; active high; level sensitive
diff --git a/board/esd/canbt/u-boot.lds b/board/esd/canbt/u-boot.lds
index 74280e6..0221e30 100644
--- a/board/esd/canbt/u-boot.lds
+++ b/board/esd/canbt/u-boot.lds
@@ -57,33 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o		(.text)
-    cpu/ppc4xx/traps.o		(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o		(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o		(.text)
-    common/dlmalloc.o		(.text)
-    lib_ppc/extable.o		(.text)
-    lib_ppc/board.o		(.text)
-    lib_generic/zlib.o		(.text)
-    lib_generic/crc32.o		(.text)
-
-    common/cmd_boot.o		(.text)
-    common/cmd_bootm.o		(.text)
-    common/cmd_flash.o		(.text)
-    common/cmd_mem.o		(.text)
-    common/cmd_nvedit.o		(.text)
-    common/console.o		(.text)
-    common/main.o		(.text)
-    net/net.o			(.text)
-
-/*    . = env_offset;
-    common/env_embedded.o	(.text)
-*/
 
     *(.text)
     *(.fixup)
@@ -93,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/cms700/cms700.c b/board/esd/cms700/cms700.c
index d0ee193..9a522b2 100644
--- a/board/esd/cms700/cms700.c
+++ b/board/esd/cms700/cms700.c
@@ -95,14 +95,12 @@
 /*
  * Check Board Identity:
  */
-
+#define LED_REG (CONFIG_SYS_PLD_BASE + 0x1000)
 int checkboard (void)
 {
 	char str[64];
 	int flashcnt;
 	int delay;
-	volatile unsigned char *led_reg = (unsigned char *)((ulong)CONFIG_SYS_PLD_BASE + 0x1000);
-	volatile unsigned char *ver_reg = (unsigned char *)((ulong)CONFIG_SYS_PLD_BASE + 0x1001);
 
 	puts ("Board: ");
 
@@ -112,20 +110,21 @@
 		puts(str);
 	}
 
-	printf(" (PLD-Version=%02d)\n", *ver_reg);
+	printf(" (PLD-Version=%02d)\n",
+	       in_8((void *)(CONFIG_SYS_PLD_BASE + 0x1001)));
 
 	/*
 	 * Flash LEDs
 	 */
 	for (flashcnt = 0; flashcnt < 3; flashcnt++) {
-		*led_reg = 0x00;        /* LEDs off */
+		out_8((void *)LED_REG, 0x00); /* LEDs off */
 		for (delay = 0; delay < 100; delay++)
 			udelay(1000);
-		*led_reg = 0x0f;        /* LEDs on */
+		out_8((void *)LED_REG, 0x0f); /* LEDs on */
 		for (delay = 0; delay < 50; delay++)
 			udelay(1000);
 	}
-	*led_reg = 0x70;
+	out_8((void *)LED_REG, 0x70);
 
 	return 0;
 }
diff --git a/board/esd/cms700/u-boot.lds b/board/esd/cms700/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cms700/u-boot.lds
+++ b/board/esd/cms700/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/common/fpga.c b/board/esd/common/fpga.c
index 5232ddd..62c3243 100644
--- a/board/esd/common/fpga.c
+++ b/board/esd/common/fpga.c
@@ -24,6 +24,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 
 /* ------------------------------------------------------------------------- */
@@ -55,7 +56,7 @@
 #define ERROR_FPGA_PRG_DONE      -3	/* Timeout after programming     */
 
 #ifndef SET_FPGA
-# define SET_FPGA(data)         out32(GPIO0_OR, data)
+# define SET_FPGA(data)         out_be32((void *)GPIO0_OR, data)
 #endif
 
 #ifdef FPGA_PROG_ACTIVE_HIGH
@@ -85,10 +86,10 @@
 	SET_FPGA(FPGA_PRG_HIGH | FPGA_CLK_HIGH | FPGA_DATA_HIGH);}	/* set data to 1  */
 
 #ifndef FPGA_DONE_STATE
-# define FPGA_DONE_STATE (in32(GPIO0_IR) & FPGA_DONE)
+# define FPGA_DONE_STATE (in_be32((void *)GPIO0_IR) & FPGA_DONE)
 #endif
 #ifndef FPGA_INIT_STATE
-# define FPGA_INIT_STATE (in32(GPIO0_IR) & FPGA_INIT)
+# define FPGA_INIT_STATE (in_be32((void *)GPIO0_IR) & FPGA_INIT)
 #endif
 
 
@@ -139,8 +140,11 @@
 	 * Setup port pins for fpga programming
 	 */
 #ifndef CONFIG_M5249
-	out32 (GPIO0_ODR, 0x00000000);	/* no open drain pins */
-	out32 (GPIO0_TCR, in32 (GPIO0_TCR) | FPGA_PRG | FPGA_CLK | FPGA_DATA);	/* setup for output */
+	out_be32 ((void *)GPIO0_ODR, 0x00000000); /* no open drain pins */
+	/* setup for output */
+	out_be32 ((void *)GPIO0_TCR,
+		  in_be32 ((void *)GPIO0_TCR) |
+		  FPGA_PRG | FPGA_CLK | FPGA_DATA);
 #endif
 	SET_FPGA (FPGA_PRG_HIGH | FPGA_CLK_HIGH | FPGA_DATA_HIGH);	/* set pins to high */
 
diff --git a/board/esd/common/lcd.h b/board/esd/common/lcd.h
index 3169e6b..01f6019 100644
--- a/board/esd/common/lcd.h
+++ b/board/esd/common/lcd.h
@@ -40,13 +40,13 @@
 #define TRUE (!FALSE)
 #endif
 
-#define S1D_WRITE_PALETTE(p,i,r,g,b)  \
-  {  \
-  ((volatile uchar*)(p))[palette_index] = (uchar)(i); \
-  ((volatile uchar*)(p))[palette_value] = (uchar)(r); \
-  ((volatile uchar*)(p))[palette_value] = (uchar)(g); \
-  ((volatile uchar*)(p))[palette_value] = (uchar)(b); \
-  }
+#define S1D_WRITE_PALETTE(p,i,r,g,b)					\
+	{								\
+		out_8(&((uchar*)(p))[palette_index], (uchar)(i));	\
+		out_8(&((uchar*)(p))[palette_index], (uchar)(r));	\
+		out_8(&((uchar*)(p))[palette_index], (uchar)(g));	\
+		out_8(&((uchar*)(p))[palette_index], (uchar)(b));	\
+	}
 
 typedef struct
 {
diff --git a/board/esd/common/xilinx_jtag/ports.c b/board/esd/common/xilinx_jtag/ports.c
index 3ad94a5..ac0d7ac 100644
--- a/board/esd/common/xilinx_jtag/ports.c
+++ b/board/esd/common/xilinx_jtag/ports.c
@@ -32,6 +32,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 
 #include "ports.h"
 
@@ -68,7 +69,7 @@
 		} else {
 			output &= ~JTAG_TCK;
 		}
-		out32(GPIO0_OR, output);
+		out_be32((void *)GPIO0_OR, output);
 	}
 }
 
@@ -98,7 +99,7 @@
 {
 	unsigned long inputs;
 
-	inputs = in32(GPIO0_IR);
+	inputs = in_be32((void *)GPIO0_IR);
 	if (inputs & JTAG_TDO)
 		return 1;
 	else
diff --git a/board/esd/cpci2dp/cpci2dp.c b/board/esd/cpci2dp/cpci2dp.c
index 517b174..aba240f 100644
--- a/board/esd/cpci2dp/cpci2dp.c
+++ b/board/esd/cpci2dp/cpci2dp.c
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 #include <malloc.h>
 
@@ -36,12 +37,14 @@
 	 * Setup GPIO pins
 	 */
 	cntrl0Reg = mfdcr(cntrl0);
-	mtdcr(cntrl0, cntrl0Reg | ((CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED | CONFIG_SYS_SELF_RST | CONFIG_SYS_INTA_FAKE) << 5));
+	mtdcr(cntrl0, cntrl0Reg |
+	      ((CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED |
+		CONFIG_SYS_SELF_RST | CONFIG_SYS_INTA_FAKE) << 5));
 
 	/* set output pins to high */
-	out32(GPIO0_OR,  CONFIG_SYS_EEPROM_WP);
+	out_be32((void *)GPIO0_OR,  CONFIG_SYS_EEPROM_WP);
 	/* setup for output (LED=off) */
-	out32(GPIO0_TCR, CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED);
+	out_be32((void *)GPIO0_TCR, CONFIG_SYS_EEPROM_WP | CONFIG_SYS_PB_LED);
 
 	/*
 	 * IRQ 0-15  405GP internally generated; active high; level sensitive
@@ -124,17 +127,20 @@
 		switch (state) {
 		case 1:
 			/* Enable write access, clear bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
+			out_be32((void *)GPIO0_OR,
+				 in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
 			state = 0;
 			break;
 		case 0:
 			/* Disable write access, set bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+			out_be32((void *)GPIO0_OR,
+				 in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
 			state = 0;
 			break;
 		default:
 			/* Read current status back. */
-			state = (0 == (in32(GPIO0_OR) & CONFIG_SYS_EEPROM_WP));
+			state = (0 == (in_be32((void *)GPIO0_OR) &
+				       CONFIG_SYS_EEPROM_WP));
 			break;
 		}
 	}
diff --git a/board/esd/cpci2dp/u-boot.lds b/board/esd/cpci2dp/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cpci2dp/u-boot.lds
+++ b/board/esd/cpci2dp/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/cpci405/cpci405.c b/board/esd/cpci405/cpci405.c
index 0aca825..ccbe245 100644
--- a/board/esd/cpci405/cpci405.c
+++ b/board/esd/cpci405/cpci405.c
@@ -111,10 +111,10 @@
 	 * First pull fpga-prg pin low,
 	 * to disable fpga logic (on version 2 board)
 	 */
-	out32(GPIO0_ODR, 0x00000000);	     /* no open drain pins	*/
-	out32(GPIO0_TCR, CONFIG_SYS_FPGA_PRG); /* setup for output	*/
-	out32(GPIO0_OR, CONFIG_SYS_FPGA_PRG); /* set output pins to high */
-	out32(GPIO0_OR, 0);		     /* pull prg low		*/
+	out_be32((void *)GPIO0_ODR, 0x00000000);	     /* no open drain pins	*/
+	out_be32((void *)GPIO0_TCR, CONFIG_SYS_FPGA_PRG); /* setup for output	*/
+	out_be32((void *)GPIO0_OR, CONFIG_SYS_FPGA_PRG); /* set output pins to high */
+	out_be32((void *)GPIO0_OR, 0);		     /* pull prg low		*/
 
 	/*
 	 * Boot onboard FPGA
diff --git a/board/esd/cpci405/u-boot.lds b/board/esd/cpci405/u-boot.lds
index 5d59761..8c01016 100644
--- a/board/esd/cpci405/u-boot.lds
+++ b/board/esd/cpci405/u-boot.lds
@@ -67,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/cpci750/u-boot.lds b/board/esd/cpci750/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/esd/cpci750/u-boot.lds
+++ b/board/esd/cpci750/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/cpciiser4/cpciiser4.c b/board/esd/cpciiser4/cpciiser4.c
index b5d2543..6e97392 100644
--- a/board/esd/cpciiser4/cpciiser4.c
+++ b/board/esd/cpciiser4/cpciiser4.c
@@ -58,7 +58,6 @@
 int board_early_init_f (void)
 {
 	int index, len, i;
-	volatile unsigned char dummy;
 	int status;
 
 #ifdef FPGA_DEBUG
@@ -116,7 +115,7 @@
 	/*
 	 * Init FPGA via RESET (read access on CS3)
 	 */
-	dummy = *(unsigned char *) 0xf0200000;
+	in_8((void *)0xf0200000);
 
 	/*
 	 * IRQ 0-15  405GP internally generated; active high; level sensitive
diff --git a/board/esd/cpciiser4/u-boot.lds b/board/esd/cpciiser4/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/cpciiser4/u-boot.lds
+++ b/board/esd/cpciiser4/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/dasa_sim/cmd_dasa_sim.c b/board/esd/dasa_sim/cmd_dasa_sim.c
index f405be9..0310c47 100644
--- a/board/esd/dasa_sim/cmd_dasa_sim.c
+++ b/board/esd/dasa_sim/cmd_dasa_sim.c
@@ -25,6 +25,7 @@
 #include <common.h>
 #include <command.h>
 #include <pci.h>
+#include <asm/io.h>
 
 #define OK 0
 #define ERROR (-1)
@@ -136,8 +137,8 @@
 	/*
 	 * Set EEPROM write-protect register to 0
 	 */
-	out32 (pci9054_iobase + 0x0c,
-		   in32 (pci9054_iobase + 0x0c) & 0xffff00ff);
+	out_be32 ((void *)(pci9054_iobase + 0x0c),
+		  in_be32 ((void *)(pci9054_iobase + 0x0c)) & 0xffff00ff);
 
 	/* Long Serial EEPROM Load Registers... */
 	val = PciEepromWriteLongVPD (0x00, 0x905410b5);
@@ -190,8 +191,8 @@
 	/*
 	 * Set EEPROM write-protect register to 0
 	 */
-	out32 (pci9054_iobase + 0x0c,
-		in32 (pci9054_iobase + 0x0c) & 0xffff00ff);
+	out_be32 ((void *)(pci9054_iobase + 0x0c),
+		  in_be32 ((void *)(pci9054_iobase + 0x0c)) & 0xffff00ff);
 
 	/* Long Serial EEPROM Load Registers... */
 	val = PciEepromWriteLongVPD (0x00, 0xffffffff);
diff --git a/board/esd/dasa_sim/config.mk b/board/esd/dasa_sim/config.mk
index 747f29f..5d612d2 100644
--- a/board/esd/dasa_sim/config.mk
+++ b/board/esd/dasa_sim/config.mk
@@ -20,14 +20,5 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 # MA 02111-1307 USA
 #
+TEXT_BASE = 0xFFFC0000
 
-#
-# esd ADCIOP boards
-#
-
-# FLASH:
-#TEXT_BASE = 0xFFFE0000
-TEXT_BASE = 0xFFFD0000
-
-# SDRAM:
-#TEXT_BASE = 0x00FE0000
diff --git a/board/esd/dasa_sim/dasa_sim.c b/board/esd/dasa_sim/dasa_sim.c
index 47d6bb3..127374b 100644
--- a/board/esd/dasa_sim/dasa_sim.c
+++ b/board/esd/dasa_sim/dasa_sim.c
@@ -74,7 +74,8 @@
 
 #ifdef FPGA_DEBUG
 	printf ("%s\n",
-			((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+		((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+		"NOT DONE" : "DONE");
 #endif
 
 	/* init fpga by asserting and deasserting PROGRAM* (USER2)... */
@@ -86,7 +87,8 @@
 
 #ifdef FPGA_DEBUG
 	printf ("%s\n",
-			((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+		((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+		"NOT DONE" : "DONE");
 #endif
 
 	/* cs1: disable burst, disable ready */
@@ -109,7 +111,8 @@
 
 #ifdef FPGA_DEBUG
 	printf ("%s\n",
-			((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+		((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+		"NOT DONE" : "DONE");
 #endif
 
 	/* set cs1 to 32 bit data-width, disable burst, enable ready */
@@ -125,7 +128,8 @@
 
 #ifdef FPGA_DEBUG
 	printf ("%s\n",
-			((in32 (0x50000084) & 0x00010000) == 0) ? "NOT DONE" : "DONE");
+		((in_be32 ((void *)0x50000084) & 0x00010000) == 0) ?
+		"NOT DONE" : "DONE");
 #endif
 
 	/* wait for 30 ms... */
diff --git a/board/esd/dasa_sim/eeprom.c b/board/esd/dasa_sim/eeprom.c
index 1b4c7b3..aa6f52c 100644
--- a/board/esd/dasa_sim/eeprom.c
+++ b/board/esd/dasa_sim/eeprom.c
@@ -24,7 +24,7 @@
 
 #include <common.h>
 #include <command.h>
-
+#include <asm/io.h>
 
 #define EEPROM_CAP              0x50000358
 #define EEPROM_DATA             0x5000035c
@@ -33,23 +33,23 @@
 unsigned int eepromReadLong(int offs)
 {
   unsigned int value;
-  volatile unsigned short ret;
+  unsigned short ret;
   int count;
 
-  *(unsigned short *)EEPROM_CAP = offs;
+  out_be16((void *)EEPROM_CAP, offs);
 
   count = 0;
 
   for (;;)
     {
       count++;
-      ret = *(unsigned short *)EEPROM_CAP;
+      ret = in_be16((void *)EEPROM_CAP);
 
       if ((ret & 0x8000) != 0)
 	break;
     }
 
-  value = *(unsigned long *)EEPROM_DATA;
+  value = in_be32((void *)EEPROM_DATA);
 
   return value;
 }
@@ -69,18 +69,18 @@
 
 void eepromWriteLong(int offs, unsigned int value)
 {
-  volatile unsigned short ret;
+  unsigned short ret;
   int count;
 
   count = 0;
 
-  *(unsigned long *)EEPROM_DATA = value;
-  *(unsigned short *)EEPROM_CAP = 0x8000 + offs;
+  out_be32((void *)EEPROM_DATA, value);
+  out_be16((void *)EEPROM_CAP, 0x8000 + offs);
 
   for (;;)
     {
       count++;
-      ret = *(unsigned short *)EEPROM_CAP;
+      ret = in_be16((void *)EEPROM_CAP);
 
       if ((ret & 0x8000) == 0)
 	break;
diff --git a/board/esd/dasa_sim/u-boot.lds b/board/esd/dasa_sim/u-boot.lds
index 6acf7b8..77674b5 100644
--- a/board/esd/dasa_sim/u-boot.lds
+++ b/board/esd/dasa_sim/u-boot.lds
@@ -57,33 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o		(.text)
-    cpu/ppc4xx/traps.o		(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/iop480_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o		(.text)
-    common/dlmalloc.o		(.text)
-    lib_ppc/extable.o		(.text)
-    lib_ppc/board.o		(.text)
-    lib_generic/zlib.o		(.text)
-    lib_generic/crc32.o		(.text)
-
-    common/cmd_boot.o		(.text)
-    common/cmd_bootm.o		(.text)
-    common/cmd_flash.o		(.text)
-    common/cmd_mem.o		(.text)
-    common/cmd_nvedit.o		(.text)
-    common/console.o		(.text)
-    common/main.o		(.text)
-
-    board/esd/dasa_sim/flash.o	(.text)
-    common/cmd_nvedit.o	(.text)
-    board/esd/dasa_sim/cmd_dasa_sim.o	(.text)
-    net/bootp.o	(.text)
 
     . = env_offset;
     common/env_embedded.o(.text)
@@ -96,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/dp405/dp405.c b/board/esd/dp405/dp405.c
index eb001da..c32c7c7 100644
--- a/board/esd/dp405/dp405.c
+++ b/board/esd/dp405/dp405.c
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 #include <malloc.h>
 
@@ -66,9 +67,11 @@
 	/*
 	 * Reset CPLD via GPIO13 (CS4) pin
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~(0x80000000 >> 13));
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~(0x80000000 >> 13));
 	udelay(1000); /* wait 1ms */
-	out32(GPIO0_OR, in32(GPIO0_OR) | (0x80000000 >> 13));
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | (0x80000000 >> 13));
 	udelay(1000); /* wait 1ms */
 
 	return 0;
@@ -104,9 +107,10 @@
 		puts(str);
 	}
 
-	id1 = trans[(~(in32(GPIO0_IR) >> 5)) & 0x0000000f];
-	id2 = trans[(~(in32(GPIO0_IR) >> 9)) & 0x0000000f];
-	printf(" (ID=0x%1X%1X, PLD=0x%02X)\n", id2, id1, in8(0xf0001000));
+	id1 = trans[(~(in_be32((void *)GPIO0_IR) >> 5)) & 0x0000000f];
+	id2 = trans[(~(in_be32((void *)GPIO0_IR) >> 9)) & 0x0000000f];
+	printf(" (ID=0x%1X%1X, PLD=0x%02X)\n",
+	       id2, id1, in_8((void *)0xf0001000));
 
 	return 0;
 }
diff --git a/board/esd/dp405/u-boot.lds b/board/esd/dp405/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/esd/dp405/u-boot.lds
+++ b/board/esd/dp405/u-boot.lds
@@ -57,23 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    drivers/net/4xx_enet.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -83,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/du405/du405.c b/board/esd/du405/du405.c
index 8a87d55..8e9ac28 100644
--- a/board/esd/du405/du405.c
+++ b/board/esd/du405/du405.c
@@ -188,13 +188,19 @@
 	/*
 	 * Reset external DUART via FPGA
 	 */
-	*(volatile unsigned char *) FPGA_MODE_REG = 0xff;	/* reset high active */
-	*(volatile unsigned char *) FPGA_MODE_REG = 0x00;	/* low again */
+	out_8((void *)FPGA_MODE_REG, 0xff); /* reset high active */
+	out_8((void *)FPGA_MODE_REG, 0x00); /* low again */
+
+	return 0;
+}
+
+void reset_phy(void)
+{
+#if defined(CONFIG_LXT971_NO_SLEEP)
 
 	/*
 	 * Disable sleep mode in LXT971
 	 */
 	lxt971_no_sleep();
-
-	return 0;
+#endif
 }
diff --git a/board/esd/du405/u-boot.lds b/board/esd/du405/u-boot.lds
index 858ae61..166d0d1 100644
--- a/board/esd/du405/u-boot.lds
+++ b/board/esd/du405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/du440/du440.c b/board/esd/du440/du440.c
index f9b91b5..45dfa6f 100644
--- a/board/esd/du440/du440.c
+++ b/board/esd/du440/du440.c
@@ -310,8 +310,8 @@
 
 int pld_revision(void)
 {
-	out8(CONFIG_SYS_CPLD_BASE, 0x00);
-	return (int)(in8(CONFIG_SYS_CPLD_BASE) & CPLD_VERSION_MASK);
+	out_8((void *)CONFIG_SYS_CPLD_BASE, 0x00);
+	return (int)(in_8((void *)CONFIG_SYS_CPLD_BASE) & CPLD_VERSION_MASK);
 }
 
 int board_revision(void)
@@ -872,12 +872,12 @@
 static int pld_interrupt(u32 arg)
 {
 	int rc = -1; /* not for us */
-	u8 status = in8(CONFIG_SYS_CPLD_BASE);
+	u8 status = in_8((void *)CONFIG_SYS_CPLD_BASE);
 
 	/* check for PLD interrupt */
 	if (status & PWR_INT_FLAG) {
 		/* reset this int */
-		out8(CONFIG_SYS_CPLD_BASE, 0);
+		out_8((void *)CONFIG_SYS_CPLD_BASE, 0);
 		rc = 0;
 		got_pldirq = 1; /* trigger backend */
 	}
@@ -890,7 +890,7 @@
 	got_pldirq = 0;
 
 	/* clear any pending interrupt */
-	out8(CONFIG_SYS_CPLD_BASE, 0);
+	out_8((void *)CONFIG_SYS_CPLD_BASE, 0);
 
 	irq_install_handler(CPLD_IRQ,
 			    (interrupt_handler_t *)pld_interrupt, 0);
@@ -906,7 +906,8 @@
 	if (got_pldirq) {
 		printf("Got interrupt!\n");
 		printf("Power %sready!\n",
-		       in8(CONFIG_SYS_CPLD_BASE) & PWR_RDY ? "":"NOT ");
+		       in_8((void *)CONFIG_SYS_CPLD_BASE) &
+		       PWR_RDY ? "":"NOT ");
 	}
 
 	irq_free_handler(CPLD_IRQ);
diff --git a/board/esd/du440/u-boot.lds b/board/esd/du440/u-boot.lds
index 05152b7..7360349 100644
--- a/board/esd/du440/u-boot.lds
+++ b/board/esd/du440/u-boot.lds
@@ -62,9 +62,6 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
 
     *(.text)
@@ -75,9 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/hh405/hh405.c b/board/esd/hh405/hh405.c
index ae3bc80..eab952c 100644
--- a/board/esd/hh405/hh405.c
+++ b/board/esd/hh405/hh405.c
@@ -29,6 +29,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 #include <malloc.h>
 #include <pci.h>
@@ -36,6 +37,26 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* FPGA internal regs */
+#define FPGA_CTRL	((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x000))
+#define FPGA_STATUS	((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x002))
+#define FPGA_CTR	((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x004))
+#define FPGA_BL		((u16 *)(CONFIG_SYS_FPGA_BASE_ADDR + 0x006))
+
+/* FPGA Control Reg */
+#define FPGA_CTRL_REV0      0x0001
+#define FPGA_CTRL_REV1      0x0002
+#define FPGA_CTRL_VGA0_BL   0x0004
+#define FPGA_CTRL_VGA0_BL_MODE 0x0008
+#define FPGA_CTRL_CF_RESET  0x0040
+#define FPGA_CTRL_PS2_PWR   0x0080
+#define FPGA_CTRL_CF_PWRN   0x0100      /* low active */
+#define FPGA_CTRL_CF_BUS_EN 0x0200
+#define FPGA_CTRL_LCD_CLK   0x7000      /* mask for lcd clock */
+#define FPGA_CTRL_OW_ENABLE 0x8000
+
+#define FPGA_STATUS_CF_DETECT 0x8000
+
 #ifdef CONFIG_VIDEO_SM501
 
 #define SWAP32(x)	 ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8)|\
@@ -297,22 +318,22 @@
 	/*
 	 * Setup GPIO pins (BLAST/GPIO0 and GPIO9 as GPIO)
 	 */
-	osrh_reg = in32(GPIO0_OSRH);
-	isr1h_reg = in32(GPIO0_ISR1H);
-	tcr_reg = in32(GPIO0_TCR);
-	out32(GPIO0_OSRH, osrh_reg & ~0xC0003000);     /* output select */
-	out32(GPIO0_ISR1H, isr1h_reg | 0xC0003000);    /* input select  */
-	out32(GPIO0_TCR, tcr_reg & ~0x80400000);       /* select input  */
+	osrh_reg = in_be32((void *)GPIO0_OSRH);
+	isr1h_reg = in_be32((void *)GPIO0_ISR1H);
+	tcr_reg = in_be32((void *)GPIO0_TCR);
+	out_be32((void *)GPIO0_OSRH, osrh_reg & ~0xC0003000);     /* output select */
+	out_be32((void *)GPIO0_ISR1H, isr1h_reg | 0xC0003000);    /* input select  */
+	out_be32((void *)GPIO0_TCR, tcr_reg & ~0x80400000);       /* select input  */
 
 	udelay(1000);            /* wait some time before reading input */
-	value = in32(GPIO0_IR) & 0x80400000;         /* get config bits */
+	value = in_be32((void *)GPIO0_IR) & 0x80400000;         /* get config bits */
 
 	/*
 	 * Restore GPIO settings
 	 */
-	out32(GPIO0_OSRH, osrh_reg);                   /* output select */
-	out32(GPIO0_ISR1H, isr1h_reg);                 /* input select  */
-	out32(GPIO0_TCR, tcr_reg);  /* enable output driver for outputs */
+	out_be32((void *)GPIO0_OSRH, osrh_reg);                   /* output select */
+	out_be32((void *)GPIO0_ISR1H, isr1h_reg);                 /* input select  */
+	out_be32((void *)GPIO0_TCR, tcr_reg);  /* enable output driver for outputs */
 
 	if (value & 0x80000000) {
 		/* Revision 1.0 or 1.1 detected */
@@ -353,7 +374,7 @@
 	/*
 	 * EBC Configuration Register: set ready timeout to 512 ebc-clks -> ca. 15 us
 	 */
-	mtebc (epcr, 0xa8400000); /* ebc always driven */
+	mtebc(epcr, 0xa8400000); /* ebc always driven */
 
 	return 0;
 }
@@ -362,27 +383,26 @@
 {
 	int i;
 
-	volatile unsigned short *fpga_ctrl =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-	volatile unsigned short *fpga_status =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 2);
-
 	if (gd->board_type >= 2) {
-		if (*fpga_status & CONFIG_SYS_FPGA_STATUS_CF_DETECT) {
-			if (!(*fpga_ctrl & CONFIG_SYS_FPGA_CTRL_CF_BUS_EN)) {
-				*fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_CF_PWRN;
+		if (in_be16(FPGA_STATUS) & FPGA_STATUS_CF_DETECT) {
+			if (!(in_be16(FPGA_CTRL) & FPGA_CTRL_CF_BUS_EN)) {
+				out_be16(FPGA_CTRL,
+					 in_be16(FPGA_CTRL) & ~FPGA_CTRL_CF_PWRN);
 
 				for (i=0; i<300; i++)
 					udelay(1000);
 
-				*fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_CF_BUS_EN;
+				out_be16(FPGA_CTRL,
+					 in_be16(FPGA_CTRL) | FPGA_CTRL_CF_BUS_EN);
 
 				for (i=0; i<20; i++)
 					udelay(1000);
 			}
 		} else {
-			*fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_CF_BUS_EN;
-			*fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_CF_PWRN;
+			out_be16(FPGA_CTRL,
+				 in_be16(FPGA_CTRL) & ~FPGA_CTRL_CF_BUS_EN);
+			out_be16(FPGA_CTRL,
+				 in_be16(FPGA_CTRL) | FPGA_CTRL_CF_PWRN);
 		}
 	}
 
@@ -391,12 +411,6 @@
 
 int misc_init_r (void)
 {
-	volatile unsigned short *fpga_ctrl =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-	volatile unsigned short *lcd_contrast =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 4);
-	volatile unsigned short *lcd_backlight =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 6);
 	unsigned char *dst;
 	ulong len = sizeof(fpgadata);
 	int status;
@@ -460,36 +474,43 @@
 	/*
 	 * Reset FPGA via FPGA_INIT pin
 	 */
-	out32(GPIO0_TCR, in32(GPIO0_TCR) | FPGA_INIT); /* setup FPGA_INIT as output */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~FPGA_INIT);  /* reset low */
+	/* setup FPGA_INIT as output */
+	out_be32((void *)GPIO0_TCR,
+		 in_be32((void *)GPIO0_TCR) | FPGA_INIT);
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~FPGA_INIT);  /* reset low */
 	udelay(1000); /* wait 1ms */
-	out32(GPIO0_OR, in32(GPIO0_OR) | FPGA_INIT);   /* reset high */
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | FPGA_INIT);   /* reset high */
 	udelay(1000); /* wait 1ms */
 
 	/*
 	 * Write Board revision into FPGA
 	 */
-	*fpga_ctrl |= gd->board_type & 0x0003;
+	out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | (gd->board_type & 0x0003));
 
 	/*
 	 * Setup and enable EEPROM write protection
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
 
 	/*
 	 * Reset touch-screen controller
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_TOUCH_RST);
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_TOUCH_RST);
 	udelay(1000);
-	out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_TOUCH_RST);
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | CONFIG_SYS_TOUCH_RST);
 
 	/*
 	 * Enable power on PS/2 interface (with reset)
 	 */
-	*fpga_ctrl &= ~(CONFIG_SYS_FPGA_CTRL_PS2_PWR);
+	out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) & ~FPGA_CTRL_PS2_PWR);
 	for (i=0;i<500;i++)
 		udelay(1000);
-	*fpga_ctrl |= (CONFIG_SYS_FPGA_CTRL_PS2_PWR);
+	out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | FPGA_CTRL_PS2_PWR);
 
 	/*
 	 * Get contrast value from environment variable
@@ -498,7 +519,8 @@
 	if (str) {
 		contrast0 = simple_strtol(str, NULL, 16);
 		if (contrast0 > 255) {
-			printf("ERROR: contrast0 value too high (0x%lx)!\n", contrast0);
+			printf("ERROR: contrast0 value too high (0x%lx)!\n",
+			       contrast0);
 			contrast0 = 0xffffffff;
 		}
 	}
@@ -512,8 +534,9 @@
 		/*
 		 * Switch backlight on
 		 */
-		*fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL;
-		*lcd_backlight = 0x0000;
+		out_be16(FPGA_CTRL,
+			 in_be16(FPGA_CTRL) | FPGA_CTRL_VGA0_BL);
+		out_be16(FPGA_BL, 0x0000);
 
 		lcd_setup(1, 0);
 		lcd_init((uchar *)CONFIG_SYS_LCD_BIG_REG, (uchar *)CONFIG_SYS_LCD_BIG_MEM,
@@ -524,8 +547,9 @@
 		/*
 		 * Switch backlight on
 		 */
-		*fpga_ctrl &= ~CONFIG_SYS_FPGA_CTRL_VGA0_BL;
-		*lcd_backlight = 0x0000;
+		out_be16(FPGA_CTRL,
+			 in_be16(FPGA_CTRL) & ~FPGA_CTRL_VGA0_BL);
+		out_be16(FPGA_BL, 0x0000);
 
 		lcd_setup(1, 0);
 		lcd_init((uchar *)CONFIG_SYS_LCD_BIG_REG, (uchar *)CONFIG_SYS_LCD_BIG_MEM,
@@ -537,19 +561,22 @@
 		 * Set default display contrast voltage
 		 */
 		if (contrast0 == 0xffffffff) {
-			*lcd_contrast = 0x0082;
+			out_be16(FPGA_CTR, 0x0082);
 		} else {
-			*lcd_contrast = contrast0;
+			out_be16(FPGA_CTR, contrast0);
 		}
-		*lcd_backlight = 0xffff;
+		out_be16(FPGA_BL, 0xffff);
 		/*
 		 * Switch backlight on
 		 */
-		*fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL | CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE;
+		out_be16(FPGA_CTRL,
+			 in_be16(FPGA_CTRL) |
+			 FPGA_CTRL_VGA0_BL |
+			 FPGA_CTRL_VGA0_BL_MODE);
 		/*
 		 * Set lcd clock (small epson)
 		 */
-		*fpga_ctrl |= LCD_CLK_06250;
+		out_be16(FPGA_CTRL, in_be16(FPGA_CTRL) | LCD_CLK_06250);
 		udelay(100);               /* wait for 100 us */
 
 		lcd_setup(0, 1);
@@ -562,19 +589,25 @@
 		 * Set default display contrast voltage
 		 */
 		if (contrast0 == 0xffffffff) {
-			*lcd_contrast = 0x0060;
+			out_be16(FPGA_CTR, 0x0060);
 		} else {
-			*lcd_contrast = contrast0;
+			out_be16(FPGA_CTR, contrast0);
 		}
-		*lcd_backlight = 0xffff;
+		out_be16(FPGA_BL, 0xffff);
 		/*
 		 * Switch backlight on
 		 */
-		*fpga_ctrl |= CONFIG_SYS_FPGA_CTRL_VGA0_BL | CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE;
+		out_be16(FPGA_CTRL,
+			 in_be16(FPGA_CTRL) |
+			 FPGA_CTRL_VGA0_BL |
+			 FPGA_CTRL_VGA0_BL_MODE);
 		/*
 		 * Set lcd clock (small epson), enable 1-wire interface
 		 */
-		*fpga_ctrl |= LCD_CLK_08330 | CONFIG_SYS_FPGA_CTRL_OW_ENABLE;
+		out_be16(FPGA_CTRL,
+			 in_be16(FPGA_CTRL) |
+			 LCD_CLK_08330 |
+			 FPGA_CTRL_OW_ENABLE);
 
 		lcd_setup(0, 1);
 		lcd_init((uchar *)CONFIG_SYS_LCD_SMALL_REG, (uchar *)CONFIG_SYS_LCD_SMALL_MEM,
@@ -593,10 +626,10 @@
 			puts("VGA:   SM501 with 8 MB ");
 			if (strcmp(str, "ppc221") == 0) {
 				printf("(800*600, %dbpp)\n", BPP);
-				*lcd_backlight = 0x002d; /* max. allowed brightness */
+				out_be16(FPGA_BL, 0x002d); /* max. allowed brightness */
 			} else if (strcmp(str, "ppc231") == 0) {
 				printf("(1024*768, %dbpp)\n", BPP);
-				*lcd_backlight = 0x0000;
+				out_be16(FPGA_BL, 0x0000);
 			} else {
 				printf("Unsupported bd_type defined (%s) -> No display configured!\n", str);
 				return 0;
@@ -646,21 +679,21 @@
 #ifdef CONFIG_IDE_RESET
 void ide_set_reset(int on)
 {
-	volatile unsigned short *fpga_mode =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-	volatile unsigned short *fpga_status =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL + 2);
-
-	if (((gd->board_type >= 2) && (*fpga_status & CONFIG_SYS_FPGA_STATUS_CF_DETECT)) ||
+	if (((gd->board_type >= 2) &&
+	     (in_be16(FPGA_STATUS) & FPGA_STATUS_CF_DETECT)) ||
 	    (gd->board_type < 2)) {
 		/*
 		 * Assert or deassert CompactFlash Reset Pin
 		 */
 		if (on) {		/* assert RESET */
 			cf_enable();
-			*fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+			out_be16(FPGA_CTRL,
+				 in_be16(FPGA_CTRL) &
+				 ~FPGA_CTRL_CF_RESET);
 		} else {		/* release RESET */
-			*fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+			out_be16(FPGA_CTRL,
+				 in_be16(FPGA_CTRL) |
+				 FPGA_CTRL_CF_RESET);
 		}
 	}
 }
@@ -684,17 +717,20 @@
 		switch (state) {
 		case 1:
 			/* Enable write access, clear bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
+			out_be32((void *)GPIO0_OR,
+				 in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_EEPROM_WP);
 			state = 0;
 			break;
 		case 0:
 			/* Disable write access, set bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
+			out_be32((void *)GPIO0_OR,
+				 in_be32((void *)GPIO0_OR) | CONFIG_SYS_EEPROM_WP);
 			state = 0;
 			break;
 		default:
 			/* Read current status back. */
-			state = (0 == (in32(GPIO0_OR) & CONFIG_SYS_EEPROM_WP));
+			state = (0 == (in_be32((void *)GPIO0_OR) &
+				       CONFIG_SYS_EEPROM_WP));
 			break;
 		}
 	}
diff --git a/board/esd/hh405/u-boot.lds b/board/esd/hh405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/hh405/u-boot.lds
+++ b/board/esd/hh405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/hub405/hub405.c b/board/esd/hub405/hub405.c
index 8785e6c..03e5ad7 100644
--- a/board/esd/hub405/hub405.c
+++ b/board/esd/hub405/hub405.c
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 #include <malloc.h>
 
@@ -44,22 +45,22 @@
 	/*
 	 * Setup GPIO pin(s) (IRQ6/GPIO23)
 	 */
-	osrl_reg = in32(GPIO0_OSRH);
-	isr1l_reg = in32(GPIO0_ISR1H);
-	tcr_reg = in32(GPIO0_TCR);
-	out32(GPIO0_OSRH, osrl_reg & ~0x00030000);     /* output select */
-	out32(GPIO0_ISR1H, isr1l_reg | 0x00030000);    /* input select  */
-	out32(GPIO0_TCR, tcr_reg & ~0x00000100);       /* select input  */
+	osrl_reg = in_be32((void *)GPIO0_OSRH);
+	isr1l_reg = in_be32((void *)GPIO0_ISR1H);
+	tcr_reg = in_be32((void *)GPIO0_TCR);
+	out_be32((void *)GPIO0_OSRH, osrl_reg & ~0x00030000);     /* output select */
+	out_be32((void *)GPIO0_ISR1H, isr1l_reg | 0x00030000);    /* input select  */
+	out_be32((void *)GPIO0_TCR, tcr_reg & ~0x00000100);       /* select input  */
 
 	udelay(1000);            /* wait some time before reading input */
-	value = in32(GPIO0_IR) & 0x00000100;         /* get config bits */
+	value = in_be32((void *)GPIO0_IR) & 0x00000100;         /* get config bits */
 
 	/*
 	 * Restore GPIO settings
 	 */
-	out32(GPIO0_OSRH, osrl_reg);                   /* output select */
-	out32(GPIO0_ISR1H, isr1l_reg);                 /* input select  */
-	out32(GPIO0_TCR, tcr_reg);  /* enable output driver for outputs */
+	out_be32((void *)GPIO0_OSRH, osrl_reg);                   /* output select */
+	out_be32((void *)GPIO0_ISR1H, isr1l_reg);                 /* input select  */
+	out_be32((void *)GPIO0_TCR, tcr_reg);  /* enable output driver for outputs */
 
 	if (value & 0x00000100) {
 		/* Revision 1.1 or 1.2 detected */
@@ -101,13 +102,9 @@
 	return 0;
 }
 
+#define LED_REG (DUART0_BA + 0x20)
 int misc_init_r (void)
 {
-	volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
-	volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
-	volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
-	volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
-	volatile unsigned char *led_reg    = (unsigned char *)((ulong)DUART0_BA + 0x20);
 	unsigned long val;
 	int delay, flashcnt;
 	char *str;
@@ -116,16 +113,17 @@
 	/*
 	 * Enable interrupts in exar duart mcr[3]
 	 */
-	*duart0_mcr = 0x08;
-	*duart1_mcr = 0x08;
-	*duart2_mcr = 0x08;
-	*duart3_mcr = 0x08;
+	out_8((void *)(DUART0_BA + 4), 0x08);
+	out_8((void *)(DUART1_BA + 4), 0x08);
+	out_8((void *)(DUART2_BA + 4), 0x08);
+	out_8((void *)(DUART3_BA + 4), 0x08);
 
 	/*
 	 * Set RS232/RS422 control (RS232 = high on GPIO)
 	 */
-	val = in32(GPIO0_OR);
-	val &= ~(CONFIG_SYS_UART2_RS232 | CONFIG_SYS_UART3_RS232 | CONFIG_SYS_UART4_RS232 | CONFIG_SYS_UART5_RS232);
+	val = in_be32((void *)GPIO0_OR);
+	val &= ~(CONFIG_SYS_UART2_RS232 | CONFIG_SYS_UART3_RS232 |
+		 CONFIG_SYS_UART4_RS232 | CONFIG_SYS_UART5_RS232);
 
 	str = getenv("phys0");
 	if (!str || (str && (str[0] == '0')))
@@ -143,7 +141,7 @@
 	if (!str || (str && (str[0] == '0')))
 		val |= CONFIG_SYS_UART5_RS232;
 
-	out32(GPIO0_OR, val);
+	out_be32((void *)GPIO0_OR, val);
 
 	/*
 	 * check board type and setup AP power
@@ -160,23 +158,27 @@
 			 * Flash LEDs
 			 */
 			for (flashcnt = 0; flashcnt < 3; flashcnt++) {
-				*led_reg = led_reg_default;        /* LED_A..D off */
+				/* LED_A..D off */
+				out_8((void *)LED_REG, led_reg_default);
 				for (delay = 0; delay < 100; delay++)
 					udelay(1000);
-				*led_reg = led_reg_default | 0xf0; /* LED_A..D on */
+				/* LED_A..D on */
+				out_8((void *)LED_REG, led_reg_default | 0xf0);
 				for (delay = 0; delay < 50; delay++)
 					udelay(1000);
 			}
-			*led_reg = led_reg_default;
+			out_8((void *)LED_REG, led_reg_default);
 		}
 	}
 
 	/*
 	 * Reset external DUARTs
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
 	udelay(10); /* wait 10us */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
 	udelay(1000); /* wait 1ms */
 
 	/*
diff --git a/board/esd/hub405/u-boot.lds b/board/esd/hub405/u-boot.lds
index 6908106..005957e 100644
--- a/board/esd/hub405/u-boot.lds
+++ b/board/esd/hub405/u-boot.lds
@@ -57,23 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    drivers/net/4xx_enet.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -83,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/ocrtc/u-boot.lds b/board/esd/ocrtc/u-boot.lds
index 1fb754c..1b50b6d 100644
--- a/board/esd/ocrtc/u-boot.lds
+++ b/board/esd/ocrtc/u-boot.lds
@@ -82,10 +82,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/pci405/pci405.c b/board/esd/pci405/pci405.c
index 0602abf..8973f97 100644
--- a/board/esd/pci405/pci405.c
+++ b/board/esd/pci405/pci405.c
@@ -338,17 +338,17 @@
 }
 
 /* ------------------------------------------------------------------------- */
+#define UART1_MCR 0xef600404
 int wpeeprom(int wp)
 {
 	int wp_state = wp;
-	volatile unsigned char *uart1_mcr = (volatile unsigned char *)0xef600404;
 
 	if (wp == 1) {
-		*uart1_mcr &= ~0x02;
+		out_8((void *)UART1_MCR, in_8((void *)UART1_MCR) & ~0x02);
 	} else if (wp == 0) {
-		*uart1_mcr |= 0x02;
+		out_8((void *)UART1_MCR, in_8((void *)UART1_MCR) | 0x02);
 	} else {
-		if (*uart1_mcr & 0x02) {
+		if (in_8((void *)UART1_MCR) & 0x02) {
 			wp_state = 0;
 		} else {
 			wp_state = 1;
diff --git a/board/esd/pci405/u-boot.lds b/board/esd/pci405/u-boot.lds
index 9697cc6..8c01016 100644
--- a/board/esd/pci405/u-boot.lds
+++ b/board/esd/pci405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/plu405/plu405.c b/board/esd/plu405/plu405.c
index 7c0aaa2..a94604a 100644
--- a/board/esd/plu405/plu405.c
+++ b/board/esd/plu405/plu405.c
@@ -237,18 +237,18 @@
 }
 
 #ifdef CONFIG_IDE_RESET
+#define FPGA_CTRL (CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL)
 void ide_set_reset(int on)
 {
-	volatile unsigned short *fpga_mode =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-
 	/*
 	 * Assert or deassert CompactFlash Reset Pin
 	 */
 	if (on) {		/* assert RESET */
-		*fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+		out_be16((void *)FPGA_CTRL,
+			 in_be16((void *)FPGA_CTRL) & ~CONFIG_SYS_FPGA_CTRL_CF_RESET);
 	} else {		/* release RESET */
-		*fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+		out_be16((void *)FPGA_CTRL,
+			 in_be16((void *)FPGA_CTRL) | CONFIG_SYS_FPGA_CTRL_CF_RESET);
 	}
 }
 #endif /* CONFIG_IDE_RESET */
diff --git a/board/esd/plu405/u-boot.lds b/board/esd/plu405/u-boot.lds
index fd5f3df..005957e 100644
--- a/board/esd/plu405/u-boot.lds
+++ b/board/esd/plu405/u-boot.lds
@@ -57,9 +57,6 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
 
     *(.text)
@@ -70,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/pmc405/u-boot.lds b/board/esd/pmc405/u-boot.lds
index ca615f5..74f1d87 100644
--- a/board/esd/pmc405/u-boot.lds
+++ b/board/esd/pmc405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index 7808d4d..0fbc3dc 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -242,7 +242,7 @@
 				       "address %08x\n",
 				       n, data, f);
 				for (i=0; i<n; i++)
-					out32(f, data);
+					out_be32((void *)f, data);
 			}
 		} else {
 			printf("Usage:\nfifo %s\n", cmdtp->help);
diff --git a/board/esd/pmc440/pmc440.c b/board/esd/pmc440/pmc440.c
index 3824105..2ab944d 100644
--- a/board/esd/pmc440/pmc440.c
+++ b/board/esd/pmc440/pmc440.c
@@ -107,31 +107,31 @@
 	 * Setup the GPIO pins
 	 * TODO: setup GPIOs via CONFIG_SYS_4xx_GPIO_TABLE in board's config file
 	 */
-	out32(GPIO0_OR,    0x40000102);
-	out32(GPIO0_TCR,   0x4c90011f);
-	out32(GPIO0_OSRL,  0x28051400);
-	out32(GPIO0_OSRH,  0x55005000);
-	out32(GPIO0_TSRL,  0x08051400);
-	out32(GPIO0_TSRH,  0x55005000);
-	out32(GPIO0_ISR1L, 0x54000000);
-	out32(GPIO0_ISR1H, 0x00000000);
-	out32(GPIO0_ISR2L, 0x44000000);
-	out32(GPIO0_ISR2H, 0x00000100);
-	out32(GPIO0_ISR3L, 0x00000000);
-	out32(GPIO0_ISR3H, 0x00000000);
+	out_be32((void *)GPIO0_OR,    0x40000102);
+	out_be32((void *)GPIO0_TCR,   0x4c90011f);
+	out_be32((void *)GPIO0_OSRL,  0x28051400);
+	out_be32((void *)GPIO0_OSRH,  0x55005000);
+	out_be32((void *)GPIO0_TSRL,  0x08051400);
+	out_be32((void *)GPIO0_TSRH,  0x55005000);
+	out_be32((void *)GPIO0_ISR1L, 0x54000000);
+	out_be32((void *)GPIO0_ISR1H, 0x00000000);
+	out_be32((void *)GPIO0_ISR2L, 0x44000000);
+	out_be32((void *)GPIO0_ISR2H, 0x00000100);
+	out_be32((void *)GPIO0_ISR3L, 0x00000000);
+	out_be32((void *)GPIO0_ISR3H, 0x00000000);
 
-	out32(GPIO1_OR,    0x80002408);
-	out32(GPIO1_TCR,   0xd6003c08);
-	out32(GPIO1_OSRL,  0x0a5a0000);
-	out32(GPIO1_OSRH,  0x00000000);
-	out32(GPIO1_TSRL,  0x00000000);
-	out32(GPIO1_TSRH,  0x00000000);
-	out32(GPIO1_ISR1L, 0x00005555);
-	out32(GPIO1_ISR1H, 0x40000000);
-	out32(GPIO1_ISR2L, 0x04010000);
-	out32(GPIO1_ISR2H, 0x00000000);
-	out32(GPIO1_ISR3L, 0x01400000);
-	out32(GPIO1_ISR3H, 0x00000000);
+	out_be32((void *)GPIO1_OR,    0x80002408);
+	out_be32((void *)GPIO1_TCR,   0xd6003c08);
+	out_be32((void *)GPIO1_OSRL,  0x0a5a0000);
+	out_be32((void *)GPIO1_OSRH,  0x00000000);
+	out_be32((void *)GPIO1_TSRL,  0x00000000);
+	out_be32((void *)GPIO1_TSRH,  0x00000000);
+	out_be32((void *)GPIO1_ISR1L, 0x00005555);
+	out_be32((void *)GPIO1_ISR1H, 0x40000000);
+	out_be32((void *)GPIO1_ISR2L, 0x04010000);
+	out_be32((void *)GPIO1_ISR2H, 0x00000000);
+	out_be32((void *)GPIO1_ISR3L, 0x01400000);
+	out_be32((void *)GPIO1_ISR3H, 0x00000000);
 
 	/* patch PLB:PCI divider for 66MHz PCI */
 	mfcpr(clk_spcid, reg);
@@ -804,17 +804,20 @@
 		switch (state) {
 		case 1:
 			/* Enable write access, clear bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) & ~GPIO0_EP_EEP);
+			out_be32((void *)GPIO0_OR,
+			      in_be32((void *)GPIO0_OR) & ~GPIO0_EP_EEP);
 			state = 0;
 			break;
 		case 0:
 			/* Disable write access, set bit GPIO_SINT2. */
-			out32(GPIO0_OR, in32(GPIO0_OR) | GPIO0_EP_EEP);
+			out_be32((void *)GPIO0_OR,
+				 in_be32((void *)GPIO0_OR) | GPIO0_EP_EEP);
 			state = 0;
 			break;
 		default:
 			/* Read current status back. */
-			state = (0 == (in32(GPIO0_OR) & GPIO0_EP_EEP));
+			state = (0 == (in_be32((void *)GPIO0_OR)
+				       & GPIO0_EP_EEP));
 			break;
 		}
 	}
diff --git a/board/esd/pmc440/sdram.c b/board/esd/pmc440/sdram.c
index 197857a..bb46ecc 100644
--- a/board/esd/pmc440/sdram.c
+++ b/board/esd/pmc440/sdram.c
@@ -70,7 +70,7 @@
 	mtsdram(DDR0_07, 0x000D0100);
 	mtsdram(DDR0_08, 0x02430001);
 	mtsdram(DDR0_09, 0x00011D5F);
-	mtsdram(DDR0_10, 0x00000300);
+	mtsdram(DDR0_10, 0x00000100);
 	mtsdram(DDR0_11, 0x0027C800);
 	mtsdram(DDR0_12, 0x00000003);
 	mtsdram(DDR0_14, 0x00000000);
diff --git a/board/esd/pmc440/u-boot-nand.lds b/board/esd/pmc440/u-boot-nand.lds
index 6e1e169..b580e0b 100644
--- a/board/esd/pmc440/u-boot-nand.lds
+++ b/board/esd/pmc440/u-boot-nand.lds
@@ -69,9 +69,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/pmc440/u-boot.lds b/board/esd/pmc440/u-boot.lds
index 05152b7..7360349 100644
--- a/board/esd/pmc440/u-boot.lds
+++ b/board/esd/pmc440/u-boot.lds
@@ -62,9 +62,6 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
 
     *(.text)
@@ -75,9 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/tasreg/tasreg.c b/board/esd/tasreg/tasreg.c
index 80ff237..760c71d 100644
--- a/board/esd/tasreg/tasreg.c
+++ b/board/esd/tasreg/tasreg.c
@@ -25,6 +25,7 @@
 #include <command.h>
 #include <malloc.h>
 #include <asm/m5249.h>
+#include <asm/io.h>
 
 
 /* Prototypes */
@@ -118,7 +119,7 @@
 
 	/** Precharge sequence **/
 	mbar_writeLong(MCFSIM_DACR0, 0x0000332c); /* Set DACR0[IP] (bit 3) */
-	*((volatile unsigned long *) 0x00) = junk; /* write to a memory location to init. precharge */
+	out_be32((void *)0, junk); /* write to a memory location to init. precharge */
 	udelay(0x10); /* Allow several Precharge cycles */
 
 	/** Refresh Sequence **/
@@ -127,7 +128,7 @@
 
 	/** Mode Register initialization **/
 	mbar_writeLong(MCFSIM_DACR0, 0x0000b364);  /* Enable DACR0[IMRS] (bit 6); RE remains enabled */
-	*((volatile unsigned long *) 0x800) = junk; /* Access RAM to initialize the mode register */
+	out_be32((void *)0x800, junk); /* Access RAM to initialize the mode register */
 
 	return CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
 };
@@ -258,7 +259,7 @@
 {
 	uchar buf[8];
 
-	*(volatile ushort *)0xe0000000 = 0x4000;
+	out_be16((void *)0xe0000000, 0x4000);
 
 	udelay(5000); /* wait for 5ms */
 
diff --git a/board/esd/tasreg/u-boot.lds b/board/esd/tasreg/u-boot.lds
index aec7e9b..e3230b9 100644
--- a/board/esd/tasreg/u-boot.lds
+++ b/board/esd/tasreg/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/voh405/u-boot.lds b/board/esd/voh405/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/esd/voh405/u-boot.lds
+++ b/board/esd/voh405/u-boot.lds
@@ -57,23 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    drivers/net/4xx_enet.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -83,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/voh405/voh405.c b/board/esd/voh405/voh405.c
index 5480105..96a04b3 100644
--- a/board/esd/voh405/voh405.c
+++ b/board/esd/voh405/voh405.c
@@ -297,18 +297,18 @@
 }
 
 #ifdef CONFIG_IDE_RESET
+#define FPGA_MODE (CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL)
 void ide_set_reset(int on)
 {
-	volatile unsigned short *fpga_mode =
-		(unsigned short *)((ulong)CONFIG_SYS_FPGA_BASE_ADDR + CONFIG_SYS_FPGA_CTRL);
-
 	/*
 	 * Assert or deassert CompactFlash Reset Pin
 	 */
 	if (on) {		/* assert RESET */
-		*fpga_mode &= ~(CONFIG_SYS_FPGA_CTRL_CF_RESET);
+		out_be16((void *)FPGA_MODE,
+			 in_be16((void *)FPGA_MODE) & ~CONFIG_SYS_FPGA_CTRL_CF_RESET);
 	} else {		/* release RESET */
-		*fpga_mode |= CONFIG_SYS_FPGA_CTRL_CF_RESET;
+		out_be16((void *)FPGA_MODE,
+			 in_be16((void *)FPGA_MODE) | CONFIG_SYS_FPGA_CTRL_CF_RESET);
 	}
 }
 #endif /* CONFIG_IDE_RESET */
diff --git a/board/esd/vom405/u-boot.lds b/board/esd/vom405/u-boot.lds
index c9472f9..8c01016 100644
--- a/board/esd/vom405/u-boot.lds
+++ b/board/esd/vom405/u-boot.lds
@@ -57,9 +57,6 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
 
     *(.text)
@@ -70,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/vom405/vom405.c b/board/esd/vom405/vom405.c
index 1b1479f..d67b23e 100644
--- a/board/esd/vom405/vom405.c
+++ b/board/esd/vom405/vom405.c
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <asm/processor.h>
+#include <asm/io.h>
 #include <command.h>
 #include <malloc.h>
 
@@ -67,9 +68,11 @@
 	/*
 	 * Reset CPLD via GPIO12 (CS3) pin
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~(0x80000000 >> 12));
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~(0x80000000 >> 12));
 	udelay(1000); /* wait 1ms */
-	out32(GPIO0_OR, in32(GPIO0_OR) | (0x80000000 >> 12));
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | (0x80000000 >> 12));
 	udelay(1000); /* wait 1ms */
 
 	return 0;
@@ -93,7 +96,7 @@
 	int i = getenv_r ("serial#", str, sizeof(str));
 	int flashcnt;
 	int delay;
-	volatile unsigned char *led_reg = (unsigned char *)((ulong)CAN_BA + 0x1000);
+	u8 *led_reg = (u8 *)(CAN_BA + 0x1000);
 
 	puts ("Board: ");
 
@@ -103,20 +106,20 @@
 		puts(str);
 	}
 
-	printf(" (PLD-Version=%02d)\n", *led_reg);
+	printf(" (PLD-Version=%02d)\n", in_8(led_reg));
 
 	/*
 	 * Flash LEDs
 	 */
 	for (flashcnt = 0; flashcnt < 3; flashcnt++) {
-		*led_reg = 0x40;        /* LED_B..D off */
+		out_8(led_reg, 0x40);        /* LED_B..D off */
 		for (delay = 0; delay < 100; delay++)
 			udelay(1000);
-		*led_reg = 0x47;        /* LED_B..D on */
+		out_8(led_reg, 0x47);        /* LED_B..D on */
 		for (delay = 0; delay < 50; delay++)
 			udelay(1000);
 	}
-	*led_reg = 0x40;
+	out_8(led_reg, 0x40);
 
 	return 0;
 }
diff --git a/board/esd/wuh405/u-boot.lds b/board/esd/wuh405/u-boot.lds
index e2e2512..005957e 100644
--- a/board/esd/wuh405/u-boot.lds
+++ b/board/esd/wuh405/u-boot.lds
@@ -57,22 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -82,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/esd/wuh405/wuh405.c b/board/esd/wuh405/wuh405.c
index 5eca3bd..e330fff 100644
--- a/board/esd/wuh405/wuh405.c
+++ b/board/esd/wuh405/wuh405.c
@@ -82,10 +82,6 @@
 
 int misc_init_r (void)
 {
-	volatile unsigned char *duart0_mcr = (unsigned char *)((ulong)DUART0_BA + 4);
-	volatile unsigned char *duart1_mcr = (unsigned char *)((ulong)DUART1_BA + 4);
-	volatile unsigned char *duart2_mcr = (unsigned char *)((ulong)DUART2_BA + 4);
-	volatile unsigned char *duart3_mcr = (unsigned char *)((ulong)DUART3_BA + 4);
 	unsigned char *dst;
 	ulong len = sizeof(fpgadata);
 	int status;
@@ -155,18 +151,20 @@
 	/*
 	 * Reset external DUARTs
 	 */
-	out32(GPIO0_OR, in32(GPIO0_OR) | CONFIG_SYS_DUART_RST); /* set reset to high */
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) | CONFIG_SYS_DUART_RST);
 	udelay(10); /* wait 10us */
-	out32(GPIO0_OR, in32(GPIO0_OR) & ~CONFIG_SYS_DUART_RST); /* set reset to low */
+	out_be32((void *)GPIO0_OR,
+		 in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_DUART_RST);
 	udelay(1000); /* wait 1ms */
 
 	/*
 	 * Enable interrupts in exar duart mcr[3]
 	 */
-	*duart0_mcr = 0x08;
-	*duart1_mcr = 0x08;
-	*duart2_mcr = 0x08;
-	*duart3_mcr = 0x08;
+	out_8((void *)(DUART0_BA + 4), 0x08);
+	out_8((void *)(DUART1_BA + 4), 0x08);
+	out_8((void *)(DUART2_BA + 4), 0x08);
+	out_8((void *)(DUART3_BA + 4), 0x08);
 
 	return (0);
 }
diff --git a/board/esteem192e/u-boot.lds b/board/esteem192e/u-boot.lds
index c4e17d6..57aabed 100644
--- a/board/esteem192e/u-boot.lds
+++ b/board/esteem192e/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/etin/debris/debris.c b/board/etin/debris/debris.c
index 227c49a..a971af3 100644
--- a/board/etin/debris/debris.c
+++ b/board/etin/debris/debris.c
@@ -173,9 +173,13 @@
 
 int misc_init_r(void)
 {
-	/* Write ethernet addr in NVRAM for VxWorks */
-	nvram_write(CONFIG_ENV_ADDR + CONFIG_SYS_NVRAM_VXWORKS_OFFS,
-			(char*)&gd->bd->bi_enetaddr[0], 6);
+	uchar ethaddr[6];
+
+	if (eth_getenv_enetaddr("ethaddr", ethaddr))
+		/* Write ethernet addr in NVRAM for VxWorks */
+		nvram_write(CONFIG_ENV_ADDR + CONFIG_SYS_NVRAM_VXWORKS_OFFS,
+				ethaddr, 6);
+
 	return 0;
 }
 
diff --git a/board/etx094/u-boot.lds b/board/etx094/u-boot.lds
index 340825e..eb3d487 100644
--- a/board/etx094/u-boot.lds
+++ b/board/etx094/u-boot.lds
@@ -75,10 +75,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/evb4510/u-boot.lds b/board/evb4510/u-boot.lds
index a435466..b72e126 100644
--- a/board/evb4510/u-boot.lds
+++ b/board/evb4510/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/evb64260/u-boot.lds b/board/evb64260/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/evb64260/u-boot.lds
+++ b/board/evb64260/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/exbitgen/u-boot.lds b/board/exbitgen/u-boot.lds
index d76b97e..2798dc8 100644
--- a/board/exbitgen/u-boot.lds
+++ b/board/exbitgen/u-boot.lds
@@ -84,10 +84,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/fads/fads.h b/board/fads/fads.h
index 24e43ea..4ab4b26 100644
--- a/board/fads/fads.h
+++ b/board/fads/fads.h
@@ -241,7 +241,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -249,7 +249,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=fads0,nor1=fads-1,nor2=fads-2,nor3=fads-3"
 #define MTDPARTS_DEFAULT	"mtdparts=fads-0:-@1m(user1),fads-1:-(user2),fads-2:-(user3),fads-3:-(user4)"
 */
diff --git a/board/fads/u-boot.lds b/board/fads/u-boot.lds
index 194ca69..b39ef14 100644
--- a/board/fads/u-boot.lds
+++ b/board/fads/u-boot.lds
@@ -63,10 +63,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/flagadm/u-boot.lds b/board/flagadm/u-boot.lds
index f36259a..1c8180a 100644
--- a/board/flagadm/u-boot.lds
+++ b/board/flagadm/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/common/sgmii_riser.c b/board/freescale/common/sgmii_riser.c
index aeacb91..4f40a1d 100644
--- a/board/freescale/common/sgmii_riser.c
+++ b/board/freescale/common/sgmii_riser.c
@@ -47,7 +47,6 @@
 		const char *model;
 		const char *path;
 
-		printf("Updating PHY address for %s\n", dev->name);
 		if (!strstr(dev->name, "eTSEC"))
 			continue;
 
@@ -64,7 +63,6 @@
 
 		model = fdt_getprop(fdt, enet_node, "model", NULL);
 
-		printf("%s's model is %s\n", enet, model);
 		/*
 		 * We only want to do this to eTSECs.  On some platforms
 		 * there are more than one type of gianfar-style ethernet
@@ -84,7 +82,6 @@
 
 		priv = dev->priv;
 
-		printf("Device flags are %x\n", priv->flags);
 		if (priv->flags & TSEC_SGMII)
 			fdt_setprop_cell(fdt, phynode, "reg", priv->phyaddr);
 	}
diff --git a/board/freescale/m5249evb/u-boot.lds b/board/freescale/m5249evb/u-boot.lds
index aec7e9b..e3230b9 100644
--- a/board/freescale/m5249evb/u-boot.lds
+++ b/board/freescale/m5249evb/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5253demo/u-boot.lds b/board/freescale/m5253demo/u-boot.lds
index a295764..6cb5ee0 100644
--- a/board/freescale/m5253demo/u-boot.lds
+++ b/board/freescale/m5253demo/u-boot.lds
@@ -73,8 +73,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5253evbe/u-boot.lds b/board/freescale/m5253evbe/u-boot.lds
index 239cf95..132fccf 100644
--- a/board/freescale/m5253evbe/u-boot.lds
+++ b/board/freescale/m5253evbe/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5271evb/u-boot.lds b/board/freescale/m5271evb/u-boot.lds
index 0bc7fa1..00c1f2a 100644
--- a/board/freescale/m5271evb/u-boot.lds
+++ b/board/freescale/m5271evb/u-boot.lds
@@ -73,8 +73,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5272c3/u-boot.lds b/board/freescale/m5272c3/u-boot.lds
index e5c7b67..9d20b22 100644
--- a/board/freescale/m5272c3/u-boot.lds
+++ b/board/freescale/m5272c3/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5275evb/u-boot.lds b/board/freescale/m5275evb/u-boot.lds
index a3e03d5..daf8724 100644
--- a/board/freescale/m5275evb/u-boot.lds
+++ b/board/freescale/m5275evb/u-boot.lds
@@ -71,8 +71,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5282evb/u-boot.lds b/board/freescale/m5282evb/u-boot.lds
index 707b228..dc18b7d 100644
--- a/board/freescale/m5282evb/u-boot.lds
+++ b/board/freescale/m5282evb/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m53017evb/u-boot.lds b/board/freescale/m53017evb/u-boot.lds
index dc53141..c79d06c 100644
--- a/board/freescale/m53017evb/u-boot.lds
+++ b/board/freescale/m53017evb/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5329evb/nand.c b/board/freescale/m5329evb/nand.c
index cf27dda..16025f9 100644
--- a/board/freescale/m5329evb/nand.c
+++ b/board/freescale/m5329evb/nand.c
@@ -47,10 +47,12 @@
 		ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
 
 		IO_ADDR_W &= ~(SET_ALE | SET_CLE);
-		*nCE &= 0xFFFB;
 
 		if (ctrl & NAND_NCE)
+			*nCE &= 0xFFFB;
+		else
 			*nCE |= 0x0004;
+
 		if (ctrl & NAND_CLE)
 			IO_ADDR_W |= SET_CLE;
 		if (ctrl & NAND_ALE)
@@ -78,7 +80,7 @@
 	gpio->pclrr_timer = 0;
 	gpio->podr_timer = 0;
 
-	nand->chip_delay = 50;
+	nand->chip_delay = 60;
 	nand->ecc.mode = NAND_ECC_SOFT;
 	nand->cmd_ctrl = nand_hwcontrol;
 
diff --git a/board/freescale/m5329evb/u-boot.lds b/board/freescale/m5329evb/u-boot.lds
index c9da922..af31098 100644
--- a/board/freescale/m5329evb/u-boot.lds
+++ b/board/freescale/m5329evb/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m5373evb/nand.c b/board/freescale/m5373evb/nand.c
index 3ebef05..df8c03b 100644
--- a/board/freescale/m5373evb/nand.c
+++ b/board/freescale/m5373evb/nand.c
@@ -47,10 +47,12 @@
 		ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
 
 		IO_ADDR_W &= ~(SET_ALE | SET_CLE);
-		*nCE &= 0xFFFB;
 
 		if (ctrl & NAND_NCE)
+			*nCE &= 0xFFFB;
+		else
 			*nCE |= 0x0004;
+
 		if (ctrl & NAND_CLE)
 			IO_ADDR_W |= SET_CLE;
 		if (ctrl & NAND_ALE)
@@ -82,7 +84,7 @@
 	gpio->pclrr_timer = 0;
 	gpio->podr_timer = 0;
 
-	nand->chip_delay = 50;
+	nand->chip_delay = 60;
 	nand->ecc.mode = NAND_ECC_SOFT;
 	nand->cmd_ctrl = nand_hwcontrol;
 
diff --git a/board/freescale/m5373evb/u-boot.lds b/board/freescale/m5373evb/u-boot.lds
index fcf1ff1..dff74b6 100644
--- a/board/freescale/m5373evb/u-boot.lds
+++ b/board/freescale/m5373evb/u-boot.lds
@@ -72,8 +72,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m547xevb/u-boot.lds b/board/freescale/m547xevb/u-boot.lds
index c25c8dc..a3014bd 100644
--- a/board/freescale/m547xevb/u-boot.lds
+++ b/board/freescale/m547xevb/u-boot.lds
@@ -71,8 +71,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/m548xevb/u-boot.lds b/board/freescale/m548xevb/u-boot.lds
index c25c8dc..a3014bd 100644
--- a/board/freescale/m548xevb/u-boot.lds
+++ b/board/freescale/m548xevb/u-boot.lds
@@ -71,8 +71,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc7448hpc2/u-boot.lds b/board/freescale/mpc7448hpc2/u-boot.lds
index f3f6c54..cd11f39 100644
--- a/board/freescale/mpc7448hpc2/u-boot.lds
+++ b/board/freescale/mpc7448hpc2/u-boot.lds
@@ -70,9 +70,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc837xemds/pci.c b/board/freescale/mpc837xemds/pci.c
index 31116b3..29de2e7 100644
--- a/board/freescale/mpc837xemds/pci.c
+++ b/board/freescale/mpc837xemds/pci.c
@@ -115,6 +115,13 @@
 	if (PARTID_NO_E(spridr) == SPR_8379)
 		return;
 
+	if (pex2)
+		fsl_setup_serdes(CONFIG_FSL_SERDES2, FSL_SERDES_PROTO_PEX_X2,
+				 FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V);
+	else
+		fsl_setup_serdes(CONFIG_FSL_SERDES2, FSL_SERDES_PROTO_PEX,
+				 FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V);
+
 	/* Configure the clock for PCIE controller */
 	clrsetbits_be32(&clk->sccr, SCCR_PCIEXP1CM | SCCR_PCIEXP2CM,
 				    SCCR_PCIEXP1CM_1 | SCCR_PCIEXP2CM_1);
@@ -132,13 +139,6 @@
 	out_be32(&pcie_law[1].bar, CONFIG_SYS_PCIE2_BASE & LAWBAR_BAR);
 	out_be32(&pcie_law[1].ar, LBLAWAR_EN | LBLAWAR_512MB);
 
-	if (pex2)
-		fsl_setup_serdes(CONFIG_FSL_SERDES2, FSL_SERDES_PROTO_PEX_X2,
-				 FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V);
-	else
-		fsl_setup_serdes(CONFIG_FSL_SERDES2, FSL_SERDES_PROTO_PEX,
-				 FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V);
-
 	mpc83xx_pcie_init(pex2 ? 1 : 2, pcie_reg, 0);
 }
 
diff --git a/board/freescale/mpc837xerdb/pci.c b/board/freescale/mpc837xerdb/pci.c
index 8bb31fc..83e89cf 100644
--- a/board/freescale/mpc837xerdb/pci.c
+++ b/board/freescale/mpc837xerdb/pci.c
@@ -13,6 +13,7 @@
 #include <common.h>
 #include <mpc83xx.h>
 #include <pci.h>
+#include <asm/io.h>
 
 #if defined(CONFIG_PCI)
 static struct pci_region pci_regions[] = {
@@ -36,12 +37,46 @@
 	}
 };
 
+static struct pci_region pcie_regions_0[] = {
+	{
+		.bus_start = CONFIG_SYS_PCIE1_MEM_BASE,
+		.phys_start = CONFIG_SYS_PCIE1_MEM_PHYS,
+		.size = CONFIG_SYS_PCIE1_MEM_SIZE,
+		.flags = PCI_REGION_MEM,
+	},
+	{
+		.bus_start = CONFIG_SYS_PCIE1_IO_BASE,
+		.phys_start = CONFIG_SYS_PCIE1_IO_PHYS,
+		.size = CONFIG_SYS_PCIE1_IO_SIZE,
+		.flags = PCI_REGION_IO,
+	},
+};
+
+static struct pci_region pcie_regions_1[] = {
+	{
+		.bus_start = CONFIG_SYS_PCIE2_MEM_BASE,
+		.phys_start = CONFIG_SYS_PCIE2_MEM_PHYS,
+		.size = CONFIG_SYS_PCIE2_MEM_SIZE,
+		.flags = PCI_REGION_MEM,
+	},
+	{
+		.bus_start = CONFIG_SYS_PCIE2_IO_BASE,
+		.phys_start = CONFIG_SYS_PCIE2_IO_PHYS,
+		.size = CONFIG_SYS_PCIE2_IO_SIZE,
+		.flags = PCI_REGION_IO,
+	},
+};
+
 void pci_init_board(void)
 {
 	volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+	volatile sysconf83xx_t *sysconf = &immr->sysconf;
 	volatile clk83xx_t *clk = (volatile clk83xx_t *)&immr->clk;
 	volatile law83xx_t *pci_law = immr->sysconf.pcilaw;
+	volatile law83xx_t *pcie_law = sysconf->pcielaw;
 	struct pci_region *reg[] = { pci_regions };
+	struct pci_region *pcie_reg[] = { pcie_regions_0, pcie_regions_1, };
+	u32 spridr = in_be32(&immr->sysconf.spridr);
 
 	/* Enable all 5 PCI_CLK_OUTPUTS */
 	clk->occr |= 0xf8000000;
@@ -55,5 +90,27 @@
 	pci_law[1].ar = LBLAWAR_EN | LBLAWAR_1MB;
 
 	mpc83xx_pci_init(1, reg, 0);
+
+	/* There is no PEX in MPC8379 parts. */
+	if (PARTID_NO_E(spridr) == SPR_8379)
+		return;
+
+	/* Configure the clock for PCIE controller */
+	clrsetbits_be32(&clk->sccr, SCCR_PCIEXP1CM | SCCR_PCIEXP2CM,
+				    SCCR_PCIEXP1CM_1 | SCCR_PCIEXP2CM_1);
+
+	/* Deassert the resets in the control register */
+	out_be32(&sysconf->pecr1, 0xE0008000);
+	out_be32(&sysconf->pecr2, 0xE0008000);
+	udelay(2000);
+
+	/* Configure PCI Express Local Access Windows */
+	out_be32(&pcie_law[0].bar, CONFIG_SYS_PCIE1_BASE & LAWBAR_BAR);
+	out_be32(&pcie_law[0].ar, LBLAWAR_EN | LBLAWAR_512MB);
+
+	out_be32(&pcie_law[1].bar, CONFIG_SYS_PCIE2_BASE & LAWBAR_BAR);
+	out_be32(&pcie_law[1].ar, LBLAWAR_EN | LBLAWAR_512MB);
+
+	mpc83xx_pcie_init(2, pcie_reg, 0);
 }
 #endif	/* CONFIG_PCI */
diff --git a/board/freescale/mpc8536ds/u-boot.lds b/board/freescale/mpc8536ds/u-boot.lds
index 901f633..f4ff756 100644
--- a/board/freescale/mpc8536ds/u-boot.lds
+++ b/board/freescale/mpc8536ds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8540ads/u-boot.lds b/board/freescale/mpc8540ads/u-boot.lds
index 515d320..41ff3f3 100644
--- a/board/freescale/mpc8540ads/u-boot.lds
+++ b/board/freescale/mpc8540ads/u-boot.lds
@@ -68,10 +68,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8541cds/u-boot.lds b/board/freescale/mpc8541cds/u-boot.lds
index d728d8b..35d5ff2 100644
--- a/board/freescale/mpc8541cds/u-boot.lds
+++ b/board/freescale/mpc8541cds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8544ds/u-boot.lds b/board/freescale/mpc8544ds/u-boot.lds
index a05ece5..159642d 100644
--- a/board/freescale/mpc8544ds/u-boot.lds
+++ b/board/freescale/mpc8544ds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8548cds/u-boot.lds b/board/freescale/mpc8548cds/u-boot.lds
index d4a2f72..c363fe7 100644
--- a/board/freescale/mpc8548cds/u-boot.lds
+++ b/board/freescale/mpc8548cds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8555cds/u-boot.lds b/board/freescale/mpc8555cds/u-boot.lds
index 11885e8..d6584a5 100644
--- a/board/freescale/mpc8555cds/u-boot.lds
+++ b/board/freescale/mpc8555cds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8560ads/u-boot.lds b/board/freescale/mpc8560ads/u-boot.lds
index 515d320..41ff3f3 100644
--- a/board/freescale/mpc8560ads/u-boot.lds
+++ b/board/freescale/mpc8560ads/u-boot.lds
@@ -68,10 +68,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8568mds/u-boot.lds b/board/freescale/mpc8568mds/u-boot.lds
index ad96410..ffc1888 100644
--- a/board/freescale/mpc8568mds/u-boot.lds
+++ b/board/freescale/mpc8568mds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8572ds/u-boot.lds b/board/freescale/mpc8572ds/u-boot.lds
index a05ece5..159642d 100644
--- a/board/freescale/mpc8572ds/u-boot.lds
+++ b/board/freescale/mpc8572ds/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8610hpcd/u-boot.lds b/board/freescale/mpc8610hpcd/u-boot.lds
index 4127492..5cc88ae 100644
--- a/board/freescale/mpc8610hpcd/u-boot.lds
+++ b/board/freescale/mpc8610hpcd/u-boot.lds
@@ -68,10 +68,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini	     : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mpc8641hpcn/mpc8641hpcn.c b/board/freescale/mpc8641hpcn/mpc8641hpcn.c
index 49718da..c94fc3f 100644
--- a/board/freescale/mpc8641hpcn/mpc8641hpcn.c
+++ b/board/freescale/mpc8641hpcn/mpc8641hpcn.c
@@ -46,6 +46,9 @@
 		"System Version: 0x%02x, FPGA Version: 0x%02x\n",
 		in8(PIXIS_BASE + PIXIS_ID), in8(PIXIS_BASE + PIXIS_VER),
 		in8(PIXIS_BASE + PIXIS_PVER));
+#ifdef CONFIG_PHYS_64BIT
+	printf ("       36-bit physical address map\n");
+#endif
 	return 0;
 }
 
diff --git a/board/freescale/mpc8641hpcn/u-boot.lds b/board/freescale/mpc8641hpcn/u-boot.lds
index 6c9da1f..e188722 100644
--- a/board/freescale/mpc8641hpcn/u-boot.lds
+++ b/board/freescale/mpc8641hpcn/u-boot.lds
@@ -69,10 +69,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/freescale/mx31ads/u-boot.lds b/board/freescale/mx31ads/u-boot.lds
index e682f30..079184e 100644
--- a/board/freescale/mx31ads/u-boot.lds
+++ b/board/freescale/mx31ads/u-boot.lds
@@ -50,7 +50,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/g2000/u-boot.lds b/board/g2000/u-boot.lds
index d8fbea3..8c01016 100644
--- a/board/g2000/u-boot.lds
+++ b/board/g2000/u-boot.lds
@@ -57,23 +57,7 @@
   .plt : { *(.plt) }
   .text      :
   {
-    /* WARNING - the following is hand-optimized to fit within	*/
-    /* the sector layout of our flash chips!	XXX FIXME XXX	*/
-
     cpu/ppc4xx/start.o	(.text)
-    cpu/ppc4xx/traps.o	(.text)
-    cpu/ppc4xx/interrupts.o	(.text)
-    cpu/ppc4xx/4xx_uart.o	(.text)
-    cpu/ppc4xx/cpu_init.o	(.text)
-    cpu/ppc4xx/speed.o	(.text)
-    drivers/net/4xx_enet.o	(.text)
-    common/dlmalloc.o	(.text)
-    lib_generic/crc32.o		(.text)
-    lib_ppc/extable.o	(.text)
-    lib_generic/zlib.o		(.text)
-
-/*    . = env_offset;*/
-/*    common/env_embedded.o(.text)*/
 
     *(.text)
     *(.fixup)
@@ -83,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gaisler/gr_cpci_ax2000/u-boot.lds b/board/gaisler/gr_cpci_ax2000/u-boot.lds
index a087631..d5d7842 100644
--- a/board/gaisler/gr_cpci_ax2000/u-boot.lds
+++ b/board/gaisler/gr_cpci_ax2000/u-boot.lds
@@ -77,10 +77,8 @@
 		*(.gnu.warning)
 /*		*(.got1)*/
 		. = ALIGN(16);
-		*(.rodata)
-		*(.rodata1)
-		*(.rodata.*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN(4);
 	_etext = .;
diff --git a/board/gaisler/gr_ep2s60/u-boot.lds b/board/gaisler/gr_ep2s60/u-boot.lds
index e461a36..99aa0ad 100644
--- a/board/gaisler/gr_ep2s60/u-boot.lds
+++ b/board/gaisler/gr_ep2s60/u-boot.lds
@@ -77,10 +77,8 @@
 		*(.gnu.warning)
 /*		*(.got1)*/
 		. = ALIGN(16);
-		*(.rodata)
-		*(.rodata1)
-		*(.rodata.*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN(4);
 	_etext = .;
diff --git a/board/gaisler/gr_xc3s_1500/u-boot.lds b/board/gaisler/gr_xc3s_1500/u-boot.lds
index ddd27d4..3b13190 100644
--- a/board/gaisler/gr_xc3s_1500/u-boot.lds
+++ b/board/gaisler/gr_xc3s_1500/u-boot.lds
@@ -77,10 +77,8 @@
 		*(.gnu.warning)
 /*		*(.got1)*/
 		. = ALIGN(16);
-		*(.rodata)
-		*(.rodata1)
-		*(.rodata.*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN(4);
 	_etext = .;
diff --git a/board/gaisler/grsim/u-boot.lds b/board/gaisler/grsim/u-boot.lds
index a9cc7ca..0fa6627 100644
--- a/board/gaisler/grsim/u-boot.lds
+++ b/board/gaisler/grsim/u-boot.lds
@@ -76,10 +76,8 @@
 		*(.gnu.warning)
 /*		*(.got1)*/
 		. = ALIGN(16);
-		*(.rodata)
-		*(.rodata1)
-		*(.rodata.*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN(4);
 	_etext = .;
diff --git a/board/gaisler/grsim_leon2/u-boot.lds b/board/gaisler/grsim_leon2/u-boot.lds
index b3462d4..c5311a6 100644
--- a/board/gaisler/grsim_leon2/u-boot.lds
+++ b/board/gaisler/grsim_leon2/u-boot.lds
@@ -76,10 +76,8 @@
 		*(.gnu.warning)
 /*		*(.got1)*/
 		. = ALIGN(16);
-		*(.rodata)
-		*(.rodata1)
-		*(.rodata.*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	. = ALIGN(4);
 	_etext = .;
diff --git a/board/gcplus/u-boot.lds b/board/gcplus/u-boot.lds
index ab7f76b..65b8167 100644
--- a/board/gcplus/u-boot.lds
+++ b/board/gcplus/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/gdsys/gdppc440etx/u-boot.lds b/board/gdsys/gdppc440etx/u-boot.lds
index 1df817b..77f0aae 100644
--- a/board/gdsys/gdppc440etx/u-boot.lds
+++ b/board/gdsys/gdppc440etx/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gdsys/neo/u-boot.lds b/board/gdsys/neo/u-boot.lds
index d803625..b95eb5c 100644
--- a/board/gdsys/neo/u-boot.lds
+++ b/board/gdsys/neo/u-boot.lds
@@ -67,9 +67,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gen860t/u-boot-flashenv.lds b/board/gen860t/u-boot-flashenv.lds
index 6c8346a..9785639 100644
--- a/board/gen860t/u-boot-flashenv.lds
+++ b/board/gen860t/u-boot-flashenv.lds
@@ -64,9 +64,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gen860t/u-boot.lds b/board/gen860t/u-boot.lds
index cab7a10..fbe3c70 100644
--- a/board/gen860t/u-boot.lds
+++ b/board/gen860t/u-boot.lds
@@ -63,10 +63,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/genietv/u-boot.lds b/board/genietv/u-boot.lds
index 3c19d19..ee0b719 100644
--- a/board/genietv/u-boot.lds
+++ b/board/genietv/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gth/u-boot.lds b/board/gth/u-boot.lds
index d5df1f4..8826550 100644
--- a/board/gth/u-boot.lds
+++ b/board/gth/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/gth2/u-boot.lds b/board/gth2/u-boot.lds
index 0594643..e6eee9b 100644
--- a/board/gth2/u-boot.lds
+++ b/board/gth2/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/hermes/u-boot.lds b/board/hermes/u-boot.lds
index 540e614..02216fb 100644
--- a/board/hermes/u-boot.lds
+++ b/board/hermes/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/hymod/u-boot.lds b/board/hymod/u-boot.lds
index fdd584d..03fefec 100644
--- a/board/hymod/u-boot.lds
+++ b/board/hymod/u-boot.lds
@@ -75,10 +75,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/icu862/u-boot.lds b/board/icu862/u-boot.lds
index 645baa0..9a28cfd 100644
--- a/board/icu862/u-boot.lds
+++ b/board/icu862/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/idmr/u-boot.lds b/board/idmr/u-boot.lds
index 0bc7fa1..00c1f2a 100644
--- a/board/idmr/u-boot.lds
+++ b/board/idmr/u-boot.lds
@@ -73,8 +73,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/impa7/u-boot.lds b/board/impa7/u-boot.lds
index a79bb8c..8c9f624 100644
--- a/board/impa7/u-boot.lds
+++ b/board/impa7/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/imx31_litekit/u-boot.lds b/board/imx31_litekit/u-boot.lds
index 9285bd5..f840017 100644
--- a/board/imx31_litekit/u-boot.lds
+++ b/board/imx31_litekit/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/imx31_phycore/imx31_phycore.c b/board/imx31_phycore/imx31_phycore.c
index ae93444..93a5c40 100644
--- a/board/imx31_phycore/imx31_phycore.c
+++ b/board/imx31_phycore/imx31_phycore.c
@@ -23,6 +23,7 @@
 
 
 #include <common.h>
+#include <s6e63d6.h>
 #include <asm/arch/mx31.h>
 #include <asm/arch/mx31-regs.h>
 
@@ -66,6 +67,62 @@
 	return 0;
 }
 
+#ifdef BOARD_LATE_INIT
+int board_late_init(void)
+{
+#ifdef CONFIG_S6E63D6
+	struct s6e63d6 data = {
+		/*
+		 * See comment in mxc_spi.c::decode_cs() for .cs field format.
+		 * We use GPIO 57 as a chipselect for the S6E63D6 and chipselect
+		 * 2 of the SPI controller #1, since it is unused.
+		 */
+		.cs = 2 | (57 << 8),
+		.bus = 0,
+		.id = 0,
+	};
+	int ret;
+
+	/* SPI1 */
+	mx31_gpio_mux(MUX_CSPI1_SCLK__CSPI1_CLK);
+	mx31_gpio_mux(MUX_CSPI1_SPI_RDY__CSPI1_DATAREADY_B);
+	mx31_gpio_mux(MUX_CSPI1_MOSI__CSPI1_MOSI);
+	mx31_gpio_mux(MUX_CSPI1_MISO__CSPI1_MISO);
+	mx31_gpio_mux(MUX_CSPI1_SS0__CSPI1_SS0_B);
+	mx31_gpio_mux(MUX_CSPI1_SS1__CSPI1_SS1_B);
+	mx31_gpio_mux(MUX_CSPI1_SS2__CSPI1_SS2_B);
+
+	/* start SPI1 clock */
+	__REG(CCM_CGR2) = __REG(CCM_CGR2) | (3 << 2);
+
+	/* GPIO 57 */
+	/* sw_mux_ctl_key_col4_key_col5_key_col6_key_col7 */
+	mx31_gpio_mux(IOMUX_MODE(0x63, MUX_CTL_GPIO));
+
+	/* SPI1 CS2 is free */
+	ret = s6e63d6_init(&data);
+	if (ret)
+		return ret;
+
+	/*
+	 * This is a "magic" sequence to initialise a C0240QGLA / C0283QGLC
+	 * OLED display connected to a S6E63D6 SPI display controller in the
+	 * 18 bit RGB mode
+	 */
+	s6e63d6_index(&data, 2);
+	s6e63d6_param(&data, 0x0182);
+	s6e63d6_index(&data, 3);
+	s6e63d6_param(&data, 0x8130);
+	s6e63d6_index(&data, 0x10);
+	s6e63d6_param(&data, 0x0000);
+	s6e63d6_index(&data, 5);
+	s6e63d6_param(&data, 0x0001);
+	s6e63d6_index(&data, 0x22);
+#endif
+	return 0;
+}
+#endif
+
 int checkboard (void)
 {
 	printf("Board: Phytec phyCore i.MX31\n");
diff --git a/board/imx31_phycore/u-boot.lds b/board/imx31_phycore/u-boot.lds
index 9285bd5..f840017 100644
--- a/board/imx31_phycore/u-boot.lds
+++ b/board/imx31_phycore/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/incaip/u-boot.lds b/board/incaip/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/incaip/u-boot.lds
+++ b/board/incaip/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/innokom/u-boot.lds b/board/innokom/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/innokom/u-boot.lds
+++ b/board/innokom/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/ip860/u-boot.lds b/board/ip860/u-boot.lds
index d1cb7e2..b47ae8e 100644
--- a/board/ip860/u-boot.lds
+++ b/board/ip860/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ivm/u-boot.lds b/board/ivm/u-boot.lds
index 2583a59..ab51bd8 100644
--- a/board/ivm/u-boot.lds
+++ b/board/ivm/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ixdp425/u-boot.lds b/board/ixdp425/u-boot.lds
index f46a7c7..7c287e1 100644
--- a/board/ixdp425/u-boot.lds
+++ b/board/ixdp425/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/jse/u-boot.lds b/board/jse/u-boot.lds
index 7141c5a..12d3938 100644
--- a/board/jse/u-boot.lds
+++ b/board/jse/u-boot.lds
@@ -75,10 +75,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/kb9202/u-boot.lds b/board/kb9202/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/kb9202/u-boot.lds
+++ b/board/kb9202/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c
index 1338950..b2bd7fd 100644
--- a/board/keymile/common/common.c
+++ b/board/keymile/common/common.c
@@ -295,11 +295,14 @@
 
 int ivm_read_eeprom (void)
 {
+#if defined(CONFIG_I2C_MUX)
 	I2C_MUX_DEVICE *dev = NULL;
+#endif
 	uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN];
 	uchar	*buf;
 	unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR;
 
+#if defined(CONFIG_I2C_MUX)
 	/* First init the Bus, select the Bus */
 #if defined(CONFIG_SYS_I2C_IVM_BUS)
 	dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS);
@@ -313,12 +316,13 @@
 		return -1;
 	}
 	i2c_set_bus_num (dev->busid);
+#endif
 
 	buf = (unsigned char *) getenv ("EEprom_ivm_addr");
 	if (buf != NULL)
 		dev_addr = simple_strtoul ((char *)buf, NULL, 16);
 
-	if (eeprom_read (dev_addr, 0, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) {
+	if (i2c_read(dev_addr, 0, 1, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) {
 		printf ("Error reading EEprom\n");
 		return -2;
 	}
@@ -390,7 +394,7 @@
 #endif
 #endif
 
-#if defined(CONFIG_MGSUVD)
+#if defined(CONFIG_KM8XX)
 static void set_sda (int state)
 {
 	I2C_SDA(state);
diff --git a/board/keymile/common/keymile_hdlc_enet.h b/board/keymile/common/keymile_hdlc_enet.h
index 965bd5a..db1560f 100644
--- a/board/keymile/common/keymile_hdlc_enet.h
+++ b/board/keymile/common/keymile_hdlc_enet.h
@@ -25,7 +25,7 @@
 #define _KEYMILE_HDLC_ENET_H_
 
 /* Unfortuantely, we have do this to get the flag defines in the cbd_t */
-#ifdef CONFIG_MGSUVD
+#ifdef CONFIG_KM8XX
 #include <commproc.h>
 #endif
 #ifdef CONFIG_MGCOGE
diff --git a/board/keymile/mgsuvd/Makefile b/board/keymile/km8xx/Makefile
similarity index 98%
rename from board/keymile/mgsuvd/Makefile
rename to board/keymile/km8xx/Makefile
index 2c5732d..a6f3241 100644
--- a/board/keymile/mgsuvd/Makefile
+++ b/board/keymile/km8xx/Makefile
@@ -29,7 +29,7 @@
 LIB	= $(obj)lib$(BOARD).a
 
 COBJS	= $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
-		mgsuvd_hdlc_enet.o
+		km8xx_hdlc_enet.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/board/keymile/mgsuvd/config.mk b/board/keymile/km8xx/config.mk
similarity index 100%
rename from board/keymile/mgsuvd/config.mk
rename to board/keymile/km8xx/config.mk
diff --git a/board/keymile/mgsuvd/mgsuvd.c b/board/keymile/km8xx/km8xx.c
similarity index 96%
rename from board/keymile/mgsuvd/mgsuvd.c
rename to board/keymile/km8xx/km8xx.c
index e7bfa31..7c58179 100644
--- a/board/keymile/mgsuvd/mgsuvd.c
+++ b/board/keymile/km8xx/km8xx.c
@@ -61,7 +61,12 @@
 
 int checkboard (void)
 {
-	puts ("Board: Keymile mgsuvd");
+	puts ("Board: Keymile ");
+#if defined(CONFIG_KMSUPX4)
+	puts ("kmsupx4");
+#else
+	puts ("mgsuvd");
+#endif
 	if (ethernet_present ())
 		puts (" with PIGGY.");
 	puts ("\n");
@@ -169,6 +174,7 @@
 	ulong memory_data[2] = {0};
 	ulong flash_data[4] = {0};
 	ulong flash_reg[3] = {0};
+	uchar enetaddr[6];
 
 	memory_data[0] = cpu_to_be32 (bd->bi_memstart);
 	memory_data[1] = cpu_to_be32 (bd->bi_memsize);
@@ -190,8 +196,9 @@
 				sizeof (brg_data));
 
 	/* MAC adr */
+	eth_getenv_enetaddr("ethaddr", enetaddr);
 	fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
-				bd->bi_enetaddr, sizeof (u8) * 6);
+				enetaddr, sizeof (u8) * 6);
 }
 
 void ft_board_setup(void *blob, bd_t *bd)
diff --git a/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c b/board/keymile/km8xx/km8xx_hdlc_enet.c
similarity index 100%
rename from board/keymile/mgsuvd/mgsuvd_hdlc_enet.c
rename to board/keymile/km8xx/km8xx_hdlc_enet.c
diff --git a/board/keymile/mgsuvd/u-boot.lds b/board/keymile/km8xx/u-boot.lds
similarity index 100%
rename from board/keymile/mgsuvd/u-boot.lds
rename to board/keymile/km8xx/u-boot.lds
diff --git a/board/keymile/kmeter1/kmeter1.c b/board/keymile/kmeter1/kmeter1.c
index f04a57a..660d87b 100644
--- a/board/keymile/kmeter1/kmeter1.c
+++ b/board/keymile/kmeter1/kmeter1.c
@@ -24,11 +24,14 @@
 #include <miiphy.h>
 #include <asm/io.h>
 #include <asm/mmu.h>
+#include <asm/processor.h>
 #include <pci.h>
 #include <libfdt.h>
 
 #include "../common/common.h"
 
+extern void disable_addr_trans (void);
+extern void enable_addr_trans (void);
 const qe_iop_conf_t qe_iop_conf_tab[] = {
 	/* port pin dir open_drain assign */
 
@@ -59,27 +62,54 @@
 	{0,  0, 0, 0, QE_IOP_TAB_END},
 };
 
+static int board_init_i2c_busses (void)
+{
+	I2C_MUX_DEVICE *dev = NULL;
+	uchar	*buf;
+
+	/* Set up the Bus for the DTTs */
+	buf = (unsigned char *) getenv ("dtt_bus");
+	if (buf != NULL)
+		dev = i2c_mux_ident_muxstring (buf);
+	if (dev == NULL) {
+		printf ("Error couldn't add Bus for DTT\n");
+		printf ("please setup dtt_bus to where your\n");
+		printf ("DTT is found.\n");
+	}
+	return 0;
+}
+
 int board_early_init_r (void)
 {
-	void *reg = (void *)(CONFIG_SYS_IMMR + 0x14a8);
-	u32 val;
+	unsigned short	svid;
 
 	/*
 	 * Because of errata in the UCCs, we have to write to the reserved
 	 * registers to slow the clocks down.
 	 */
-	val = in_be32 (reg);
-	/* UCC1 */
-	val |= 0x00003000;
-	/* UCC2 */
-	val |= 0x0c000000;
-	out_be32 (reg, val);
+	svid =  SVR_REV(mfspr (SVR));
+	switch (svid) {
+	case 0x0020:
+		setbits_be32((void *)(CONFIG_SYS_IMMR + 0x14a8), 0x0c003000);
+		break;
+	case 0x0021:
+		clrsetbits_be32((void *)(CONFIG_SYS_IMMR + 0x14ac),
+			0x00000050, 0x000000a0);
+		break;
+	}
 	/* enable the PHY on the PIGGY */
 	setbits (8, (void *)(CONFIG_SYS_PIGGY_BASE + 0x10003), 0x01);
 
 	return 0;
 }
 
+int misc_init_r (void)
+{
+	/* add board specific i2c busses */
+	board_init_i2c_busses ();
+	return 0;
+}
+
 int fixed_sdram(void)
 {
 	volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
@@ -87,16 +117,7 @@
 	u32 ddr_size;
 	u32 ddr_size_log2;
 
-	msize = CONFIG_SYS_DDR_SIZE;
-	for (ddr_size = msize << 20, ddr_size_log2 = 0;
-	     (ddr_size > 1); ddr_size = ddr_size >> 1, ddr_size_log2++) {
-		if (ddr_size & 1)
-			return -1;
-	}
-
-	im->sysconf.ddrlaw[0].ar =
-	    LAWAR_EN | ((ddr_size_log2 - 1) & LAWAR_SIZE);
-
+	im->sysconf.ddrlaw[0].ar = LAWAR_EN | 0x1e;
 	im->ddr.csbnds[0].csbnds = CONFIG_SYS_DDR_CS0_BNDS;
 	im->ddr.cs_config[0] = CONFIG_SYS_DDR_CS0_CONFIG;
 	im->ddr.timing_cfg_0 = CONFIG_SYS_DDR_TIMING_0;
@@ -112,6 +133,21 @@
 	udelay (200);
 	im->ddr.sdram_cfg |= SDRAM_CFG_MEM_EN;
 
+	msize = CONFIG_SYS_DDR_SIZE << 20;
+	disable_addr_trans ();
+	msize = get_ram_size (CONFIG_SYS_DDR_BASE, msize);
+	enable_addr_trans ();
+	msize /= (1024 * 1024);
+	if (CONFIG_SYS_DDR_SIZE != msize) {
+		for (ddr_size = msize << 20, ddr_size_log2 = 0;
+		     (ddr_size > 1); ddr_size = ddr_size >> 1, ddr_size_log2++)
+			if (ddr_size & 1)
+				return -1;
+		im->sysconf.ddrlaw[0].ar =
+		    LAWAR_EN | ((ddr_size_log2 - 1) & LAWAR_SIZE);
+		im->ddr.csbnds[0].csbnds = (((msize / 16) - 1) & 0xff);
+	}
+
 	return msize;
 }
 
@@ -156,3 +192,12 @@
 	ft_cpu_setup (blob, bd);
 }
 #endif
+
+#if defined(CONFIG_HUSH_INIT_VAR)
+extern int ivm_read_eeprom (void);
+int hush_init_var (void)
+{
+	ivm_read_eeprom ();
+	return 0;
+}
+#endif
diff --git a/board/keymile/mgcoge/mgcoge.c b/board/keymile/mgcoge/mgcoge.c
index 0e3aa49..67722e7 100644
--- a/board/keymile/mgcoge/mgcoge.c
+++ b/board/keymile/mgcoge/mgcoge.c
@@ -326,6 +326,7 @@
 	ulong memory_data[2] = {0};
 	ulong flash_data[8] = {0};
 	flash_info_t	*info;
+	uchar enetaddr[6];
 
 	memory_data[0] = cpu_to_be32 (bd->bi_memstart);
 	memory_data[1] = cpu_to_be32 (bd->bi_memsize);
@@ -344,8 +345,9 @@
 	fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data,
 				sizeof (flash_data));
 	/* MAC addr */
+	eth_getenv_enetaddr("ethaddr", enetaddr);
 	fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address",
-				bd->bi_enetaddr, sizeof (u8) * 6);
+				enetaddr, sizeof (u8) * 6);
 }
 
 void ft_board_setup (void *blob, bd_t *bd)
diff --git a/board/korat/u-boot-F7FC.lds b/board/korat/u-boot-F7FC.lds
index 9bed401..c175f91 100644
--- a/board/korat/u-boot-F7FC.lds
+++ b/board/korat/u-boot-F7FC.lds
@@ -75,9 +75,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/korat/u-boot.lds b/board/korat/u-boot.lds
index 05152b7..7798722 100644
--- a/board/korat/u-boot.lds
+++ b/board/korat/u-boot.lds
@@ -75,9 +75,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/kup/common/kup.h b/board/kup/common/kup.h
index 70d7f01..b736283 100644
--- a/board/kup/common/kup.h
+++ b/board/kup/common/kup.h
@@ -41,4 +41,6 @@
 
 extern void poweron_key (void);
 
+extern void load_sernum_ethaddr(void);
+
 #endif	/* __KUP_H */
diff --git a/board/kup/kup4k/kup4k.c b/board/kup/kup4k/kup4k.c
index df3ffb4..98f5f5a 100644
--- a/board/kup/kup4k/kup4k.c
+++ b/board/kup/kup4k/kup4k.c
@@ -250,6 +250,7 @@
 	immap->im_ioport.iop_papar &= ~0x80;
 	immap->im_ioport.iop_padat |= 0x80;	/* turn it off */
 #endif
+	load_sernum_ethaddr();
 	setenv("hw","4k");
 	poweron_key();
 	return (0);
diff --git a/board/kup/kup4k/u-boot.lds b/board/kup/kup4k/u-boot.lds
index 120ca00..f2b6650 100644
--- a/board/kup/kup4k/u-boot.lds
+++ b/board/kup/kup4k/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/kup/kup4x/kup4x.c b/board/kup/kup4x/kup4x.c
index c5b742d..65a222b 100644
--- a/board/kup/kup4x/kup4x.c
+++ b/board/kup/kup4x/kup4x.c
@@ -295,7 +295,6 @@
 int misc_init_r (void)
 {
 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
-
 #ifdef CONFIG_IDE_LED
 	/* Configure PA8 as output port */
 	immap->im_ioport.iop_padir |= 0x80;
@@ -306,6 +305,7 @@
 #ifdef KUP4X_USB
 	usb_init_kup4x ();
 #endif
+	load_sernum_ethaddr();
 	setenv ("hw", "4x");
 	poweron_key ();
 	return (0);
diff --git a/board/kup/kup4x/u-boot.lds b/board/kup/kup4x/u-boot.lds
index 120ca00..f2b6650 100644
--- a/board/kup/kup4x/u-boot.lds
+++ b/board/kup/kup4x/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/lantec/u-boot.lds b/board/lantec/u-boot.lds
index 6028c26..b9fa2d6 100644
--- a/board/lantec/u-boot.lds
+++ b/board/lantec/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/lart/u-boot.lds b/board/lart/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/lart/u-boot.lds
+++ b/board/lart/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/logodl/u-boot.lds b/board/logodl/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/logodl/u-boot.lds
+++ b/board/logodl/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/lpc2292sodimm/u-boot.lds b/board/lpc2292sodimm/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/lpc2292sodimm/u-boot.lds
+++ b/board/lpc2292sodimm/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/lpd7a40x/u-boot.lds b/board/lpd7a40x/u-boot.lds
index 3c14437..b98ed95 100644
--- a/board/lpd7a40x/u-boot.lds
+++ b/board/lpd7a40x/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/lubbock/u-boot.lds b/board/lubbock/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/lubbock/u-boot.lds
+++ b/board/lubbock/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/lwmon/u-boot.lds b/board/lwmon/u-boot.lds
index 319cc7b..9e46f9d 100644
--- a/board/lwmon/u-boot.lds
+++ b/board/lwmon/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/lwmon5/sdram.c b/board/lwmon5/sdram.c
index 72968d7..a482387 100644
--- a/board/lwmon5/sdram.c
+++ b/board/lwmon5/sdram.c
@@ -160,49 +160,6 @@
  ************************************************************************/
 phys_size_t initdram (int board_type)
 {
-#if 0 /* test-only: will remove this define later, when ECC problems are solved! */
-	/* CL=3 */
-	mtsdram(DDR0_02, 0x00000000);
-
-	mtsdram(DDR0_00, 0x0000190A);
-	mtsdram(DDR0_01, 0x01000000);
-	mtsdram(DDR0_03, 0x02030603); /* A suitable burst length was taken. CAS is right for our board */
-
-	mtsdram(DDR0_04, 0x0A030300);
-	mtsdram(DDR0_05, 0x02020308);
-	mtsdram(DDR0_06, 0x0103C812);
-	mtsdram(DDR0_07, 0x00090100);
-	mtsdram(DDR0_08, 0x02c80001);
-	mtsdram(DDR0_09, 0x00011D5F);
-	mtsdram(DDR0_10, 0x00000300);
-	mtsdram(DDR0_11, 0x000CC800);
-	mtsdram(DDR0_12, 0x00000003);
-	mtsdram(DDR0_14, 0x00000000);
-	mtsdram(DDR0_17, 0x1e000000);
-	mtsdram(DDR0_18, 0x1e1e1e1e);
-	mtsdram(DDR0_19, 0x1e1e1e1e);
-	mtsdram(DDR0_20, 0x0B0B0B0B);
-	mtsdram(DDR0_21, 0x0B0B0B0B);
-#ifdef CONFIG_DDR_ECC
-	mtsdram(DDR0_22, 0x00267F0B | DDR0_22_CTRL_RAW_ECC_ENABLE); /* enable ECC	*/
-#else
-	mtsdram(DDR0_22, 0x00267F0B);
-#endif
-
-	mtsdram(DDR0_23, 0x01000000);
-	mtsdram(DDR0_24, 0x01010001);
-
-	mtsdram(DDR0_26, 0x2D93028A);
-	mtsdram(DDR0_27, 0x0784682B);
-
-	mtsdram(DDR0_28, 0x00000080);
-	mtsdram(DDR0_31, 0x00000000);
-	mtsdram(DDR0_42, 0x01000006);
-
-	mtsdram(DDR0_43, 0x030A0200);
-	mtsdram(DDR0_44, 0x00000003);
-	mtsdram(DDR0_02, 0x00000001); /* Activate the denali core */
-#else
 	/* CL=4 */
 	mtsdram(DDR0_02, 0x00000000);
 
@@ -216,7 +173,7 @@
 	mtsdram(DDR0_07, 0x00090100);
 	mtsdram(DDR0_08, 0x03c80001);
 	mtsdram(DDR0_09, 0x00011D5F);
-	mtsdram(DDR0_10, 0x00000300);
+	mtsdram(DDR0_10, 0x00000100);
 	mtsdram(DDR0_11, 0x000CC800);
 	mtsdram(DDR0_12, 0x00000003);
 	mtsdram(DDR0_14, 0x00000000);
@@ -244,7 +201,6 @@
 	mtsdram(DDR0_43, 0x050A0200);
 	mtsdram(DDR0_44, 0x00000005);
 	mtsdram(DDR0_02, 0x00000001); /* Activate the denali core */
-#endif
 
 	denali_wait_for_dlllock();
 
diff --git a/board/lwmon5/u-boot.lds b/board/lwmon5/u-boot.lds
index 05152b7..7798722 100644
--- a/board/lwmon5/u-boot.lds
+++ b/board/lwmon5/u-boot.lds
@@ -75,9 +75,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/m501sk/m501sk.c b/board/m501sk/m501sk.c
index 65a8b29..dc5b786 100644
--- a/board/m501sk/m501sk.c
+++ b/board/m501sk/m501sk.c
@@ -105,11 +105,6 @@
 	return status;
 }
 
-void load_sernum_ethaddr(void)
-{
-	return;
-}
-
 /*
  * Miscelaneous platform dependent initialisations
  */
diff --git a/board/m501sk/u-boot.lds b/board/m501sk/u-boot.lds
index ae6caf5..2247c37 100644
--- a/board/m501sk/u-boot.lds
+++ b/board/m501sk/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/mbx8xx/mbx8xx.c b/board/mbx8xx/mbx8xx.c
index af4f57d..a3bf1f7 100644
--- a/board/mbx8xx/mbx8xx.c
+++ b/board/mbx8xx/mbx8xx.c
@@ -241,7 +241,7 @@
 	return *((ulong *) packet->data);
 }
 
-void board_get_enetaddr (uchar * addr)
+static void board_get_enetaddr(uchar *addr)
 {
 	int i;
 	vpd_packet_t *packet;
@@ -251,6 +251,18 @@
 		addr[i] = packet->data[i];
 }
 
+int misc_init_r(void)
+{
+	uchar enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+
+	return 0;
+}
+
 /*
  * Check Board Identity:
  */
diff --git a/board/mbx8xx/u-boot.lds b/board/mbx8xx/u-boot.lds
index 24484c7..ca35e88 100644
--- a/board/mbx8xx/u-boot.lds
+++ b/board/mbx8xx/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/micronas/vct/u-boot.lds b/board/micronas/vct/u-boot.lds
index da9e605..b90b186 100644
--- a/board/micronas/vct/u-boot.lds
+++ b/board/micronas/vct/u-boot.lds
@@ -35,7 +35,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/mimc/mimc200/mimc200.c b/board/mimc/mimc200/mimc200.c
index 1092cd0..6df741e 100644
--- a/board/mimc/mimc200/mimc200.c
+++ b/board/mimc/mimc200/mimc200.c
@@ -30,7 +30,7 @@
 #include <asm/arch/portmux.h>
 #include <lcd.h>
 
-#define SM_PM_GCCTRL				0x0060
+#include "../../../cpu/at32ap/hsmc3.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -76,22 +76,30 @@
 
 	/* are we suppressing the console ? */
 	if (gpio_get_value(GPIO_PIN_PE(21)) == 1)
-		gd->flags |= GD_FLG_SILENT;
+		gd->flags |= (GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE);
 
 	/* reset phys */
 	portmux_select_gpio(PORTMUX_PORT_E, 1 << 24, PORTMUX_DIR_INPUT);
 	portmux_select_gpio(PORTMUX_PORT_C, 1 << 18,
 			PORTMUX_DIR_OUTPUT | PORTMUX_INIT_HIGH);
 
-	/* GCLK0 - 10MHz clock */
-	writel(0x00000004, (void *)SM_BASE + SM_PM_GCCTRL);
-	portmux_select_peripheral(PORTMUX_PORT_A, 1 << 30, PORTMUX_FUNC_A, 0);
-
 	udelay(5000);
 
 	/* release phys reset */
 	gpio_set_value(GPIO_PIN_PC(18), 0);	/* PHY RESET (Release)	*/
 
+	/* setup Data Flash chip select (NCS2) */
+	hsmc3_writel(MODE2, 0x20121003);
+	hsmc3_writel(CYCLE2, 0x000a0009);
+	hsmc3_writel(PULSE2, 0x0a060806);
+	hsmc3_writel(SETUP2, 0x00030102);
+
+	/* setup FRAM chip select (NCS3) */
+	hsmc3_writel(MODE3, 0x10120001);
+	hsmc3_writel(CYCLE3, 0x001e001d);
+	hsmc3_writel(PULSE3, 0x08040704);
+	hsmc3_writel(SETUP3, 0x02050204);
+
 #if defined(CONFIG_MACB)
 	/* init macb0 pins */
 	portmux_enable_macb0(PORTMUX_MACB_MII, PORTMUX_DRIVE_HIGH);
@@ -132,6 +140,14 @@
 	return 0;
 }
 
+int board_postclk_init(void)
+{
+	/* Use GCLK0 as 10MHz output */
+	gclk_enable_output(0, PORTMUX_DRIVE_LOW);
+	gclk_set_rate(0, GCLK_PARENT_OSC0, 10000000);
+	return 0;
+}
+
 /* SPI chip select control */
 #ifdef CONFIG_ATMEL_SPI
 #include <spi.h>
diff --git a/board/mimc/mimc200/u-boot.lds b/board/mimc/mimc200/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/mimc/mimc200/u-boot.lds
+++ b/board/mimc/mimc200/u-boot.lds
@@ -36,8 +36,7 @@
 	_etext = .;
 
 	.rodata : {
-		*(.rodata)
-		*(.rodata.*)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/board/miromico/hammerhead/u-boot.lds b/board/miromico/hammerhead/u-boot.lds
index e736adf..a7243f2 100644
--- a/board/miromico/hammerhead/u-boot.lds
+++ b/board/miromico/hammerhead/u-boot.lds
@@ -36,8 +36,7 @@
 	_etext = .;
 
 	.rodata : {
-		*(.rodata)
-		*(.rodata.*)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/board/ml2/u-boot.lds b/board/ml2/u-boot.lds
index 13ceea0..a6b6748 100644
--- a/board/ml2/u-boot.lds
+++ b/board/ml2/u-boot.lds
@@ -79,10 +79,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/modnet50/u-boot.lds b/board/modnet50/u-boot.lds
index a435466..b72e126 100644
--- a/board/modnet50/u-boot.lds
+++ b/board/modnet50/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/mousse/u-boot.lds b/board/mousse/u-boot.lds
index 8188873..44144e2 100644
--- a/board/mousse/u-boot.lds
+++ b/board/mousse/u-boot.lds
@@ -62,10 +62,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/mp2usb/u-boot.lds b/board/mp2usb/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/mp2usb/u-boot.lds
+++ b/board/mp2usb/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/mpc8540eval/u-boot.lds b/board/mpc8540eval/u-boot.lds
index d65ccbe..0747913 100644
--- a/board/mpc8540eval/u-boot.lds
+++ b/board/mpc8540eval/u-boot.lds
@@ -73,10 +73,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/mpl/mip405/u-boot.lds b/board/mpl/mip405/u-boot.lds
index 8714c2b..d71a299 100644
--- a/board/mpl/mip405/u-boot.lds
+++ b/board/mpl/mip405/u-boot.lds
@@ -89,10 +89,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/mpl/pip405/u-boot.lds b/board/mpl/pip405/u-boot.lds
index afe203b..f6f88a7 100644
--- a/board/mpl/pip405/u-boot.lds
+++ b/board/mpl/pip405/u-boot.lds
@@ -84,10 +84,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/mpl/vcma9/cmd_vcma9.c b/board/mpl/vcma9/cmd_vcma9.c
index 2748fa9..7d2aa3c 100644
--- a/board/mpl/vcma9/cmd_vcma9.c
+++ b/board/mpl/vcma9/cmd_vcma9.c
@@ -76,21 +76,18 @@
 			cs8900_e2prom_write(addr, data);
 		} else if (strcmp(argv[2], "setaddr") == 0) {
 			uchar addr, i, csum; ushort data;
+			uchar ethaddr[6];
 
 			/* check for valid ethaddr */
-			for (i = 0; i < 6; i++)
-				if (gd->bd->bi_enetaddr[i] != 0)
-					break;
-
-			if (i < 6) {
+			if (eth_getenv_enetaddr("ethaddr", ethaddr)) {
 				addr = 1;
 				data = 0x2158;
 				cs8900_e2prom_write(addr, data);
 				csum = cs8900_chksum(data);
 				addr++;
 				for (i = 0; i < 6; i+=2) {
-					data = gd->bd->bi_enetaddr[i+1] << 8 |
-					       gd->bd->bi_enetaddr[i];
+					data = enetaddr[i+1] << 8 |
+					       enetaddr[i];
 					cs8900_e2prom_write(addr, data);
 					csum += cs8900_chksum(data);
 					addr++;
diff --git a/board/mpl/vcma9/u-boot.lds b/board/mpl/vcma9/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/mpl/vcma9/u-boot.lds
+++ b/board/mpl/vcma9/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/mpr2/u-boot.lds b/board/mpr2/u-boot.lds
index b1f0e1d..deae344 100644
--- a/board/mpr2/u-boot.lds
+++ b/board/mpr2/u-boot.lds
@@ -63,7 +63,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/ms7720se/lowlevel_init.S b/board/ms7720se/lowlevel_init.S
index dcb77ef..7593811 100644
--- a/board/ms7720se/lowlevel_init.S
+++ b/board/ms7720se/lowlevel_init.S
@@ -18,6 +18,8 @@
  * MA 02111-1307 USA
  */
 
+#include <asm/macro.h>
+
 	.global	lowlevel_init
 
 	.text
@@ -25,157 +27,83 @@
 
 lowlevel_init:
 
-	mov.l	WTCSR_A,r1
-	mov.l	WTCSR_D,r0
-	mov.w	r0,@r1
+	write16	WTCSR_A, WTCSR_D
 
-	mov.l	WTCNT_A,r1
-	mov.l	WTCNT_D,r0
-	mov.w	r0,@r1
+	write16	WTCNT_A, WTCNT_D
 
-	mov.l	FRQCR_A,r1
-	mov.l	FRQCR_D,r0
-	mov.w	r0,@r1
+	write16	FRQCR_A, FRQCR_D
 
-	mov.l	UCLKCR_A,r1
-	mov.l	UCLKCR_D,r0
-	mov.w	r0,@r1
+	write16	UCLKCR_A, UCLKCR_D
 
-	mov.l	CMNCR_A, r1
-	mov.l	CMNCR_D, r0
-	mov.l	r0, @r1
+	write32	CMNCR_A, CMNCR_D
 
-	mov.l	CS0BCR_A, r1
-	mov.l	CS0BCR_D, r0
-	mov.l	r0, @r1
+	write32	CMNCR_A, CMNCR_D
 
-	mov.l	CS2BCR_A, r1
-	mov.l	CS2BCR_D, r0
-	mov.l	r0, @r1
+	write32	CS0BCR_A, CS0BCR_D
 
-	mov.l	CS3BCR_A, r1
-	mov.l	CS3BCR_D, r0
-	mov.l	r0, @r1
+	write32	CS2BCR_A, CS2BCR_D
 
-	mov.l	CS4BCR_A, r1
-	mov.l	CS4BCR_D, r0
-	mov.l	r0, @r1
+	write32	CS3BCR_A, CS3BCR_D
 
-	mov.l	CS5ABCR_A, r1
-	mov.l	CS5ABCR_D, r0
-	mov.l	r0, @r1
+	write32	CS4BCR_A, CS4BCR_D
 
-	mov.l	CS5BBCR_A, r1
-	mov.l	CS5BBCR_D, r0
-	mov.l	r0, @r1
+	write32	CS5ABCR_A, CS5ABCR_D
 
-	mov.l	CS6ABCR_A, r1
-	mov.l	CS6ABCR_D, r0
-	mov.l	r0, @r1
+	write32	CS5BBCR_A, CS5BBCR_D
 
-	mov.l	CS6BBCR_A, r1
-	mov.l	CS6BBCR_D, r0
-	mov.l	r0, @r1
+	write32	CS6ABCR_A, CS6ABCR_D
 
-	mov.l	CS0WCR_A, r1
-	mov.l	CS0WCR_D, r0
-	mov.l	r0, @r1
+	write32	CS6BBCR_A, CS6BBCR_D
 
-	mov.l	CS2WCR_A, r1
-	mov.l	CS2WCR_D, r0
-	mov.l	r0, @r1
+	write32	CS0WCR_A, CS0WCR_D
 
-	mov.l	CS3WCR_A, r1
-	mov.l	CS3WCR_D, r0
-	mov.l	r0, @r1
+	write32	CS2WCR_A, CS2WCR_D
 
-	mov.l	CS4WCR_A, r1
-	mov.l	CS4WCR_D, r0
-	mov.l	r0, @r1
+	write32	CS3WCR_A, CS3WCR_D
 
-	mov.l	CS5AWCR_A, r1
-	mov.l	CS5AWCR_D, r0
-	mov.l	r0, @r1
+	write32	CS4WCR_A, CS4WCR_D
 
-	mov.l	CS5BWCR_A, r1
-	mov.l	CS5BWCR_D, r0
-	mov.l	r0, @r1
+	write32	CS5AWCR_A, CS5AWCR_D
 
-	mov.l	CS6AWCR_A, r1
-	mov.l	CS6AWCR_D, r0
-	mov.l	r0, @r1
+	write32	CS5BWCR_A, CS5BWCR_D
 
-	mov.l	CS6BWCR_A, r1
-	mov.l	CS6BWCR_D, r0
-	mov.l	r0, @r1
+	write32	CS6AWCR_A, CS6AWCR_D
 
-	mov.l	SDCR_A, r1
-	mov.l	SDCR_D1, r0
-	mov.l	r0, @r1
+	write32	CS6BWCR_A, CS6BWCR_D
 
-	mov.l	RTCSR_A, r1
-	mov.l	RTCSR_D, r0
-	mov.l	r0, @r1
+	write32	SDCR_A, SDCR_D1
 
-	mov.l	RTCNT_A, r1
-	mov.l	RTCNT_D, r0
-	mov.l	r0, @r1
+	write32	RTCSR_A, RTCSR_D
 
-	mov.l	RTCOR_A, r1
-	mov.l	RTCOR_D, r0
-	mov.l	r0, @r1
+	write32	RTCNT_A RTCNT_D
 
-	mov.l	SDCR_A, r1
-	mov.l	SDCR_D2, r0
-	mov.l	r0, @r1
+	write32	RTCOR_A, RTCOR_D
 
-	mov.l	SDMR3_A, r1
-	mov.l	SDMR3_D, r0
-	mov.w	r0, @r1
+	write32	SDCR_A, SDCR_D2
 
-	mov.l	PCCR_A, r1
-	mov.l	PCCR_D, r0
-	mov.w	r0, @r1
+	write16	SDMR3_A, SDMR3_D
 
-	mov.l	PDCR_A, r1
-	mov.l	PDCR_D, r0
-	mov.w	r0, @r1
+	write16	PCCR_A, PCCR_D
 
-	mov.l	PECR_A, r1
-	mov.l	PECR_D, r0
-	mov.w	r0, @r1
+	write16	PDCR_A, PDCR_D
 
-	mov.l	PGCR_A, r1
-	mov.l	PGCR_D, r0
-	mov.w	r0, @r1
+	write16	PECR_A, PECR_D
 
-	mov.l	PHCR_A, r1
-	mov.l	PHCR_D, r0
-	mov.w	r0, @r1
+	write16	PGCR_A, PGCR_D
 
-	mov.l	PPCR_A, r1
-	mov.l	PPCR_D, r0
-	mov.w	r0, @r1
+	write16	PHCR_A, PHCR_D
 
-	mov.l	PTCR_A, r1
-	mov.l	PTCR_D, r0
-	mov.w	r0, @r1
+	write16	PPCR_A, PPCR_D
 
-	mov.l	PVCR_A, r1
-	mov.l	PVCR_D, r0
-	mov.w	r0, @r1
+	write16	PTCR_A, PTCR_D
 
-	mov.l	PSELA_A, r1
-	mov.l	PSELA_D, r0
-	mov.w	r0, @r1
+	write16	PVCR_A, PVCR_D
 
-	mov.l	CCR_A, r1
-	mov.l	CCR_D, r0
-	mov.l	r0, @r1
+	write16	PSELA_A, PSELA_D
 
-	mov.l	LED_A, r1
-	mov.l	LED_D, r0
-	mov.b	r0, @r1
+	write32	CCR_A, CCR_D
+
+	write8	LED_A, LED_D
 
 	rts
 	 nop
diff --git a/board/ms7720se/u-boot.lds b/board/ms7720se/u-boot.lds
index 2156f6a..1f9b792 100644
--- a/board/ms7720se/u-boot.lds
+++ b/board/ms7720se/u-boot.lds
@@ -62,7 +62,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/ms7722se/u-boot.lds b/board/ms7722se/u-boot.lds
index 7dffe00..7b0fb67 100644
--- a/board/ms7722se/u-boot.lds
+++ b/board/ms7722se/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/ms7750se/u-boot.lds b/board/ms7750se/u-boot.lds
index 7dffe00..7b0fb67 100644
--- a/board/ms7750se/u-boot.lds
+++ b/board/ms7750se/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/muas3001/muas3001.c b/board/muas3001/muas3001.c
index 6b1e59f..8f83dd9 100644
--- a/board/muas3001/muas3001.c
+++ b/board/muas3001/muas3001.c
@@ -346,7 +346,9 @@
 	/* MAC Adresse */
 	nodeoffset = fdt_path_offset (blob, "/soc/cpm/ethernet");
 	if (nodeoffset >= 0) {
-		ret = fdt_setprop (blob, nodeoffset, "mac-address", bd->bi_enetaddr,
+		uchar ethaddr[6];
+		eth_getenv_enetaddr("ethaddr", ethaddr);
+		ret = fdt_setprop (blob, nodeoffset, "mac-address", ethaddr,
 					sizeof (uchar) * 6);
 	if (ret < 0)
 		printf ("ft_blob_update): cannot set /soc/cpm/ethernet/mac-address "
diff --git a/board/munices/u-boot.lds b/board/munices/u-boot.lds
index 0a1a6ad..5fe8707 100644
--- a/board/munices/u-boot.lds
+++ b/board/munices/u-boot.lds
@@ -57,9 +57,7 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/mx1ads/u-boot.lds b/board/mx1ads/u-boot.lds
index 5460c8c..1c710cb 100644
--- a/board/mx1ads/u-boot.lds
+++ b/board/mx1ads/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/mx1fs2/u-boot.lds b/board/mx1fs2/u-boot.lds
index c96e58a..d912d93 100644
--- a/board/mx1fs2/u-boot.lds
+++ b/board/mx1fs2/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/nc650/u-boot.lds b/board/nc650/u-boot.lds
index ca91ac4..dd040f0 100644
--- a/board/nc650/u-boot.lds
+++ b/board/nc650/u-boot.lds
@@ -61,10 +61,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netphone/u-boot.lds b/board/netphone/u-boot.lds
index 8836560..68fe165 100644
--- a/board/netphone/u-boot.lds
+++ b/board/netphone/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netstal/common/nm_bsp.c b/board/netstal/common/nm_bsp.c
index e38b706..237f4ed 100644
--- a/board/netstal/common/nm_bsp.c
+++ b/board/netstal/common/nm_bsp.c
@@ -83,40 +83,20 @@
 
 void common_misc_init_r(void)
 {
-	char *s = getenv(DEFAULT_ETH_ADDR);
-	char *e;
-	int i;
-	u32 serial = get_serial_number();
 	IPaddr_t ipaddr;
 	char *ipstring;
+	uchar ethaddr[6];
 
-	for (i = 0; i < 6; ++i) {
-		gd->bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-
-	if (gd->bd->bi_enetaddr[3] == 0 &&
-	    gd->bd->bi_enetaddr[4] == 0 &&
-	    gd->bd->bi_enetaddr[5] == 0) {
-		char ethaddr[22];
-
+	if (!eth_getenv_enetaddr(DEFAULT_ETH_ADDR, ethaddr)) {
 		/* Must be in sync with CONFIG_ETHADDR */
-		gd->bd->bi_enetaddr[0] = 0x00;
-		gd->bd->bi_enetaddr[1] = 0x60;
-		gd->bd->bi_enetaddr[2] = 0x13;
-		gd->bd->bi_enetaddr[3] = (serial >> 16) & 0xff;
-		gd->bd->bi_enetaddr[4] = (serial >>  8) & 0xff;
-		gd->bd->bi_enetaddr[5] = hcu_get_slot();
-		sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X%c",
-			gd->bd->bi_enetaddr[0], gd->bd->bi_enetaddr[1],
-			gd->bd->bi_enetaddr[2], gd->bd->bi_enetaddr[3],
-			gd->bd->bi_enetaddr[4],
-			gd->bd->bi_enetaddr[5],
-			0) ;
-		printf("%s: Setting eth %s serial 0x%x\n",  __FUNCTION__,
-		       ethaddr, serial);
-		setenv(DEFAULT_ETH_ADDR, ethaddr);
+		u32 serial = get_serial_number();
+		ethaddr[0] = 0x00;
+		ethaddr[1] = 0x60;
+		ethaddr[2] = 0x13;
+		ethaddr[3] = (serial >> 16) & 0xff;
+		ethaddr[4] = (serial >>  8) & 0xff;
+		ethaddr[5] = hcu_get_slot();
+		eth_setenv_enetaddr(DEFAULT_ETH_ADDR, ethaddr);
 	}
 
 	/* IP-Adress update */
diff --git a/board/netstal/hcu4/u-boot.lds b/board/netstal/hcu4/u-boot.lds
index d9abcd6..0c38ea2 100644
--- a/board/netstal/hcu4/u-boot.lds
+++ b/board/netstal/hcu4/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netstal/hcu5/u-boot.lds b/board/netstal/hcu5/u-boot.lds
index c3009bb..21a2be2 100644
--- a/board/netstal/hcu5/u-boot.lds
+++ b/board/netstal/hcu5/u-boot.lds
@@ -74,9 +74,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netstal/mcu25/u-boot.lds b/board/netstal/mcu25/u-boot.lds
index a00f570..b589956 100644
--- a/board/netstal/mcu25/u-boot.lds
+++ b/board/netstal/mcu25/u-boot.lds
@@ -72,10 +72,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netstar/eeprom.lds b/board/netstar/eeprom.lds
index f3be320..132476d 100644
--- a/board/netstar/eeprom.lds
+++ b/board/netstar/eeprom.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/netstar/u-boot.lds b/board/netstar/u-boot.lds
index 5823f62..6a5510a 100644
--- a/board/netstar/u-boot.lds
+++ b/board/netstar/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/netta/u-boot.lds b/board/netta/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/netta/u-boot.lds
+++ b/board/netta/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netta2/u-boot.lds b/board/netta2/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/netta2/u-boot.lds
+++ b/board/netta2/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/netvia/u-boot.lds b/board/netvia/u-boot.lds
index 6bc5768..8c48f1f 100644
--- a/board/netvia/u-boot.lds
+++ b/board/netvia/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ns9750dev/u-boot.lds b/board/ns9750dev/u-boot.lds
index c656701..b7fc19c 100644
--- a/board/ns9750dev/u-boot.lds
+++ b/board/ns9750dev/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/nx823/flash.c b/board/nx823/flash.c
index 194d841..336e704 100644
--- a/board/nx823/flash.c
+++ b/board/nx823/flash.c
@@ -27,8 +27,9 @@
 #include <common.h>
 #include <mpc8xx.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 flash_info_t	flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips	*/
-extern u_long  *my_sernum;		/* from nx823.c */
 
 /*-----------------------------------------------------------------------
  * Protection Flags:
@@ -346,7 +347,7 @@
 	if (addr >= CONFIG_SYS_FLASH_SN_SECTOR && addr < CONFIG_SYS_FLASH_SN_BASE)
 	{
 		u_long dest = CONFIG_SYS_FLASH_SN_BASE;
-		u_short *sn = (u_short *)my_sernum;
+		u_short *sn = (u_short *)gd->bd->bi_sernum;
 
 		printf("(saving sernum)");
 		for (i=0; i<4; i++)
diff --git a/board/nx823/nx823.c b/board/nx823/nx823.c
index df9aaab..6ec29dc 100644
--- a/board/nx823/nx823.c
+++ b/board/nx823/nx823.c
@@ -360,39 +360,30 @@
 	return (get_ram_size (base, maxsize));
 }
 
-u_long *my_sernum;
-
 int misc_init_r (void)
 {
+	int i;
 	char tmp[50];
-	u_char *e = gd->bd->bi_enetaddr;
+	uchar ethaddr[6];
+	bd_t *bd = gd->bd;
+	ulong my_sernum = bd->bi_sernum;
 
-	/* save serial numbre from flash (uniquely programmed) */
-	my_sernum = malloc (8);
-	memcpy (my_sernum, gd->bd->bi_sernum, 8);
+	/* load unique serial number */
+	for (i = 0; i < 8; ++i)
+		bd->bi_sernum[i] = *(u_char *) (CONFIG_SYS_FLASH_SN_BASE + i);
 
 	/* save env variables according to sernum */
 	sprintf (tmp, "%08lx%08lx", my_sernum[0], my_sernum[1]);
 	setenv ("serial#", tmp);
 
-	sprintf (tmp, "%02x:%02x:%02x:%02x:%02x:%02x", e[0], e[1], e[2], e[3],
-		 e[4], e[5]);
-	setenv ("ethaddr", tmp);
-	return (0);
-}
-
-void load_sernum_ethaddr (void)
-{
-	int i;
-	bd_t *bd = gd->bd;
-
-	for (i = 0; i < 8; i++) {
-		bd->bi_sernum[i] = *(u_char *) (CONFIG_SYS_FLASH_SN_BASE + i);
+	if (!eth_getenv_enetaddr("ethaddr", ethaddr)) {
+		ethaddr[0] = 0x10;
+		ethaddr[1] = 0x20;
+		ethaddr[2] = 0x30;
+		ethaddr[3] = bd->bi_sernum[1] << 4 | bd->bi_sernum[2];
+		ethaddr[4] = bd->bi_sernum[5];
+		ethaddr[5] = bd->bi_sernum[6];
 	}
-	bd->bi_enetaddr[0] = 0x10;
-	bd->bi_enetaddr[1] = 0x20;
-	bd->bi_enetaddr[2] = 0x30;
-	bd->bi_enetaddr[3] = bd->bi_sernum[1] << 4 | bd->bi_sernum[2];
-	bd->bi_enetaddr[4] = bd->bi_sernum[5];
-	bd->bi_enetaddr[5] = bd->bi_sernum[6];
+
+	return 0;
 }
diff --git a/board/nx823/u-boot.lds b/board/nx823/u-boot.lds
index 759b412..ee74eb9 100644
--- a/board/nx823/u-boot.lds
+++ b/board/nx823/u-boot.lds
@@ -63,10 +63,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/omap1510inn/u-boot.lds b/board/omap1510inn/u-boot.lds
index 1c70fcd..13b3643 100644
--- a/board/omap1510inn/u-boot.lds
+++ b/board/omap1510inn/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/omap1610inn/u-boot.lds b/board/omap1610inn/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/omap1610inn/u-boot.lds
+++ b/board/omap1610inn/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/omap2420h4/u-boot.lds b/board/omap2420h4/u-boot.lds
index 89e627b..46535dd 100644
--- a/board/omap2420h4/u-boot.lds
+++ b/board/omap2420h4/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/omap3/beagle/beagle.c b/board/omap3/beagle/beagle.c
index 7377058..8d60651 100644
--- a/board/omap3/beagle/beagle.c
+++ b/board/omap3/beagle/beagle.c
@@ -116,6 +116,8 @@
 
 	beagle_identify();
 
+	dieid_num_r();
+
 	return 0;
 }
 
diff --git a/board/omap3/beagle/u-boot.lds b/board/omap3/beagle/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/beagle/u-boot.lds
+++ b/board/omap3/beagle/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	.ARM.extab	: { *(.ARM.extab* .gnu.linkonce.armextab.*) }
 	__exidx_start = .;
diff --git a/board/omap3/evm/evm.c b/board/omap3/evm/evm.c
index b406312..3a27c8f 100644
--- a/board/omap3/evm/evm.c
+++ b/board/omap3/evm/evm.c
@@ -68,6 +68,8 @@
 	setup_net_chip();
 #endif
 
+	dieid_num_r();
+
 	return 0;
 }
 
diff --git a/board/omap3/evm/u-boot.lds b/board/omap3/evm/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/evm/u-boot.lds
+++ b/board/omap3/evm/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	.ARM.extab	: { *(.ARM.extab* .gnu.linkonce.armextab.*) }
 	__exidx_start = .;
diff --git a/board/omap3/overo/overo.c b/board/omap3/overo/overo.c
index 48375ad..37bf350 100644
--- a/board/omap3/overo/overo.c
+++ b/board/omap3/overo/overo.c
@@ -60,6 +60,8 @@
 {
 	power_init_r();
 
+	dieid_num_r();
+
 	return 0;
 }
 
diff --git a/board/omap3/overo/u-boot.lds b/board/omap3/overo/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/overo/u-boot.lds
+++ b/board/omap3/overo/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	.ARM.extab	: { *(.ARM.extab* .gnu.linkonce.armextab.*) }
 	__exidx_start = .;
diff --git a/board/omap3/pandora/pandora.c b/board/omap3/pandora/pandora.c
index 3f9de99..dfd51ec 100644
--- a/board/omap3/pandora/pandora.c
+++ b/board/omap3/pandora/pandora.c
@@ -77,6 +77,8 @@
 	writel(GPIO28, &gpio5_base->setdataout);
 	writel(GPIO4, &gpio6_base->setdataout);
 
+	dieid_num_r();
+
 	return 0;
 }
 
diff --git a/board/omap3/pandora/u-boot.lds b/board/omap3/pandora/u-boot.lds
index 69d8ac9..66a8925 100644
--- a/board/omap3/pandora/u-boot.lds
+++ b/board/omap3/pandora/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	.ARM.extab	: { *(.ARM.extab* .gnu.linkonce.armextab.*) }
 	__exidx_start = .;
diff --git a/board/omap3/zoom1/u-boot.lds b/board/omap3/zoom1/u-boot.lds
index 01047c3..0eb318b 100644
--- a/board/omap3/zoom1/u-boot.lds
+++ b/board/omap3/zoom1/u-boot.lds
@@ -39,7 +39,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	.ARM.extab	: { *(.ARM.extab* .gnu.linkonce.armextab.*) }
 	__exidx_start = .;
diff --git a/board/omap3/zoom1/zoom1.c b/board/omap3/zoom1/zoom1.c
index d67abf7..702f732 100644
--- a/board/omap3/zoom1/zoom1.c
+++ b/board/omap3/zoom1/zoom1.c
@@ -61,6 +61,7 @@
 int misc_init_r(void)
 {
 	power_init_r();
+	dieid_num_r();
 	return 0;
 }
 
diff --git a/board/omap5912osk/u-boot.lds b/board/omap5912osk/u-boot.lds
index 0bf6eff..3132b9a 100644
--- a/board/omap5912osk/u-boot.lds
+++ b/board/omap5912osk/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/omap730p2/u-boot.lds b/board/omap730p2/u-boot.lds
index d86eb36..4d50f2c 100644
--- a/board/omap730p2/u-boot.lds
+++ b/board/omap730p2/u-boot.lds
@@ -34,7 +34,7 @@
 	  *(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/pb1x00/u-boot.lds b/board/pb1x00/u-boot.lds
index da20de1..9a6cd1b 100644
--- a/board/pb1x00/u-boot.lds
+++ b/board/pb1x00/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/pcippc2/u-boot.lds b/board/pcippc2/u-boot.lds
index 5395108..4bb582d 100644
--- a/board/pcippc2/u-boot.lds
+++ b/board/pcippc2/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/pcs440ep/pcs440ep.c b/board/pcs440ep/pcs440ep.c
index 5fd3291..2727214 100644
--- a/board/pcs440ep/pcs440ep.c
+++ b/board/pcs440ep/pcs440ep.c
@@ -182,14 +182,21 @@
 }
 
 #define EEPROM_LEN	256
-void load_sernum_ethaddr (void)
+static void load_ethaddr(void)
 {
+	int	ok_ethaddr, ok_eth1addr;
 	int	ret;
 	char	buf[EEPROM_LEN];
 	char	mac[32];
 	char	*use_eeprom;
 	u16	checksumcrc16 = 0;
 
+	/* If the env is sane, then nothing for us to do */
+	ok_ethaddr = eth_getenv_enetaddr("ethaddr", buf);
+	ok_eth1addr = eth_getenv_enetaddr("eth1addr", buf);
+	if (ok_ethaddr && ok_eth1addr)
+		return;
+
 	/* read the MACs from EEprom */
 	status_led_set (0, STATUS_LED_ON);
 	status_led_set (1, STATUS_LED_ON);
@@ -207,22 +214,10 @@
 			printf("%s: EEPROM Checksum not OK\n", __FUNCTION__);
 		} else {
 			/* get the MACs */
-			sprintf (mac, "%02x:%02x:%02x:%02x:%02x:%02x",
-				buf[3],
-				buf[4],
-				buf[5],
-				buf[6],
-				buf[7],
-				buf[8]);
-			setenv ("ethaddr", (char *) mac);
-			sprintf (mac, "%02x:%02x:%02x:%02x:%02x:%02x",
-				buf[9],
-				buf[10],
-				buf[11],
-				buf[12],
-				buf[13],
-				buf[14]);
-			setenv ("eth1addr", (char *) mac);
+			if (!ok_ethaddr)
+				eth_setenv_enetaddr("ethaddr", &buf[3]);
+			if (!ok_eth1addr)
+				eth_setenv_enetaddr("eth1addr", &buf[9]);
 			return;
 		}
 	}
@@ -446,6 +441,8 @@
 	uint pbcr;
 	int size_val = 0;
 
+	load_ethaddr();
+
 	/* Re-do sizing to get full correct info */
 	mtdcr(ebccfga, pb0cr);
 	pbcr = mfdcr(ebccfgd);
diff --git a/board/pcs440ep/u-boot.lds b/board/pcs440ep/u-boot.lds
index 6b7dd21..a4c537e 100644
--- a/board/pcs440ep/u-boot.lds
+++ b/board/pcs440ep/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/pleb2/u-boot.lds b/board/pleb2/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/pleb2/u-boot.lds
+++ b/board/pleb2/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/pm854/u-boot.lds b/board/pm854/u-boot.lds
index 18cb27a..45aaadc 100644
--- a/board/pm854/u-boot.lds
+++ b/board/pm854/u-boot.lds
@@ -81,10 +81,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/pm856/u-boot.lds b/board/pm856/u-boot.lds
index e9c6a12..1dce2ab 100644
--- a/board/pm856/u-boot.lds
+++ b/board/pm856/u-boot.lds
@@ -81,10 +81,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/pn62/pn62.c b/board/pn62/pn62.c
index 1b545bf..53d7e57 100644
--- a/board/pn62/pn62.c
+++ b/board/pn62/pn62.c
@@ -30,7 +30,7 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 static int get_serial_number (char *string, int size);
-static int get_mac_address (int id, u8 * mac, char *string, int size);
+static void get_mac_address(int id, u8 *mac);
 
 #ifdef CONFIG_SHOW_BOOT_PROGRESS
 void show_boot_progress (int phase)
@@ -138,18 +138,16 @@
 	}
 	show_startup_phase (9);
 
-	if (getenv ("ethaddr") == NULL &&
-		get_mac_address (0, mac, str, sizeof (str)) > 0) {
-		setenv ("ethaddr", str);
-		memcpy (gd->bd->bi_enetaddr, mac, 6);
+	if (!eth_getenv_enetaddr("ethaddr", mac)) {
+		get_mac_address(0, mac);
+		eth_setenv_enetaddr("ethaddr", mac);
 	}
 	show_startup_phase (10);
 
 #ifdef CONFIG_HAS_ETH1
-	if (getenv ("eth1addr") == NULL &&
-		get_mac_address (1, mac, str, sizeof (str)) > 0) {
-		setenv ("eth1addr", str);
-		memcpy (gd->bd->bi_enet1addr, mac, 6);
+	if (!eth_getenv_enetaddr("eth1addr", mac)) {
+		get_mac_address(1, mac);
+		eth_setenv_enetaddr("eth1addr", mac);
 	}
 #endif /* CONFIG_HAS_ETH1 */
 	show_startup_phase (11);
@@ -177,15 +175,9 @@
 	return i;
 }
 
-static int get_mac_address (int id, u8 * mac, char *string, int size)
+static void get_mac_address(int id, u8 *mac)
 {
-	if (size < 6 * 3)
-		return -1;
-
 	i2155x_read_vpd (I2155X_VPD_MAC0_START + 6 * id, 6, mac);
-	return sprintf (string, "%02x:%02x:%02x:%02x:%02x:%02x",
-				mac[0], mac[1], mac[2],
-				mac[3], mac[4], mac[5]);
 }
 
 int board_eth_init(bd_t *bis)
diff --git a/board/ppmc7xx/u-boot.lds b/board/ppmc7xx/u-boot.lds
index ca2e300..b0da216 100644
--- a/board/ppmc7xx/u-boot.lds
+++ b/board/ppmc7xx/u-boot.lds
@@ -70,9 +70,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/prodrive/alpr/u-boot.lds b/board/prodrive/alpr/u-boot.lds
index 33b03af..e7c5fe6 100644
--- a/board/prodrive/alpr/u-boot.lds
+++ b/board/prodrive/alpr/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/prodrive/p3mx/u-boot.lds b/board/prodrive/p3mx/u-boot.lds
index ff2d8b7..632921a 100644
--- a/board/prodrive/p3mx/u-boot.lds
+++ b/board/prodrive/p3mx/u-boot.lds
@@ -70,10 +70,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/prodrive/p3p440/u-boot.lds b/board/prodrive/p3p440/u-boot.lds
index 17cfde8..9327970 100644
--- a/board/prodrive/p3p440/u-boot.lds
+++ b/board/prodrive/p3p440/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/prodrive/pdnb3/u-boot.lds b/board/prodrive/pdnb3/u-boot.lds
index dc59119..6324436 100644
--- a/board/prodrive/pdnb3/u-boot.lds
+++ b/board/prodrive/pdnb3/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/psyent/pci5441/u-boot.lds b/board/psyent/pci5441/u-boot.lds
index d3b7c31..b2d88a5 100644
--- a/board/psyent/pci5441/u-boot.lds
+++ b/board/psyent/pci5441/u-boot.lds
@@ -34,8 +34,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/board/psyent/pk1c20/u-boot.lds b/board/psyent/pk1c20/u-boot.lds
index d3b7c31..b2d88a5 100644
--- a/board/psyent/pk1c20/u-boot.lds
+++ b/board/psyent/pk1c20/u-boot.lds
@@ -34,8 +34,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/board/purple/u-boot.lds b/board/purple/u-boot.lds
index bf1394b..04a641a 100644
--- a/board/purple/u-boot.lds
+++ b/board/purple/u-boot.lds
@@ -48,7 +48,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/pxa255_idp/u-boot.lds b/board/pxa255_idp/u-boot.lds
index 96ac25c..fb4358b 100644
--- a/board/pxa255_idp/u-boot.lds
+++ b/board/pxa255_idp/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/qemu-mips/u-boot.lds b/board/qemu-mips/u-boot.lds
index 03bcb09..ad058ca 100644
--- a/board/qemu-mips/u-boot.lds
+++ b/board/qemu-mips/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/quad100hd/u-boot.lds b/board/quad100hd/u-boot.lds
index 7cf4d4f..24d31a1 100644
--- a/board/quad100hd/u-boot.lds
+++ b/board/quad100hd/u-boot.lds
@@ -68,9 +68,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/quantum/u-boot.lds b/board/quantum/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/quantum/u-boot.lds
+++ b/board/quantum/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/r360mpi/u-boot.lds b/board/r360mpi/u-boot.lds
index db28544..61d4b11 100644
--- a/board/r360mpi/u-boot.lds
+++ b/board/r360mpi/u-boot.lds
@@ -71,10 +71,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/rbc823/u-boot.lds b/board/rbc823/u-boot.lds
index 63bd21b..552f15d 100644
--- a/board/rbc823/u-boot.lds
+++ b/board/rbc823/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/renesas/MigoR/u-boot.lds b/board/renesas/MigoR/u-boot.lds
index f9c1eff..c004b83 100644
--- a/board/renesas/MigoR/u-boot.lds
+++ b/board/renesas/MigoR/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/ap325rxa/lowlevel_init.S b/board/renesas/ap325rxa/lowlevel_init.S
index b32f491..0daf25a 100644
--- a/board/renesas/ap325rxa/lowlevel_init.S
+++ b/board/renesas/ap325rxa/lowlevel_init.S
@@ -173,7 +173,7 @@
 CS0WCR_D:	.long	0x00000480
 CS4WCR_D:	.long	0x00000480
 CS5AWCR_D:	.long	0x00000380
-CS5BWCR_D:	.long	0x00000600
+CS5BWCR_D:	.long	0x00000080
 CS6AWCR_D:	.long	0x00000300
 CS6BWCR_D:	.long	0x00000540
 
diff --git a/board/renesas/ap325rxa/u-boot.lds b/board/renesas/ap325rxa/u-boot.lds
index e9f8dc0..94bacca 100644
--- a/board/renesas/ap325rxa/u-boot.lds
+++ b/board/renesas/ap325rxa/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/r2dplus/u-boot.lds b/board/renesas/r2dplus/u-boot.lds
index 040e530..e1c15b0 100644
--- a/board/renesas/r2dplus/u-boot.lds
+++ b/board/renesas/r2dplus/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/r7780mp/u-boot.lds b/board/renesas/r7780mp/u-boot.lds
index eaa05d0..f32d0b8 100644
--- a/board/renesas/r7780mp/u-boot.lds
+++ b/board/renesas/r7780mp/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/rsk7203/u-boot.lds b/board/renesas/rsk7203/u-boot.lds
index 63e5b97..bd4a550 100644
--- a/board/renesas/rsk7203/u-boot.lds
+++ b/board/renesas/rsk7203/u-boot.lds
@@ -56,7 +56,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/sh7763rdp/u-boot.lds b/board/renesas/sh7763rdp/u-boot.lds
index 7177416..b1a967d 100644
--- a/board/renesas/sh7763rdp/u-boot.lds
+++ b/board/renesas/sh7763rdp/u-boot.lds
@@ -59,7 +59,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/sh7785lcr/config.mk b/board/renesas/sh7785lcr/config.mk
index 20807df..66d35cb 100644
--- a/board/renesas/sh7785lcr/config.mk
+++ b/board/renesas/sh7785lcr/config.mk
@@ -22,4 +22,8 @@
 #
 # NOTE: Must match value used in u-boot.lds (in this directory).
 #
+sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
+
+ifndef TEXT_BASE
 TEXT_BASE = 0x0ff80000
+endif
diff --git a/board/renesas/sh7785lcr/lowlevel_init.S b/board/renesas/sh7785lcr/lowlevel_init.S
index f5ebeb9..97920df 100644
--- a/board/renesas/sh7785lcr/lowlevel_init.S
+++ b/board/renesas/sh7785lcr/lowlevel_init.S
@@ -130,6 +130,46 @@
 	write32	CS6WCR_A,	CS_SD_WCR_D
 
 lbsc_end:
+#if defined(CONFIG_SH_32BIT)
+	/*------- set PMB -------*/
+	write32	PASCR_A,	PASCR_29BIT_D
+	write32	MMUCR_A,	MMUCR_D
+
+	/*****************************************************************
+	 * ent	virt		phys		v	sz	c	wt
+	 * 0	0xa0000000	0x00000000	1	64M	0	0
+	 * 1	0xa4000000	0x04000000	1	16M	0	0
+	 * 2	0xa6000000	0x08000000	1	16M	0	0
+	 * 9	0x88000000	0x48000000	1	128M	1	1
+	 * 10	0x90000000	0x50000000	1	128M	1	1
+	 * 11	0x98000000	0x58000000	1	128M	1	1
+	 * 13	0xa8000000	0x48000000	1	128M	0	0
+	 * 14	0xb0000000	0x50000000	1	128M	0	0
+	 * 15	0xb8000000	0x58000000	1	128M	0	0
+	 */
+	write32	PMB_ADDR_FLASH_A,	PMB_ADDR_FLASH_D
+	write32	PMB_DATA_FLASH_A,	PMB_DATA_FLASH_D
+	write32	PMB_ADDR_CPLD_A,	PMB_ADDR_CPLD_D
+	write32	PMB_DATA_CPLD_A,	PMB_DATA_CPLD_D
+	write32	PMB_ADDR_USB_A,		PMB_ADDR_USB_D
+	write32	PMB_DATA_USB_A,		PMB_DATA_USB_D
+	write32	PMB_ADDR_DDR_C1_A,	PMB_ADDR_DDR_C1_D
+	write32	PMB_DATA_DDR_C1_A,	PMB_DATA_DDR_C1_D
+	write32	PMB_ADDR_DDR_C2_A,	PMB_ADDR_DDR_C2_D
+	write32	PMB_DATA_DDR_C2_A,	PMB_DATA_DDR_C2_D
+	write32	PMB_ADDR_DDR_C3_A,	PMB_ADDR_DDR_C3_D
+	write32	PMB_DATA_DDR_C3_A,	PMB_DATA_DDR_C3_D
+	write32	PMB_ADDR_DDR_N1_A,	PMB_ADDR_DDR_N1_D
+	write32	PMB_DATA_DDR_N1_A,	PMB_DATA_DDR_N1_D
+	write32	PMB_ADDR_DDR_N2_A,	PMB_ADDR_DDR_N2_D
+	write32	PMB_DATA_DDR_N2_A,	PMB_DATA_DDR_N2_D
+	write32	PMB_ADDR_DDR_N3_A,	PMB_ADDR_DDR_N3_D
+	write32	PMB_DATA_DDR_N3_A,	PMB_DATA_DDR_N3_D
+
+	write32	PASCR_A,	PASCR_INIT
+	mov.l	DUMMY_ADDR, r0
+	icbi	@r0
+#endif
 
 	write32	CCR_A,	CCR_D
 
@@ -140,7 +180,11 @@
 
 /*------- LBSC -------*/
 MMSELR_A:	.long	0xfc400020
+#if defined(CONFIG_SH_32BIT)
+MMSELR_D:	.long	0xa5a50005
+#else
 MMSELR_D:	.long	0xa5a50002
+#endif
 
 /*------- DBSC2 -------*/
 #define DBSC2_BASE	0xfe800000
@@ -287,5 +331,55 @@
 CS_I2C_BCR_D:	.long	0x11111100
 CS_I2C_WCR_D:	.long	0x00000003
 
+#if defined(CONFIG_SH_32BIT)
+/*------- set PMB -------*/
+PMB_ADDR_FLASH_A:	.long	PMB_ADDR_BASE(0)
+PMB_ADDR_CPLD_A:	.long	PMB_ADDR_BASE(1)
+PMB_ADDR_USB_A:		.long	PMB_ADDR_BASE(2)
+PMB_ADDR_DDR_C1_A:	.long	PMB_ADDR_BASE(9)
+PMB_ADDR_DDR_C2_A:	.long	PMB_ADDR_BASE(10)
+PMB_ADDR_DDR_C3_A:	.long	PMB_ADDR_BASE(11)
+PMB_ADDR_DDR_N1_A:	.long	PMB_ADDR_BASE(13)
+PMB_ADDR_DDR_N2_A:	.long	PMB_ADDR_BASE(14)
+PMB_ADDR_DDR_N3_A:	.long	PMB_ADDR_BASE(15)
+
+PMB_ADDR_FLASH_D:	.long	mk_pmb_addr_val(0xa0)
+PMB_ADDR_CPLD_D:	.long	mk_pmb_addr_val(0xa4)
+PMB_ADDR_USB_D:		.long	mk_pmb_addr_val(0xa6)
+PMB_ADDR_DDR_C1_D:	.long	mk_pmb_addr_val(0x88)
+PMB_ADDR_DDR_C2_D:	.long	mk_pmb_addr_val(0x90)
+PMB_ADDR_DDR_C3_D:	.long	mk_pmb_addr_val(0x98)
+PMB_ADDR_DDR_N1_D:	.long	mk_pmb_addr_val(0xa8)
+PMB_ADDR_DDR_N2_D:	.long	mk_pmb_addr_val(0xb0)
+PMB_ADDR_DDR_N3_D:	.long	mk_pmb_addr_val(0xb8)
+
+PMB_DATA_FLASH_A:	.long	PMB_DATA_BASE(0)
+PMB_DATA_CPLD_A:	.long	PMB_DATA_BASE(1)
+PMB_DATA_USB_A:		.long	PMB_DATA_BASE(2)
+PMB_DATA_DDR_C1_A:	.long	PMB_DATA_BASE(9)
+PMB_DATA_DDR_C2_A:	.long	PMB_DATA_BASE(10)
+PMB_DATA_DDR_C3_A:	.long	PMB_DATA_BASE(11)
+PMB_DATA_DDR_N1_A:	.long	PMB_DATA_BASE(13)
+PMB_DATA_DDR_N2_A:	.long	PMB_DATA_BASE(14)
+PMB_DATA_DDR_N3_A:	.long	PMB_DATA_BASE(15)
+
+/*						ppn   ub v s1 s0  c  wt */
+PMB_DATA_FLASH_D:	.long	mk_pmb_data_val(0x00, 1, 1, 0, 1, 0, 1)
+PMB_DATA_CPLD_D:	.long	mk_pmb_data_val(0x04, 1, 1, 0, 0, 0, 1)
+PMB_DATA_USB_D:		.long	mk_pmb_data_val(0x08, 1, 1, 0, 0, 0, 1)
+PMB_DATA_DDR_C1_D:	.long	mk_pmb_data_val(0x48, 0, 1, 1, 0, 1, 1)
+PMB_DATA_DDR_C2_D:	.long	mk_pmb_data_val(0x50, 0, 1, 1, 0, 1, 1)
+PMB_DATA_DDR_C3_D:	.long	mk_pmb_data_val(0x58, 0, 1, 1, 0, 1, 1)
+PMB_DATA_DDR_N1_D:	.long	mk_pmb_data_val(0x48, 1, 1, 1, 0, 0, 1)
+PMB_DATA_DDR_N2_D:	.long	mk_pmb_data_val(0x50, 1, 1, 1, 0, 0, 1)
+PMB_DATA_DDR_N3_D:	.long	mk_pmb_data_val(0x58, 1, 1, 1, 0, 0, 1)
+
+DUMMY_ADDR:	.long	0xa0000000
+PASCR_29BIT_D:	.long	0x00000000
+PASCR_INIT:	.long	0x80000080	/* check booting mode */
+MMUCR_A:	.long	0xff000010
+MMUCR_D:	.long	0x00000004	/* clear ITLB */
+#endif	/* CONFIG_SH_32BIT */
+
 CCR_A:		.long	0xff00001c
 CCR_D:		.long	0x0000090b
diff --git a/board/renesas/sh7785lcr/sh7785lcr.c b/board/renesas/sh7785lcr/sh7785lcr.c
index 786c758..6bdf3c0 100644
--- a/board/renesas/sh7785lcr/sh7785lcr.c
+++ b/board/renesas/sh7785lcr/sh7785lcr.c
@@ -54,3 +54,34 @@
 {
 	return pci_eth_init(bis);
 }
+
+#if defined(CONFIG_SH_32BIT)
+int do_pmb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	/* clear ITLB */
+	writel(0x00000004, 0xff000010);
+
+	/* delete PMB for peripheral */
+	writel(0, PMB_ADDR_BASE(0));
+	writel(0, PMB_DATA_BASE(0));
+	writel(0, PMB_ADDR_BASE(1));
+	writel(0, PMB_DATA_BASE(1));
+	writel(0, PMB_ADDR_BASE(2));
+	writel(0, PMB_DATA_BASE(2));
+
+	/* add PMB for SDRAM(0x40000000 - 0x47ffffff) */
+	writel(mk_pmb_addr_val(0x80), PMB_ADDR_BASE(8));
+	writel(mk_pmb_data_val(0x40, 0, 1, 1, 0, 1, 1), PMB_DATA_BASE(8));
+	writel(mk_pmb_addr_val(0xa0), PMB_ADDR_BASE(12));
+	writel(mk_pmb_data_val(0x40, 1, 1, 1, 0, 0, 1), PMB_DATA_BASE(12));
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	pmb,	1,	1,	do_pmb,
+	"pmb     - PMB setting\n",
+	"\n"
+	"    - PMB setting for all SDRAM mapping\n"
+);
+#endif
diff --git a/board/renesas/sh7785lcr/u-boot.lds b/board/renesas/sh7785lcr/u-boot.lds
index 231769f..255ab37 100644
--- a/board/renesas/sh7785lcr/u-boot.lds
+++ b/board/renesas/sh7785lcr/u-boot.lds
@@ -1,7 +1,7 @@
 /*
  * Copyrigth (c) 2007
  * Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
- * Copyrigth (c) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Copyrigth (c) 2008-2009 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -28,7 +28,7 @@
 
 SECTIONS
 {
-	. = 0x08000000 + (128 * 1024 * 1024) - (512 * 1024);
+	. = 0x88000000 + (128 * 1024 * 1024) - (512 * 1024);
 
 	PROVIDE (reloc_dst = .);
 
@@ -50,7 +50,7 @@
 	PROVIDE (_ecode = .);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		. = ALIGN(4);
 	}
 	PROVIDE (_etext = .);
diff --git a/board/renesas/sh7785lcr/u-boot_29bit b/board/renesas/sh7785lcr/u-boot_29bit
new file mode 100644
index 0000000..231769f
--- /dev/null
+++ b/board/renesas/sh7785lcr/u-boot_29bit
@@ -0,0 +1,96 @@
+/*
+ * Copyrigth (c) 2007
+ * Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * Copyrigth (c) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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
+ */
+
+OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+OUTPUT_ARCH(sh)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x08000000 + (128 * 1024 * 1024) - (512 * 1024);
+
+	PROVIDE (reloc_dst = .);
+
+	PROVIDE (_ftext = .);
+	PROVIDE (_fcode = .);
+	PROVIDE (_start = .);
+
+	.text :
+	{
+		cpu/sh4/start.o		(.text)
+		. = ALIGN(8192);
+		common/env_embedded.o	(.ppcenv)
+		. = ALIGN(8192);
+		common/env_embedded.o	(.ppcenvr)
+		. = ALIGN(8192);
+		*(.text)
+		. = ALIGN(4);
+	} =0xFF
+	PROVIDE (_ecode = .);
+	.rodata :
+	{
+		*(.rodata)
+		. = ALIGN(4);
+	}
+	PROVIDE (_etext = .);
+
+
+	PROVIDE (_fdata = .);
+	.data :
+	{
+		*(.data)
+		. = ALIGN(4);
+	}
+	PROVIDE (_edata = .);
+
+	PROVIDE (_fgot = .);
+	.got :
+	{
+		*(.got)
+		. = ALIGN(4);
+	}
+	PROVIDE (_egot = .);
+
+	PROVIDE (__u_boot_cmd_start = .);
+	.u_boot_cmd :
+	{
+		*(.u_boot_cmd)
+		. = ALIGN(4);
+	}
+	PROVIDE (__u_boot_cmd_end = .);
+
+	PROVIDE (reloc_dst_end = .);
+	/* _reloc_dst_end = .; */
+
+	PROVIDE (bss_start = .);
+	PROVIDE (__bss_start = .);
+	.bss :
+	{
+		*(.bss)
+		. = ALIGN(4);
+	}
+	PROVIDE (bss_end = .);
+
+	PROVIDE (_end = .);
+}
diff --git a/board/renesas/sh7785lcr/u-boot_32bit b/board/renesas/sh7785lcr/u-boot_32bit
new file mode 100644
index 0000000..446fb93
--- /dev/null
+++ b/board/renesas/sh7785lcr/u-boot_32bit
@@ -0,0 +1,96 @@
+/*
+ * Copyrigth (c) 2007
+ * Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * Copyrigth (c) 2008-2009 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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
+ */
+
+OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+OUTPUT_ARCH(sh)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x88000000 + (128 * 1024 * 1024) - (512 * 1024);
+
+	PROVIDE (reloc_dst = .);
+
+	PROVIDE (_ftext = .);
+	PROVIDE (_fcode = .);
+	PROVIDE (_start = .);
+
+	.text :
+	{
+		cpu/sh4/start.o		(.text)
+		. = ALIGN(8192);
+		common/env_embedded.o	(.ppcenv)
+		. = ALIGN(8192);
+		common/env_embedded.o	(.ppcenvr)
+		. = ALIGN(8192);
+		*(.text)
+		. = ALIGN(4);
+	} =0xFF
+	PROVIDE (_ecode = .);
+	.rodata :
+	{
+		*(.rodata)
+		. = ALIGN(4);
+	}
+	PROVIDE (_etext = .);
+
+
+	PROVIDE (_fdata = .);
+	.data :
+	{
+		*(.data)
+		. = ALIGN(4);
+	}
+	PROVIDE (_edata = .);
+
+	PROVIDE (_fgot = .);
+	.got :
+	{
+		*(.got)
+		. = ALIGN(4);
+	}
+	PROVIDE (_egot = .);
+
+	PROVIDE (__u_boot_cmd_start = .);
+	.u_boot_cmd :
+	{
+		*(.u_boot_cmd)
+		. = ALIGN(4);
+	}
+	PROVIDE (__u_boot_cmd_end = .);
+
+	PROVIDE (reloc_dst_end = .);
+	/* _reloc_dst_end = .; */
+
+	PROVIDE (bss_start = .);
+	PROVIDE (__bss_start = .);
+	.bss :
+	{
+		*(.bss)
+		. = ALIGN(4);
+	}
+	PROVIDE (bss_end = .);
+
+	PROVIDE (_end = .);
+}
diff --git a/board/rmu/u-boot.lds b/board/rmu/u-boot.lds
index 55cb5ec..faa1c6c 100644
--- a/board/rmu/u-boot.lds
+++ b/board/rmu/u-boot.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/rsdproto/u-boot.lds b/board/rsdproto/u-boot.lds
index b2bd576..771f7de 100644
--- a/board/rsdproto/u-boot.lds
+++ b/board/rsdproto/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/samsung/smdk2400/u-boot.lds b/board/samsung/smdk2400/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/samsung/smdk2400/u-boot.lds
+++ b/board/samsung/smdk2400/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/samsung/smdk2410/u-boot.lds b/board/samsung/smdk2410/u-boot.lds
index 987b07d..33363c2 100644
--- a/board/samsung/smdk2410/u-boot.lds
+++ b/board/samsung/smdk2410/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/samsung/smdk6400/u-boot-nand.lds b/board/samsung/smdk6400/u-boot-nand.lds
index bd6b24f..b868fdd 100644
--- a/board/samsung/smdk6400/u-boot-nand.lds
+++ b/board/samsung/smdk6400/u-boot-nand.lds
@@ -40,7 +40,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/sandburst/common/sb_common.c b/board/sandburst/common/sb_common.c
index f6ea16f..b8160c8 100644
--- a/board/sandburst/common/sb_common.c
+++ b/board/sandburst/common/sb_common.c
@@ -394,9 +394,8 @@
  *  mgmt mac address.
  *
  ************************************************************************/
-static int macaddr_idx = 0;
 
-void board_get_enetaddr (uchar * enet)
+void board_get_enetaddr(int macaddr_idx, uchar *enet)
 {
 	int i;
 	unsigned short tmp;
@@ -419,7 +418,6 @@
 		tmp += 31;
 		memcpy(&enet[4], &tmp, 2);
 
-		macaddr_idx++;
 	} else {
 		enet[0] = 0x02;
 		enet[1] = 0x00;
diff --git a/board/sandburst/common/sb_common.h b/board/sandburst/common/sb_common.h
index 888e4f0..e652ba8 100644
--- a/board/sandburst/common/sb_common.h
+++ b/board/sandburst/common/sb_common.h
@@ -72,5 +72,6 @@
 int sbcommon_secondary_present(void);
 unsigned short sbcommon_get_serial_number(void);
 void sbcommon_fans(void);
+void board_get_enetaddr(int macaddr_idx, uchar *enet);
 
 #endif /* __SBCOMMON_H__ */
diff --git a/board/sandburst/karef/karef.c b/board/sandburst/karef/karef.c
index 9b94af5..55310d7 100644
--- a/board/sandburst/karef/karef.c
+++ b/board/sandburst/karef/karef.c
@@ -354,6 +354,7 @@
 {
 	unsigned short sernum;
 	char envstr[255];
+	uchar enetaddr[6];
 	KAREF_FPGA_REGS_ST *karef_ps;
 	OFEM_FPGA_REGS_ST *ofem_ps;
 
@@ -408,6 +409,34 @@
 		printf("fakeled is set. use 'setenv fakeled ; setenv bootdelay 5 ; saveenv' to recover\n");
 	}
 
+#ifdef CONFIG_HAS_ETH0
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(0, enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH1
+	if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+		board_get_enetaddr(1, enetaddr);
+		eth_putenv_enetaddr("eth1addr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+	if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+		board_get_enetaddr(2, enetaddr);
+		eth_putenv_enetaddr("eth2addr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH3
+	if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+		board_get_enetaddr(3, enetaddr);
+		eth_putenv_enetaddr("eth3addr", enetaddr);
+	}
+#endif
+
 	return (0);
 }
 
diff --git a/board/sandburst/karef/u-boot.lds b/board/sandburst/karef/u-boot.lds
index 6223f4e..f509100 100644
--- a/board/sandburst/karef/u-boot.lds
+++ b/board/sandburst/karef/u-boot.lds
@@ -91,10 +91,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sandburst/metrobox/metrobox.c b/board/sandburst/metrobox/metrobox.c
index ec4c451..8bb8c02 100644
--- a/board/sandburst/metrobox/metrobox.c
+++ b/board/sandburst/metrobox/metrobox.c
@@ -321,6 +321,7 @@
 {
 	unsigned short sernum;
 	char envstr[255];
+	uchar enetaddr[6];
 	unsigned char opto_rev;
 	OPTO_FPGA_REGS_ST *opto_ps;
 
@@ -379,6 +380,34 @@
 		}
 	}
 
+#ifdef CONFIG_HAS_ETH0
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(0, enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH1
+	if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+		board_get_enetaddr(1, enetaddr);
+		eth_putenv_enetaddr("eth1addr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+	if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+		board_get_enetaddr(2, enetaddr);
+		eth_putenv_enetaddr("eth2addr", enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH3
+	if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+		board_get_enetaddr(3, enetaddr);
+		eth_putenv_enetaddr("eth3addr", enetaddr);
+	}
+#endif
+
 	return (0);
 }
 
diff --git a/board/sandburst/metrobox/u-boot.lds b/board/sandburst/metrobox/u-boot.lds
index 54e18e0..f1bc4a0 100644
--- a/board/sandburst/metrobox/u-boot.lds
+++ b/board/sandburst/metrobox/u-boot.lds
@@ -91,10 +91,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sbc2410x/u-boot.lds b/board/sbc2410x/u-boot.lds
index d0666ac..3eae0e2 100644
--- a/board/sbc2410x/u-boot.lds
+++ b/board/sbc2410x/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/sbc405/u-boot.lds b/board/sbc405/u-boot.lds
index d6f34c9..d9410fa 100644
--- a/board/sbc405/u-boot.lds
+++ b/board/sbc405/u-boot.lds
@@ -83,10 +83,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sbc8548/u-boot.lds b/board/sbc8548/u-boot.lds
index 70d11f2..a54a001 100644
--- a/board/sbc8548/u-boot.lds
+++ b/board/sbc8548/u-boot.lds
@@ -80,10 +80,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sbc8560/u-boot.lds b/board/sbc8560/u-boot.lds
index 759ee82..8c12ba4 100644
--- a/board/sbc8560/u-boot.lds
+++ b/board/sbc8560/u-boot.lds
@@ -86,10 +86,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sbc8641d/u-boot.lds b/board/sbc8641d/u-boot.lds
index adfa816..f156d4f 100644
--- a/board/sbc8641d/u-boot.lds
+++ b/board/sbc8641d/u-boot.lds
@@ -68,10 +68,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sc3/u-boot.lds b/board/sc3/u-boot.lds
index d729f2e..75174e1 100644
--- a/board/sc3/u-boot.lds
+++ b/board/sc3/u-boot.lds
@@ -84,10 +84,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sc520_cdp/sc520_cdp.c b/board/sc520_cdp/sc520_cdp.c
index 779f957..830ec37 100644
--- a/board/sc520_cdp/sc520_cdp.c
+++ b/board/sc520_cdp/sc520_cdp.c
@@ -27,7 +27,7 @@
 #include <asm/io.h>
 #include <asm/pci.h>
 #include <asm/ic/sc520.h>
-#include <asm/ic/ali512x.h>
+#include <ali512x.h>
 #include <spi.h>
 #include <netdev.h>
 
@@ -575,10 +575,10 @@
 
 void spi_init_f(void)
 {
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
 	spi_eeprom_probe(1);
 #endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
 	mw_eeprom_probe(2);
 #endif
 }
@@ -595,13 +595,13 @@
 		offset |= addr[i];
 	}
 
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
 	res = spi_eeprom_read(1, offset, buffer, len);
 #endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
 	res = mw_eeprom_read(2, offset, buffer, len);
 #endif
-#if !defined(CONFIG_SC520_CDP_USE_SPI) && !defined(CONFIG_SC520_CDP_USE_MW)
+#if !defined(CONFIG_SYS_SC520_CDP_USE_SPI) && !defined(CONFIG_SYS_SC520_CDP_USE_MW)
 	res = 0;
 #endif
 	return res;
@@ -619,13 +619,13 @@
 		offset |= addr[i];
 	}
 
-#ifdef CONFIG_SC520_CDP_USE_SPI
+#ifdef CONFIG_SYS_SC520_CDP_USE_SPI
 	res = spi_eeprom_write(1, offset, buffer, len);
 #endif
-#ifdef CONFIG_SC520_CDP_USE_MW
+#ifdef CONFIG_SYS_SC520_CDP_USE_MW
 	res = mw_eeprom_write(2, offset, buffer, len);
 #endif
-#if !defined(CONFIG_SC520_CDP_USE_SPI) && !defined(CONFIG_SC520_CDP_USE_MW)
+#if !defined(CONFIG_SYS_SC520_CDP_USE_SPI) && !defined(CONFIG_SYS_SC520_CDP_USE_MW)
 	res = 0;
 #endif
 	return res;
diff --git a/board/sc520_cdp/u-boot.lds b/board/sc520_cdp/u-boot.lds
index 0f5011a..df437c7 100644
--- a/board/sc520_cdp/u-boot.lds
+++ b/board/sc520_cdp/u-boot.lds
@@ -31,7 +31,7 @@
 	.text  : { *(.text); }
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) *(.rodata.str1.1) *(.rodata.str1.32) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = 0x400000;	                    /* Ram data segment to use */
 	_i386boot_romdata_dest = ABSOLUTE(.);
diff --git a/board/sc520_spunk/u-boot.lds b/board/sc520_spunk/u-boot.lds
index d2436bc..efb570b 100644
--- a/board/sc520_spunk/u-boot.lds
+++ b/board/sc520_spunk/u-boot.lds
@@ -32,7 +32,7 @@
 	.text  : { *(.text); }
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = 0x400000;	                    /* Ram data segment to use */
 	_i386boot_romdata_dest = ABSOLUTE(.);
diff --git a/board/scb9328/u-boot.lds b/board/scb9328/u-boot.lds
index c96e58a..d912d93 100644
--- a/board/scb9328/u-boot.lds
+++ b/board/scb9328/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/shannon/u-boot.lds b/board/shannon/u-boot.lds
index fce2533..13b7bb7 100644
--- a/board/shannon/u-boot.lds
+++ b/board/shannon/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/siemens/CCM/u-boot.lds b/board/siemens/CCM/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/siemens/CCM/u-boot.lds
+++ b/board/siemens/CCM/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/siemens/IAD210/IAD210.c b/board/siemens/IAD210/IAD210.c
index e21bb24..67e5c8f 100644
--- a/board/siemens/IAD210/IAD210.c
+++ b/board/siemens/IAD210/IAD210.c
@@ -258,7 +258,7 @@
 	return 0;
 }
 
-void board_get_enetaddr (uchar * addr)
+static void board_get_enetaddr(uchar *addr)
 {
 	int i;
 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
@@ -284,3 +284,15 @@
 
 	cpm->cp_rccr = rccrtmp;
 }
+
+int misc_init_r(void)
+{
+	uchar enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+
+	return 0;
+}
diff --git a/board/siemens/IAD210/u-boot.lds b/board/siemens/IAD210/u-boot.lds
index 47677c6..12a53ba 100644
--- a/board/siemens/IAD210/u-boot.lds
+++ b/board/siemens/IAD210/u-boot.lds
@@ -71,10 +71,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/siemens/SMN42/u-boot.lds b/board/siemens/SMN42/u-boot.lds
index 49d18f7..cb5a3ba 100644
--- a/board/siemens/SMN42/u-boot.lds
+++ b/board/siemens/SMN42/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/siemens/pcu_e/u-boot.lds b/board/siemens/pcu_e/u-boot.lds
index 319cc7b..9e46f9d 100644
--- a/board/siemens/pcu_e/u-boot.lds
+++ b/board/siemens/pcu_e/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sixnet/sixnet.c b/board/sixnet/sixnet.c
index 3ed581e..4fcd84b 100644
--- a/board/sixnet/sixnet.c
+++ b/board/sixnet/sixnet.c
@@ -264,6 +264,7 @@
 	char* e;
 	int reg;
 	bd_t *bd = gd->bd;
+	uchar enetaddr[6];
 
 	memctl->memc_or2 = NVRAM_OR_PRELIM;
 	memctl->memc_br2 = NVRAM_BR_VALUE;
@@ -315,13 +316,9 @@
 	 * is present it gets a unique address, otherwise it
 	 * shares the FEC address.
 	 */
-	s = getenv("eth1addr");
-	if (s == NULL)
-		s = getenv("ethaddr");
-	for (reg=0; reg<6; ++reg) {
-		bd->bi_enet1addr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e+1 : e;
+	if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+		eth_setenv_enetaddr("eth1addr", enetaddr);
 	}
 
 	return (0);
diff --git a/board/sixnet/u-boot.lds b/board/sixnet/u-boot.lds
index efa4244..bde981b 100644
--- a/board/sixnet/u-boot.lds
+++ b/board/sixnet/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/snmc/qs850/u-boot.lds b/board/snmc/qs850/u-boot.lds
index 6fa9b81..7de0de8 100644
--- a/board/snmc/qs850/u-boot.lds
+++ b/board/snmc/qs850/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/snmc/qs860t/u-boot.lds b/board/snmc/qs860t/u-boot.lds
index 6fa9b81..7de0de8 100644
--- a/board/snmc/qs860t/u-boot.lds
+++ b/board/snmc/qs860t/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/socrates/u-boot.lds b/board/socrates/u-boot.lds
index 499f531..9241b5c 100644
--- a/board/socrates/u-boot.lds
+++ b/board/socrates/u-boot.lds
@@ -84,10 +84,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini	     : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/spc1920/u-boot.lds b/board/spc1920/u-boot.lds
index 5af36c9..4e221bc 100644
--- a/board/spc1920/u-boot.lds
+++ b/board/spc1920/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/spd8xx/u-boot.lds b/board/spd8xx/u-boot.lds
index 7d94421..a06d8c6 100644
--- a/board/spd8xx/u-boot.lds
+++ b/board/spd8xx/u-boot.lds
@@ -62,10 +62,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/ssv/adnpesc1/u-boot.lds b/board/ssv/adnpesc1/u-boot.lds
index be77952..98ee8f8 100644
--- a/board/ssv/adnpesc1/u-boot.lds
+++ b/board/ssv/adnpesc1/u-boot.lds
@@ -38,7 +38,7 @@
 	. = ALIGN(4);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	__rodata_end = .;
 
diff --git a/board/st/nmdk8815/u-boot.lds b/board/st/nmdk8815/u-boot.lds
index 6d6481b..c2adbab 100644
--- a/board/st/nmdk8815/u-boot.lds
+++ b/board/st/nmdk8815/u-boot.lds
@@ -34,7 +34,7 @@
 		*(.text)
 	}
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 	. = ALIGN(4);
 	.data : { *(.data) }
 	. = ALIGN(4);
diff --git a/board/stxgp3/u-boot.lds b/board/stxgp3/u-boot.lds
index cdcb39a..182e940 100644
--- a/board/stxgp3/u-boot.lds
+++ b/board/stxgp3/u-boot.lds
@@ -88,10 +88,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/stxssa/u-boot.lds b/board/stxssa/u-boot.lds
index 6ee8d60..750ddb3 100644
--- a/board/stxssa/u-boot.lds
+++ b/board/stxssa/u-boot.lds
@@ -88,10 +88,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/stxxtc/u-boot.lds b/board/stxxtc/u-boot.lds
index 4966f4d..14201ac 100644
--- a/board/stxxtc/u-boot.lds
+++ b/board/stxxtc/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/svm_sc8xx/u-boot.lds b/board/svm_sc8xx/u-boot.lds
index ceab4d2..11a819a 100644
--- a/board/svm_sc8xx/u-boot.lds
+++ b/board/svm_sc8xx/u-boot.lds
@@ -76,10 +76,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/sx1/u-boot.lds b/board/sx1/u-boot.lds
index 9a9dd21..af0b4d0 100644
--- a/board/sx1/u-boot.lds
+++ b/board/sx1/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/tb0229/u-boot.lds b/board/tb0229/u-boot.lds
index 086d74d..56d7c25 100644
--- a/board/tb0229/u-boot.lds
+++ b/board/tb0229/u-boot.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/board/tqc/tqm85xx/u-boot.lds b/board/tqc/tqm85xx/u-boot.lds
index b1637a5..91c8952 100644
--- a/board/tqc/tqm85xx/u-boot.lds
+++ b/board/tqc/tqm85xx/u-boot.lds
@@ -81,10 +81,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini	     : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/tqc/tqm8xx/tqm8xx.c b/board/tqc/tqm8xx/tqm8xx.c
index e065d69..f92c598 100644
--- a/board/tqc/tqm8xx/tqm8xx.c
+++ b/board/tqc/tqm8xx/tqm8xx.c
@@ -449,11 +449,14 @@
 
 
 #ifdef CONFIG_MISC_INIT_R
+extern void load_sernum_ethaddr(void);
 int misc_init_r (void)
 {
 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
 	volatile memctl8xx_t *memctl = &immap->im_memctl;
 
+	load_sernum_ethaddr();
+
 #ifdef	CONFIG_SYS_OR_TIMING_FLASH_AT_50MHZ
 	int scy, trlx, flash_or_timing, clk_diff;
 
diff --git a/board/tqc/tqm8xx/u-boot.lds b/board/tqc/tqm8xx/u-boot.lds
index 5c9b26c..19c1541 100644
--- a/board/tqc/tqm8xx/u-boot.lds
+++ b/board/tqc/tqm8xx/u-boot.lds
@@ -75,10 +75,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/trab/u-boot.lds b/board/trab/u-boot.lds
index bd13d13..912a2bb 100644
--- a/board/trab/u-boot.lds
+++ b/board/trab/u-boot.lds
@@ -45,7 +45,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/trizepsiv/u-boot.lds b/board/trizepsiv/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/trizepsiv/u-boot.lds
+++ b/board/trizepsiv/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/uc100/u-boot.lds b/board/uc100/u-boot.lds
index 66a57e6..1450d37 100644
--- a/board/uc100/u-boot.lds
+++ b/board/uc100/u-boot.lds
@@ -75,10 +75,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/v37/u-boot.lds b/board/v37/u-boot.lds
index bf78a32..d24289c 100644
--- a/board/v37/u-boot.lds
+++ b/board/v37/u-boot.lds
@@ -78,10 +78,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/v38b/v38b.c b/board/v38b/v38b.c
index d774295..9e7c1d7 100644
--- a/board/v38b/v38b.c
+++ b/board/v38b/v38b.c
@@ -223,6 +223,18 @@
 	return 0;
 }
 
+extern void board_get_enetaddr(uchar *enetaddr);
+int misc_init_r(void)
+{
+	uchar enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(enetaddr);
+		eth_putenv_enetaddr("ethaddr", enetaddr);
+	}
+
+	return 0;
+}
 
 #if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_RESET)
 void init_ide_reset(void)
diff --git a/board/voiceblue/eeprom.lds b/board/voiceblue/eeprom.lds
index f3be320..132476d 100644
--- a/board/voiceblue/eeprom.lds
+++ b/board/voiceblue/eeprom.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/voiceblue/u-boot.lds b/board/voiceblue/u-boot.lds
index 8bf1990..97fcef3 100644
--- a/board/voiceblue/u-boot.lds
+++ b/board/voiceblue/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/w7o/u-boot.lds b/board/w7o/u-boot.lds
index 80e960b..191a179 100644
--- a/board/w7o/u-boot.lds
+++ b/board/w7o/u-boot.lds
@@ -67,10 +67,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/wepep250/u-boot.lds b/board/wepep250/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/wepep250/u-boot.lds
+++ b/board/wepep250/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/westel/amx860/u-boot.lds b/board/westel/amx860/u-boot.lds
index ef9a251..61650a8 100644
--- a/board/westel/amx860/u-boot.lds
+++ b/board/westel/amx860/u-boot.lds
@@ -73,10 +73,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xaeniax/u-boot.lds b/board/xaeniax/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/xaeniax/u-boot.lds
+++ b/board/xaeniax/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/xes/xpedite5200/u-boot.lds b/board/xes/xpedite5200/u-boot.lds
index bd952d2..af4f016 100644
--- a/board/xes/xpedite5200/u-boot.lds
+++ b/board/xes/xpedite5200/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xes/xpedite5370/u-boot.lds b/board/xes/xpedite5370/u-boot.lds
index cb39912..f117d9b 100644
--- a/board/xes/xpedite5370/u-boot.lds
+++ b/board/xes/xpedite5370/u-boot.lds
@@ -65,10 +65,8 @@
     PROVIDE (etext = .);
     .rodata    :
    {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   } :text
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/microblaze-generic/u-boot.lds b/board/xilinx/microblaze-generic/u-boot.lds
index b38f648..5a08680 100644
--- a/board/xilinx/microblaze-generic/u-boot.lds
+++ b/board/xilinx/microblaze-generic/u-boot.lds
@@ -38,7 +38,7 @@
 	.rodata ALIGN(0x4):
 	{
 		__rodata_start = .;
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 		__rodata_end = .;
 	}
 
diff --git a/board/xilinx/ml300/u-boot.lds b/board/xilinx/ml300/u-boot.lds
index 913ff6e..fa60e6b 100644
--- a/board/xilinx/ml300/u-boot.lds
+++ b/board/xilinx/ml300/u-boot.lds
@@ -81,10 +81,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/ppc405-generic/u-boot-ram.lds b/board/xilinx/ppc405-generic/u-boot-ram.lds
index 6bbd3bd..908d84b 100644
--- a/board/xilinx/ppc405-generic/u-boot-ram.lds
+++ b/board/xilinx/ppc405-generic/u-boot-ram.lds
@@ -64,10 +64,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/ppc405-generic/u-boot-rom.lds b/board/xilinx/ppc405-generic/u-boot-rom.lds
index d094006..592976a 100644
--- a/board/xilinx/ppc405-generic/u-boot-rom.lds
+++ b/board/xilinx/ppc405-generic/u-boot-rom.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/ppc440-generic/u-boot-ram.lds b/board/xilinx/ppc440-generic/u-boot-ram.lds
index d65f3de..3ab9a31 100644
--- a/board/xilinx/ppc440-generic/u-boot-ram.lds
+++ b/board/xilinx/ppc440-generic/u-boot-ram.lds
@@ -64,10 +64,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/ppc440-generic/u-boot-rom.lds b/board/xilinx/ppc440-generic/u-boot-rom.lds
index 8b468ee..7420280 100644
--- a/board/xilinx/ppc440-generic/u-boot-rom.lds
+++ b/board/xilinx/ppc440-generic/u-boot-rom.lds
@@ -74,10 +74,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xilinx/xilinx_enet/emac_adapter.c b/board/xilinx/xilinx_enet/emac_adapter.c
index 0b100d2..35bcc4d 100644
--- a/board/xilinx/xilinx_enet/emac_adapter.c
+++ b/board/xilinx/xilinx_enet/emac_adapter.c
@@ -74,6 +74,7 @@
 {
 	u32 Options;
 	XStatus Result;
+	uchar enetaddr[6];
 
 #ifdef DEBUG
 	printf("EMAC Initialization Started\n\r");
@@ -87,11 +88,14 @@
 	/* make sure the Emac is stopped before it is started */
 	(void) XEmac_Stop(&Emac);
 
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
 #ifdef CONFIG_ENV_IS_NOWHERE
-	memcpy(bis->bi_enetaddr, EMACAddr, 6);
+		memcpy(enetaddr, EMACAddr, 6);
+		eth_setenv_enetaddr("ethaddr", enetaddr);
 #endif
+	}
 
-	Result = XEmac_SetMacAddress(&Emac, bis->bi_enetaddr);
+	Result = XEmac_SetMacAddress(&Emac, enetaddr);
 	if (Result != XST_SUCCESS) {
 		return 0;
 	}
diff --git a/board/xm250/u-boot.lds b/board/xm250/u-boot.lds
index 1e88820..8af5001 100644
--- a/board/xm250/u-boot.lds
+++ b/board/xm250/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/xpedite1k/u-boot.lds b/board/xpedite1k/u-boot.lds
index 13c52b9..c8f9646 100644
--- a/board/xpedite1k/u-boot.lds
+++ b/board/xpedite1k/u-boot.lds
@@ -89,10 +89,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xpedite1k/u-boot.lds.debug b/board/xpedite1k/u-boot.lds.debug
index 116c2ba..5824cd9 100644
--- a/board/xpedite1k/u-boot.lds.debug
+++ b/board/xpedite1k/u-boot.lds.debug
@@ -78,10 +78,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/xpedite1k/xpedite1k.c b/board/xpedite1k/xpedite1k.c
index 58bcfaf..cd1a368 100644
--- a/board/xpedite1k/xpedite1k.c
+++ b/board/xpedite1k/xpedite1k.c
@@ -335,29 +335,58 @@
  * board_get_enetaddr -- Read the MAC Addresses in the I2C EEPROM
  *-----------------------------------------------------------------------------
  */
-static int enetaddr_num = 0;
-void board_get_enetaddr (uchar * enet)
+static int read_i2c;
+static void board_get_enetaddr(uchar *enet)
 {
 	int i;
 	unsigned char buff[0x100], *cp;
 
+	if (read_i2c)
+		return;
+
 	/* Initialize I2C					*/
 	i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
 
 	/* Read 256 bytes in EEPROM				*/
 	i2c_read (0x50, 0, 1, buff, 0x100);
 
-	if (enetaddr_num == 0) {
-		cp = &buff[0xF4];
-		enetaddr_num = 1;
-	}
-	else
-		cp = &buff[0xFA];
-
+	cp = &buff[0xF4];
 	for (i = 0; i < 6; i++,cp++)
 		enet[i] = *cp;
 
-	printf ("MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n",
-		enet[0], enet[1], enet[2], enet[3], enet[4], enet[5]);
+	printf("MAC address = %pM\n", enet);
+	read_i2c = 1;
+}
 
+int misc_init_r(void)
+{
+	uchar enetaddr[6], i2c_enetaddr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		board_get_enetaddr(i2c_enetaddr);
+		eth_putenv_enetaddr("ethaddr", i2c_enetaddr);
+	}
+
+#ifdef CONFIG_HAS_ETH1
+	if (!eth_getenv_enetaddr("eth1addr", enetaddr)) {
+		board_get_enetaddr(i2c_enetaddr);
+		eth_putenv_enetaddr("eth1addr", i2c_enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH2
+	if (!eth_getenv_enetaddr("eth2addr", enetaddr)) {
+		board_get_enetaddr(i2c_enetaddr);
+		eth_putenv_enetaddr("eth2addr", i2c_enetaddr);
+	}
+#endif
+
+#ifdef CONFIG_HAS_ETH3
+	if (!eth_getenv_enetaddr("eth3addr", enetaddr)) {
+		board_get_enetaddr(i2c_enetaddr);
+		eth_putenv_enetaddr("eth3addr", i2c_enetaddr);
+	}
+#endif
+
+	return 0;
 }
diff --git a/board/xsengine/u-boot.lds b/board/xsengine/u-boot.lds
index 1e88820..8af5001 100644
--- a/board/xsengine/u-boot.lds
+++ b/board/xsengine/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/board/zeus/u-boot.lds b/board/zeus/u-boot.lds
index 877573e..f86570d 100644
--- a/board/zeus/u-boot.lds
+++ b/board/zeus/u-boot.lds
@@ -67,9 +67,7 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/board/zylonite/u-boot.lds b/board/zylonite/u-boot.lds
index 7cf9fdf..a077bc5 100644
--- a/board/zylonite/u-boot.lds
+++ b/board/zylonite/u-boot.lds
@@ -36,7 +36,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/common/Makefile b/common/Makefile
index f13cd11..23171ca 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -110,6 +110,7 @@
 COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
 COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
 COBJS-$(CONFIG_MP) += cmd_mp.o
+COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
 COBJS-y += cmd_nand.o
 COBJS-$(CONFIG_CMD_NET) += cmd_net.o
 COBJS-$(CONFIG_CMD_ONENAND) += cmd_onenand.o
@@ -129,6 +130,7 @@
 COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o
 COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
 COBJS-$(CONFIG_CMD_UBI) += cmd_ubi.o
+COBJS-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o
 COBJS-$(CONFIG_CMD_UNIVERSE) += cmd_universe.o
 ifdef CONFIG_CMD_USB
 COBJS-y += cmd_usb.o
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c
index b2d6f84..700314b 100644
--- a/common/cmd_bdinfo.c
+++ b/common/cmd_bdinfo.c
@@ -26,12 +26,13 @@
  */
 #include <common.h>
 #include <command.h>
-#include <net.h>		/* for print_IPaddr */
 
 DECLARE_GLOBAL_DATA_PTR;
 
 static void print_num(const char *, ulong);
 
+static void print_eth(int idx);
+
 #ifndef CONFIG_ARM	/* PowerPC and other */
 static void print_lnum(const char *, u64);
 
@@ -40,7 +41,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 	char buf[32];
 
@@ -91,51 +91,28 @@
 	print_str ("pevfreq",	    strmhz(buf, bd->bi_pevfreq));
 #endif
 
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-
+	print_eth(0);
 #if defined(CONFIG_HAS_ETH1)
-	puts ("\neth1addr    =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);
-	}
+	print_eth(1);
 #endif
-
 #if defined(CONFIG_HAS_ETH2)
-       puts ("\neth2addr    =");
-       for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet2addr[i]);
-	}
+	print_eth(2);
 #endif
-
 #if defined(CONFIG_HAS_ETH3)
-       puts ("\neth3addr    =");
-       for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet3addr[i]);
-	}
+	print_eth(3);
 #endif
-
 #if defined(CONFIG_HAS_ETH4)
-       puts ("\neth4addr    =");
-       for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet4addr[i]);
-	}
+	print_eth(4);
 #endif
-
 #if defined(CONFIG_HAS_ETH5)
-       puts ("\neth5addr    =");
-       for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet5addr[i]);
-	}
+	print_eth(5);
 #endif
 
 #ifdef CONFIG_HERMES
 	print_str ("ethspeed",	    strmhz(buf, bd->bi_ethspeed));
 #endif
-	puts ("\nIP addr     = ");	print_IPaddr (bd->bi_ip_addr);
-	printf ("\nbaudrate    = %6ld bps\n", bd->bi_baudrate   );
+	printf ("IP addr     = %pI4\n", &bd->bi_ip_addr);
+	printf ("baudrate    = %6ld bps\n", bd->bi_baudrate   );
 	return 0;
 }
 
@@ -143,7 +120,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 
 	print_num ("memstart",		(ulong)bd->bi_memstart);
@@ -152,13 +128,9 @@
 	print_num ("flashsize",		(ulong)bd->bi_flashsize);
 	print_num ("flashoffset",	(ulong)bd->bi_flashoffset);
 
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts ("\nip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
-	printf ("\nbaudrate    = %ld bps\n", bd->bi_baudrate);
+	print_eth(0);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
+	printf ("baudrate    = %ld bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -167,9 +139,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-#if defined(CONFIG_CMD_NET)
-	int i;
-#endif
 	bd_t *bd = gd->bd;
 
 	print_num ("mem start",		(ulong)bd->bi_memstart);
@@ -184,15 +153,11 @@
 #endif
 
 #if defined(CONFIG_CMD_NET)
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts ("\nip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
+	print_eth(0);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
 
-	printf ("\nbaudrate    = %ld bps\n", bd->bi_baudrate);
+	printf ("baudrate    = %ld bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -200,7 +165,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 	print_num ("mem start      ",	(ulong)bd->bi_memstart);
 	print_lnum ("mem size       ",	(u64)bd->bi_memsize);
@@ -212,14 +176,10 @@
 	print_num ("sram size      ",	(ulong)bd->bi_sramsize);
 #endif
 #if defined(CONFIG_CMD_NET)
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts ("\nip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
+	print_eth(0);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
-	printf ("\nbaudrate    = %ld bps\n", (ulong)bd->bi_baudrate);
+	printf ("baudrate    = %ld bps\n", (ulong)bd->bi_baudrate);
 	return 0;
 }
 
@@ -227,9 +187,6 @@
 int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 {
 	bd_t *bd = gd->bd;
-#if defined(CONFIG_CMD_NET)
-	int i;
-#endif
 
 #ifdef DEBUG
 	print_num("bd address             ", (ulong) bd);
@@ -251,14 +208,10 @@
 	       CONFIG_SYS_GBL_DATA_SIZE);
 
 #if defined(CONFIG_CMD_NET)
-	puts("ethaddr                =");
-	for (i = 0; i < 6; ++i) {
-		printf("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts("\nIP addr                = ");
-	print_IPaddr(bd->bi_ip_addr);
+	print_eth(0);
+	printf("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
-	printf("\nbaudrate               = %6ld bps\n", bd->bi_baudrate);
+	printf("baudrate               = %6ld bps\n", bd->bi_baudrate);
 	return 0;
 }
 
@@ -267,7 +220,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 	char buf[32];
 
@@ -294,36 +246,20 @@
 	print_str ("vcofreq",		strmhz(buf, bd->bi_vcofreq));
 #endif
 #if defined(CONFIG_CMD_NET)
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-
+	print_eth(0);
 #if defined(CONFIG_HAS_ETH1)
-	puts ("\neth1addr    =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);
-	}
+	print_eth(1);
 #endif
-
 #if defined(CONFIG_HAS_ETH2)
-	puts ("\neth2addr    =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet2addr[i]);
-	}
+	print_eth(2);
 #endif
-
 #if defined(CONFIG_HAS_ETH3)
-	puts ("\neth3addr    =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet3addr[i]);
-	}
+	print_eth(3);
 #endif
 
-	puts ("\nip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
-	printf ("\nbaudrate    = %ld bps\n", bd->bi_baudrate);
+	printf ("baudrate    = %ld bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -333,7 +269,6 @@
 
 int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 	char buf[32];
 
@@ -351,12 +286,9 @@
 	print_num("flashsize",   (ulong)bd->bi_flashsize);
 	print_num("flashoffset", (ulong)bd->bi_flashoffset);
 
-	puts("ethaddr     =");
-	for (i = 0; i < 6; ++i)
-		printf("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	puts("\nip_addr     = ");
-	print_IPaddr(bd->bi_ip_addr);
-	printf("\nbaudrate    = %d bps\n", bd->bi_baudrate);
+	print_eth(0);
+	printf("ip_addr     = %pI4\n", &bd->bi_ip_addr);
+	printf("baudrate    = %d bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -365,7 +297,6 @@
 
 int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
-	int i;
 	bd_t *bd = gd->bd;
 
 	print_num ("boot_params",	(ulong)bd->bi_boot_params);
@@ -375,13 +306,9 @@
 	print_num ("flashsize",		(ulong)bd->bi_flashsize);
 	print_num ("flashoffset",	(ulong)bd->bi_flashoffset);
 
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts ("\nip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
-	printf ("\nbaudrate    = %d bps\n", bd->bi_baudrate);
+	print_eth(0);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
+	printf ("baudrate    = %d bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -405,16 +332,10 @@
 	}
 
 #if defined(CONFIG_CMD_NET)
-	puts ("ethaddr     =");
-	for (i=0; i<6; ++i) {
-		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
-	}
-	puts  ( "\n"
-		"ip_addr     = ");
-	print_IPaddr (bd->bi_ip_addr);
+	print_eth(0);
+	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
-	printf ("\n"
-		"baudrate    = %d bps\n", bd->bi_baudrate);
+	printf ("baudrate    = %d bps\n", bd->bi_baudrate);
 
 	return 0;
 }
@@ -426,6 +347,19 @@
 	printf ("%-12s= 0x%08lX\n", name, value);
 }
 
+static void print_eth(int idx)
+{
+	char name[10], *val;
+	if (idx)
+		sprintf(name, "eth%iaddr", idx);
+	else
+		strcpy(name, "ethaddr");
+	val = getenv(name);
+	if (!val)
+		val = "(not set)";
+	printf("%-12s= %s\n", name, val);
+}
+
 #ifndef CONFIG_ARM
 static void print_lnum(const char *name, u64 value)
 {
diff --git a/common/cmd_elf.c b/common/cmd_elf.c
index 19e1249..4a3fff1 100644
--- a/common/cmd_elf.c
+++ b/common/cmd_elf.c
@@ -131,10 +131,12 @@
 
 #if defined(CONFIG_WALNUT)
 	tmp = (char *) CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
-	memcpy ((char *) tmp, (char *) &gd->bd->bi_enetaddr[3], 3);
+	eth_getenv_enetaddr("ethaddr", build_buf);
+	memcpy(tmp, &build_buf[3], 3);
 #elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
 	tmp = (char *) CONFIG_SYS_VXWORKS_MAC_PTR;
-	memcpy ((char *) tmp, (char *) &gd->bd->bi_enetaddr[0], 6);
+	eth_getenv_enetaddr("ethaddr", build_buf);
+	memcpy(tmp, build_buf, 6);
 #else
 	puts ("## Ethernet MAC address not copied to NV RAM\n");
 #endif
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
index 510654e..f1f3517 100644
--- a/common/cmd_flash.c
+++ b/common/cmd_flash.c
@@ -31,12 +31,12 @@
 #include <dataflash.h>
 #endif
 
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 #include <jffs2/jffs2.h>
 
 /* parition handling routines */
 int mtdparts_init(void);
-int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
 int find_dev_and_part(const char *id, struct mtd_device **dev,
 		u8 *part_num, struct part_info **part);
 #endif
@@ -325,7 +325,7 @@
 	flash_info_t *info;
 	ulong bank, addr_first, addr_last;
 	int n, sect_first, sect_last;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	struct mtd_device *dev;
 	struct part_info *part;
 	u8 dev_type, dev_num, pnum;
@@ -357,9 +357,9 @@
 		return rcode;
 	}
 
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	/* erase <part-id> - erase partition */
-	if ((argc == 2) && (id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
+	if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
 		mtdparts_init();
 		if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
 			if (dev->id->type == MTD_DEV_TYPE_NOR) {
@@ -470,7 +470,7 @@
 #endif /* CONFIG_SYS_NO_FLASH */
 	ulong addr_first, addr_last;
 	int p;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	struct mtd_device *dev;
 	struct part_info *part;
 	u8 dev_type, dev_num, pnum;
@@ -563,9 +563,9 @@
 		return rcode;
 	}
 
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	/* protect on/off <part-id> */
-	if ((argc == 3) && (id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
+	if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
 		mtdparts_init();
 		if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
 			if (dev->id->type == MTD_DEV_TYPE_NOR) {
@@ -698,7 +698,7 @@
 
 
 /**************************************************/
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 # define TMP_ERASE	"erase <part-id>\n    - erase partition\n"
 # define TMP_PROT_ON	"protect on <part-id>\n    - protect partition\n"
 # define TMP_PROT_OFF	"protect off <part-id>\n    - make partition writable\n"
diff --git a/common/cmd_ide.c b/common/cmd_ide.c
index 8c6ed35..9bc6b4a 100644
--- a/common/cmd_ide.c
+++ b/common/cmd_ide.c
@@ -303,7 +303,7 @@
 #ifdef CONFIG_SYS_64BIT_LBA
 		lbaint_t blk  = simple_strtoull(argv[3], NULL, 16);
 
-		printf ("\nIDE read: device %d block # %qd, count %ld ... ",
+		printf ("\nIDE read: device %d block # %Ld, count %ld ... ",
 			curr_device, blk, cnt);
 #else
 		lbaint_t blk  = simple_strtoul(argv[3], NULL, 16);
@@ -332,7 +332,7 @@
 #ifdef CONFIG_SYS_64BIT_LBA
 		lbaint_t blk  = simple_strtoull(argv[3], NULL, 16);
 
-		printf ("\nIDE write: device %d block # %qd, count %ld ... ",
+		printf ("\nIDE write: device %d block # %Ld, count %ld ... ",
 			curr_device, blk, cnt);
 #else
 		lbaint_t blk  = simple_strtoul(argv[3], NULL, 16);
@@ -1315,7 +1315,7 @@
 		lba48 = 1;
 	}
 #endif
-	debug ("ide_read dev %d start %qX, blocks %lX buffer at %lX\n",
+	debug ("ide_read dev %d start %LX, blocks %lX buffer at %lX\n",
 		device, blknr, blkcnt, (ulong)buffer);
 
 	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
@@ -1403,7 +1403,7 @@
 
 		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
 #if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
-			printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
+			printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
 				device, blknr, c);
 #else
 			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
@@ -1493,7 +1493,7 @@
 
 		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
 #if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
-			printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
+			printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
 				device, blknr, c);
 #else
 			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
index d0a7cea..860d1d9 100644
--- a/common/cmd_jffs2.c
+++ b/common/cmd_jffs2.c
@@ -136,40 +136,6 @@
  * field for read-only partitions */
 #define MTD_WRITEABLE_CMD		1
 
-#ifdef CONFIG_JFFS2_CMDLINE
-/* default values for mtdids and mtdparts variables */
-#if defined(MTDIDS_DEFAULT)
-static const char *const mtdids_default = MTDIDS_DEFAULT;
-#else
-#warning "MTDIDS_DEFAULT not defined!"
-static const char *const mtdids_default = NULL;
-#endif
-
-#if defined(MTDPARTS_DEFAULT)
-static const char *const mtdparts_default = MTDPARTS_DEFAULT;
-#else
-#warning "MTDPARTS_DEFAULT not defined!"
-static const char *const mtdparts_default = NULL;
-#endif
-
-/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
-#define MTDIDS_MAXLEN		128
-#define MTDPARTS_MAXLEN		512
-#define PARTITION_MAXLEN	16
-static char last_ids[MTDIDS_MAXLEN];
-static char last_parts[MTDPARTS_MAXLEN];
-static char last_partition[PARTITION_MAXLEN];
-
-/* low level jffs2 cache cleaning routine */
-extern void jffs2_free_cache(struct part_info *part);
-
-/* mtdids mapping list, filled by parse_ids() */
-struct list_head mtdids;
-
-/* device/partition list, parse_cmdline() parses into here */
-struct list_head devices;
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
 /* current active device and partition number */
 static struct mtd_device *current_dev = NULL;
 static u8 current_partnum = 0;
@@ -188,601 +154,14 @@
 #define cramfs_info(x)		(0)
 #endif
 
-static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num);
-
-/* command line only routines */
-#ifdef CONFIG_JFFS2_CMDLINE
-
-static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
-static int device_del(struct mtd_device *dev);
-
-/**
- * Parses a string into a number.  The number stored at ptr is
- * potentially suffixed with K (for kilobytes, or 1024 bytes),
- * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
- * 1073741824).  If the number is suffixed with K, M, or G, then
- * the return value is the number multiplied by one kilobyte, one
- * megabyte, or one gigabyte, respectively.
- *
- * @param ptr where parse begins
- * @param retptr output pointer to next char after parse completes (output)
- * @return resulting unsigned int
- */
-static unsigned long memsize_parse (const char *const ptr, const char **retptr)
-{
-	unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
-
-	switch (**retptr) {
-		case 'G':
-		case 'g':
-			ret <<= 10;
-		case 'M':
-		case 'm':
-			ret <<= 10;
-		case 'K':
-		case 'k':
-			ret <<= 10;
-			(*retptr)++;
-		default:
-			break;
-	}
-
-	return ret;
-}
-
-/**
- * Format string describing supplied size. This routine does the opposite job
- * to memsize_parse(). Size in bytes is converted to string and if possible
- * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
- *
- * Note, that this routine does not check for buffer overflow, it's the caller
- * who must assure enough space.
- *
- * @param buf output buffer
- * @param size size to be converted to string
- */
-static void memsize_format(char *buf, u32 size)
-{
-#define SIZE_GB ((u32)1024*1024*1024)
-#define SIZE_MB ((u32)1024*1024)
-#define SIZE_KB ((u32)1024)
-
-	if ((size % SIZE_GB) == 0)
-		sprintf(buf, "%ug", size/SIZE_GB);
-	else if ((size % SIZE_MB) == 0)
-		sprintf(buf, "%um", size/SIZE_MB);
-	else if (size % SIZE_KB == 0)
-		sprintf(buf, "%uk", size/SIZE_KB);
-	else
-		sprintf(buf, "%u", size);
-}
-
-/**
- * This routine does global indexing of all partitions. Resulting index for
- * current partition is saved in 'mtddevnum'. Current partition name in
- * 'mtddevname'.
- */
-static void index_partitions(void)
-{
-	char buf[16];
-	u16 mtddevnum;
-	struct part_info *part;
-	struct list_head *dentry;
-	struct mtd_device *dev;
-
-	DEBUGF("--- index partitions ---\n");
-
-	if (current_dev) {
-		mtddevnum = 0;
-		list_for_each(dentry, &devices) {
-			dev = list_entry(dentry, struct mtd_device, link);
-			if (dev == current_dev) {
-				mtddevnum += current_partnum;
-				sprintf(buf, "%d", mtddevnum);
-				setenv("mtddevnum", buf);
-				break;
-			}
-			mtddevnum += dev->num_parts;
-		}
-
-		part = jffs2_part_info(current_dev, current_partnum);
-		setenv("mtddevname", part->name);
-
-		DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
-	} else {
-		setenv("mtddevnum", NULL);
-		setenv("mtddevname", NULL);
-
-		DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
-	}
-}
-
-/**
- * Save current device and partition in environment variable 'partition'.
- */
-static void current_save(void)
-{
-	char buf[16];
-
-	DEBUGF("--- current_save ---\n");
-
-	if (current_dev) {
-		sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
-					current_dev->id->num, current_partnum);
-
-		setenv("partition", buf);
-		strncpy(last_partition, buf, 16);
-
-		DEBUGF("=> partition %s\n", buf);
-	} else {
-		setenv("partition", NULL);
-		last_partition[0] = '\0';
-
-		DEBUGF("=> partition NULL\n");
-	}
-	index_partitions();
-}
-
-/**
- * Performs sanity check for supplied NOR flash partition. Table of existing
- * NOR flash devices is searched and partition device is located. Alignment
- * with the granularity of NOR flash sectors is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_nor(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_CMD_FLASH)
-	/* info for FLASH chips */
-	extern flash_info_t flash_info[];
-	flash_info_t *flash;
-	int offset_aligned;
-	u32 end_offset, sector_size = 0;
-	int i;
-
-	flash = &flash_info[id->num];
-
-	/* size of last sector */
-	part->sector_size = flash->size -
-		(flash->start[flash->sector_count-1] - flash->start[0]);
-
-	offset_aligned = 0;
-	for (i = 0; i < flash->sector_count; i++) {
-		if ((flash->start[i] - flash->start[0]) == part->offset) {
-			offset_aligned = 1;
-			break;
-		}
-	}
-	if (offset_aligned == 0) {
-		printf("%s%d: partition (%s) start offset alignment incorrect\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	end_offset = part->offset + part->size;
-	offset_aligned = 0;
-	for (i = 0; i < flash->sector_count; i++) {
-		if (i) {
-			sector_size = flash->start[i] - flash->start[i-1];
-			if (part->sector_size < sector_size)
-				part->sector_size = sector_size;
-		}
-		if ((flash->start[i] - flash->start[0]) == end_offset)
-			offset_aligned = 1;
-	}
-
-	if (offset_aligned || flash->size == end_offset)
-		return 0;
-
-	printf("%s%d: partition (%s) size alignment incorrect\n",
-			MTD_DEV_TYPE(id->type), id->num, part->name);
-#endif
-	return 1;
-}
-
-/**
- * Performs sanity check for supplied NAND flash partition. Table of existing
- * NAND flash devices is searched and partition device is located. Alignment
- * with the granularity of nand erasesize is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_nand(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
-	/* info for NAND chips */
-	nand_info_t *nand;
-
-	nand = &nand_info[id->num];
-
-	part->sector_size = nand->erasesize;
-
-	if ((unsigned long)(part->offset) % nand->erasesize) {
-		printf("%s%d: partition (%s) start offset alignment incorrect\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	if (part->size % nand->erasesize) {
-		printf("%s%d: partition (%s) size alignment incorrect\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	return 0;
-#else
-	return 1;
-#endif
-}
-
-/**
- * Performs sanity check for supplied OneNAND flash partition.
- * Table of existing OneNAND flash devices is searched and partition device
- * is located. Alignment with the granularity of nand erasesize is verified.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate_onenand(struct mtdids *id, struct part_info *part)
-{
-#if defined(CONFIG_CMD_ONENAND)
-	/* info for OneNAND chips */
-	struct mtd_info *mtd;
-
-	mtd = &onenand_mtd;
-
-	part->sector_size = mtd->erasesize;
-
-	if ((unsigned long)(part->offset) % mtd->erasesize) {
-		printf("%s%d: partition (%s) start offset"
-			"alignment incorrect\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	if (part->size % mtd->erasesize) {
-		printf("%s%d: partition (%s) size alignment incorrect\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	return 0;
-#else
-	return 1;
-#endif
-}
-
-
-/**
- * Performs sanity check for supplied partition. Offset and size are verified
- * to be within valid range. Partition type is checked and either
- * parts_validate_nor() or parts_validate_nand() is called with the argument
- * of part.
- *
- * @param id of the parent device
- * @param part partition to validate
- * @return 0 if partition is valid, 1 otherwise
- */
-static int part_validate(struct mtdids *id, struct part_info *part)
-{
-	if (part->size == SIZE_REMAINING)
-		part->size = id->size - part->offset;
-
-	if (part->offset > id->size) {
-		printf("%s: offset %08x beyond flash size %08x\n",
-				id->mtd_id, part->offset, id->size);
-		return 1;
-	}
-
-	if ((part->offset + part->size) <= part->offset) {
-		printf("%s%d: partition (%s) size too big\n",
-				MTD_DEV_TYPE(id->type), id->num, part->name);
-		return 1;
-	}
-
-	if (part->offset + part->size > id->size) {
-		printf("%s: partitioning exceeds flash size\n", id->mtd_id);
-		return 1;
-	}
-
-	if (id->type == MTD_DEV_TYPE_NAND)
-		return part_validate_nand(id, part);
-	else if (id->type == MTD_DEV_TYPE_NOR)
-		return part_validate_nor(id, part);
-	else if (id->type == MTD_DEV_TYPE_ONENAND)
-		return part_validate_onenand(id, part);
-	else
-		DEBUGF("part_validate: invalid dev type\n");
-
-	return 1;
-}
-
-/**
- * Delete selected partition from the partion list of the specified device.
- *
- * @param dev device to delete partition from
- * @param part partition to delete
- * @return 0 on success, 1 otherwise
- */
-static int part_del(struct mtd_device *dev, struct part_info *part)
-{
-	u8 current_save_needed = 0;
-
-	/* if there is only one partition, remove whole device */
-	if (dev->num_parts == 1)
-		return device_del(dev);
-
-	/* otherwise just delete this partition */
-
-	if (dev == current_dev) {
-		/* we are modyfing partitions for the current device,
-		 * update current */
-		struct part_info *curr_pi;
-		curr_pi = jffs2_part_info(current_dev, current_partnum);
-
-		if (curr_pi) {
-			if (curr_pi == part) {
-				printf("current partition deleted, resetting current to 0\n");
-				current_partnum = 0;
-			} else if (part->offset <= curr_pi->offset) {
-				current_partnum--;
-			}
-			current_save_needed = 1;
-		}
-	}
-
-#ifdef CONFIG_NAND_LEGACY
-	jffs2_free_cache(part);
-#endif
-	list_del(&part->link);
-	free(part);
-	dev->num_parts--;
-
-	if (current_save_needed > 0)
-		current_save();
-	else
-		index_partitions();
-
-	return 0;
-}
-
-/**
- * Delete all partitions from parts head list, free memory.
- *
- * @param head list of partitions to delete
- */
-static void part_delall(struct list_head *head)
-{
-	struct list_head *entry, *n;
-	struct part_info *part_tmp;
-
-	/* clean tmp_list and free allocated memory */
-	list_for_each_safe(entry, n, head) {
-		part_tmp = list_entry(entry, struct part_info, link);
-
-#ifdef CONFIG_NAND_LEGACY
-		jffs2_free_cache(part_tmp);
-#endif
-		list_del(entry);
-		free(part_tmp);
-	}
-}
-
-/**
- * Add new partition to the supplied partition list. Make sure partitions are
- * sorted by offset in ascending order.
- *
- * @param head list this partition is to be added to
- * @param new partition to be added
- */
-static int part_sort_add(struct mtd_device *dev, struct part_info *part)
-{
-	struct list_head *entry;
-	struct part_info *new_pi, *curr_pi;
-
-	/* link partition to parrent dev */
-	part->dev = dev;
-
-	if (list_empty(&dev->parts)) {
-		DEBUGF("part_sort_add: list empty\n");
-		list_add(&part->link, &dev->parts);
-		dev->num_parts++;
-		index_partitions();
-		return 0;
-	}
-
-	new_pi = list_entry(&part->link, struct part_info, link);
-
-	/* get current partition info if we are updating current device */
-	curr_pi = NULL;
-	if (dev == current_dev)
-		curr_pi = jffs2_part_info(current_dev, current_partnum);
-
-	list_for_each(entry, &dev->parts) {
-		struct part_info *pi;
-
-		pi = list_entry(entry, struct part_info, link);
-
-		/* be compliant with kernel cmdline, allow only one partition at offset zero */
-		if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
-			printf("cannot add second partition at offset 0\n");
-			return 1;
-		}
-
-		if (new_pi->offset <= pi->offset) {
-			list_add_tail(&part->link, entry);
-			dev->num_parts++;
-
-			if (curr_pi && (pi->offset <= curr_pi->offset)) {
-				/* we are modyfing partitions for the current
-				 * device, update current */
-				current_partnum++;
-				current_save();
-			} else {
-				index_partitions();
-			}
-			return 0;
-		}
-	}
-
-	list_add_tail(&part->link, &dev->parts);
-	dev->num_parts++;
-	index_partitions();
-	return 0;
-}
-
-/**
- * Add provided partition to the partition list of a given device.
- *
- * @param dev device to which partition is added
- * @param part partition to be added
- * @return 0 on success, 1 otherwise
- */
-static int part_add(struct mtd_device *dev, struct part_info *part)
-{
-	/* verify alignment and size */
-	if (part_validate(dev->id, part) != 0)
-		return 1;
-
-	/* partition is ok, add it to the list */
-	if (part_sort_add(dev, part) != 0)
-		return 1;
-
-	return 0;
-}
-
-/**
- * Parse one partition definition, allocate memory and return pointer to this
- * location in retpart.
- *
- * @param partdef pointer to the partition definition string i.e. <part-def>
- * @param ret output pointer to next char after parse completes (output)
- * @param retpart pointer to the allocated partition (output)
- * @return 0 on success, 1 otherwise
- */
-static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
-{
-	struct part_info *part;
-	unsigned long size;
-	unsigned long offset;
-	const char *name;
-	int name_len;
-	unsigned int mask_flags;
-	const char *p;
-
-	p = partdef;
-	*retpart = NULL;
-	*ret = NULL;
-
-	/* fetch the partition size */
-	if (*p == '-') {
-		/* assign all remaining space to this partition */
-		DEBUGF("'-': remaining size assigned\n");
-		size = SIZE_REMAINING;
-		p++;
-	} else {
-		size = memsize_parse(p, &p);
-		if (size < MIN_PART_SIZE) {
-			printf("partition size too small (%lx)\n", size);
-			return 1;
-		}
-	}
-
-	/* check for offset */
-	offset = OFFSET_NOT_SPECIFIED;
-	if (*p == '@') {
-		p++;
-		offset = memsize_parse(p, &p);
-	}
-
-	/* now look for the name */
-	if (*p == '(') {
-		name = ++p;
-		if ((p = strchr(name, ')')) == NULL) {
-			printf("no closing ) found in partition name\n");
-			return 1;
-		}
-		name_len = p - name + 1;
-		if ((name_len - 1) == 0) {
-			printf("empty partition name\n");
-			return 1;
-		}
-		p++;
-	} else {
-		/* 0x00000000@0x00000000 */
-		name_len = 22;
-		name = NULL;
-	}
-
-	/* test for options */
-	mask_flags = 0;
-	if (strncmp(p, "ro", 2) == 0) {
-		mask_flags |= MTD_WRITEABLE_CMD;
-		p += 2;
-	}
-
-	/* check for next partition definition */
-	if (*p == ',') {
-		if (size == SIZE_REMAINING) {
-			*ret = NULL;
-			printf("no partitions allowed after a fill-up partition\n");
-			return 1;
-		}
-		*ret = ++p;
-	} else if ((*p == ';') || (*p == '\0')) {
-		*ret = p;
-	} else {
-		printf("unexpected character '%c' at the end of partition\n", *p);
-		*ret = NULL;
-		return 1;
-	}
-
-	/*  allocate memory */
-	part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
-	if (!part) {
-		printf("out of memory\n");
-		return 1;
-	}
-	memset(part, 0, sizeof(struct part_info) + name_len);
-	part->size = size;
-	part->offset = offset;
-	part->mask_flags = mask_flags;
-	part->name = (char *)(part + 1);
-
-	if (name) {
-		/* copy user provided name */
-		strncpy(part->name, name, name_len - 1);
-		part->auto_name = 0;
-	} else {
-		/* auto generated name in form of size@offset */
-		sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
-		part->auto_name = 1;
-	}
-
-	part->name[name_len - 1] = '\0';
-	INIT_LIST_HEAD(&part->link);
-
-	DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
-			part->name, part->size,
-			part->offset, part->mask_flags);
-
-	*retpart = part;
-	return 0;
-}
-#endif/* #ifdef CONFIG_JFFS2_CMDLINE */
-
+#ifndef CONFIG_CMD_MTDPARTS
 /**
  * Check device number to be within valid range for given device type.
  *
  * @param dev device to validate
  * @return 0 if device is valid, 1 otherwise
  */
-static int device_validate(u8 type, u8 num, u32 *size)
+static int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
 	if (type == MTD_DEV_TYPE_NOR) {
 #if defined(CONFIG_CMD_FLASH)
@@ -828,310 +207,6 @@
 	return 1;
 }
 
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Delete all mtd devices from a supplied devices list, free memory allocated for
- * each device and delete all device partitions.
- *
- * @return 0 on success, 1 otherwise
- */
-static int device_delall(struct list_head *head)
-{
-	struct list_head *entry, *n;
-	struct mtd_device *dev_tmp;
-
-	/* clean devices list */
-	list_for_each_safe(entry, n, head) {
-		dev_tmp = list_entry(entry, struct mtd_device, link);
-		list_del(entry);
-		part_delall(&dev_tmp->parts);
-		free(dev_tmp);
-	}
-	INIT_LIST_HEAD(&devices);
-
-	return 0;
-}
-
-/**
- * If provided device exists it's partitions are deleted, device is removed
- * from device list and device memory is freed.
- *
- * @param dev device to be deleted
- * @return 0 on success, 1 otherwise
- */
-static int device_del(struct mtd_device *dev)
-{
-	part_delall(&dev->parts);
-	list_del(&dev->link);
-	free(dev);
-
-	if (dev == current_dev) {
-		/* we just deleted current device */
-		if (list_empty(&devices)) {
-			current_dev = NULL;
-		} else {
-			/* reset first partition from first dev from the
-			 * devices list as current */
-			current_dev = list_entry(devices.next, struct mtd_device, link);
-			current_partnum = 0;
-		}
-		current_save();
-		return 0;
-	}
-
-	index_partitions();
-	return 0;
-}
-
-/**
- * Search global device list and return pointer to the device of type and num
- * specified.
- *
- * @param type device type
- * @param num device number
- * @return NULL if requested device does not exist
- */
-static struct mtd_device* device_find(u8 type, u8 num)
-{
-	struct list_head *entry;
-	struct mtd_device *dev_tmp;
-
-	list_for_each(entry, &devices) {
-		dev_tmp = list_entry(entry, struct mtd_device, link);
-
-		if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
-			return dev_tmp;
-	}
-
-	return NULL;
-}
-
-/**
- * Add specified device to the global device list.
- *
- * @param dev device to be added
- */
-static void device_add(struct mtd_device *dev)
-{
-	u8 current_save_needed = 0;
-
-	if (list_empty(&devices)) {
-		current_dev = dev;
-		current_partnum = 0;
-		current_save_needed = 1;
-	}
-
-	list_add_tail(&dev->link, &devices);
-
-	if (current_save_needed > 0)
-		current_save();
-	else
-		index_partitions();
-}
-
-/**
- * Parse device type, name and mtd-id. If syntax is ok allocate memory and
- * return pointer to the device structure.
- *
- * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
- * @param ret output pointer to next char after parse completes (output)
- * @param retdev pointer to the allocated device (output)
- * @return 0 on success, 1 otherwise
- */
-static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
-{
-	struct mtd_device *dev;
-	struct part_info *part;
-	struct mtdids *id;
-	const char *mtd_id;
-	unsigned int mtd_id_len;
-	const char *p, *pend;
-	LIST_HEAD(tmp_list);
-	struct list_head *entry, *n;
-	u16 num_parts;
-	u32 offset;
-	int err = 1;
-
-	p = mtd_dev;
-	*retdev = NULL;
-	*ret = NULL;
-
-	DEBUGF("===device_parse===\n");
-
-	/* fetch <mtd-id> */
-	mtd_id = p;
-	if (!(p = strchr(mtd_id, ':'))) {
-		printf("no <mtd-id> identifier\n");
-		return 1;
-	}
-	mtd_id_len = p - mtd_id + 1;
-	p++;
-
-	/* verify if we have a valid device specified */
-	if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
-		printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
-		return 1;
-	}
-
-	DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
-			id->type, MTD_DEV_TYPE(id->type),
-			id->num, id->mtd_id);
-	pend = strchr(p, ';');
-	DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
-
-
-	/* parse partitions */
-	num_parts = 0;
-
-	offset = 0;
-	if ((dev = device_find(id->type, id->num)) != NULL) {
-		/* if device already exists start at the end of the last partition */
-		part = list_entry(dev->parts.prev, struct part_info, link);
-		offset = part->offset + part->size;
-	}
-
-	while (p && (*p != '\0') && (*p != ';')) {
-		err = 1;
-		if ((part_parse(p, &p, &part) != 0) || (!part))
-			break;
-
-		/* calculate offset when not specified */
-		if (part->offset == OFFSET_NOT_SPECIFIED)
-			part->offset = offset;
-		else
-			offset = part->offset;
-
-		/* verify alignment and size */
-		if (part_validate(id, part) != 0)
-			break;
-
-		offset += part->size;
-
-		/* partition is ok, add it to the list */
-		list_add_tail(&part->link, &tmp_list);
-		num_parts++;
-		err = 0;
-	}
-	if (err == 1) {
-		part_delall(&tmp_list);
-		return 1;
-	}
-
-	if (num_parts == 0) {
-		printf("no partitions for device %s%d (%s)\n",
-				MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
-		return 1;
-	}
-
-	DEBUGF("\ntotal partitions: %d\n", num_parts);
-
-	/* check for next device presence */
-	if (p) {
-		if (*p == ';') {
-			*ret = ++p;
-		} else if (*p == '\0') {
-			*ret = p;
-		} else {
-			printf("unexpected character '%c' at the end of device\n", *p);
-			*ret = NULL;
-			return 1;
-		}
-	}
-
-	/* allocate memory for mtd_device structure */
-	if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
-		printf("out of memory\n");
-		return 1;
-	}
-	memset(dev, 0, sizeof(struct mtd_device));
-	dev->id = id;
-	dev->num_parts = 0; /* part_sort_add increments num_parts */
-	INIT_LIST_HEAD(&dev->parts);
-	INIT_LIST_HEAD(&dev->link);
-
-	/* move partitions from tmp_list to dev->parts */
-	list_for_each_safe(entry, n, &tmp_list) {
-		part = list_entry(entry, struct part_info, link);
-		list_del(entry);
-		if (part_sort_add(dev, part) != 0) {
-			device_del(dev);
-			return 1;
-		}
-	}
-
-	*retdev = dev;
-
-	DEBUGF("===\n\n");
-	return 0;
-}
-
-/**
- * Initialize global device list.
- *
- * @return 0 on success, 1 otherwise
- */
-static int jffs2_devices_init(void)
-{
-	last_parts[0] = '\0';
-	current_dev = NULL;
-	current_save();
-
-	return device_delall(&devices);
-}
-
-/*
- * Search global mtdids list and find id of requested type and number.
- *
- * @return pointer to the id if it exists, NULL otherwise
- */
-static struct mtdids* id_find(u8 type, u8 num)
-{
-	struct list_head *entry;
-	struct mtdids *id;
-
-	list_for_each(entry, &mtdids) {
-		id = list_entry(entry, struct mtdids, link);
-
-		if ((id->type == type) && (id->num == num))
-			return id;
-	}
-
-	return NULL;
-}
-
-/**
- * Search global mtdids list and find id of a requested mtd_id.
- *
- * Note: first argument is not null terminated.
- *
- * @param mtd_id string containing requested mtd_id
- * @param mtd_id_len length of supplied mtd_id
- * @return pointer to the id if it exists, NULL otherwise
- */
-static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
-{
-	struct list_head *entry;
-	struct mtdids *id;
-
-	DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
-			mtd_id_len, mtd_id, mtd_id_len);
-
-	list_for_each(entry, &mtdids) {
-		id = list_entry(entry, struct mtdids, link);
-
-		DEBUGF("entry: '%s' (len = %d)\n",
-				id->mtd_id, strlen(id->mtd_id));
-
-		if (mtd_id_len != strlen(id->mtd_id))
-			continue;
-		if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
-			return id;
-	}
-
-	return NULL;
-}
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
 /**
  * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
  * return device type and number.
@@ -1142,7 +217,7 @@
  * @param dev_num parsed device number (output)
  * @return 0 on success, 1 otherwise
  */
-int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
 {
 	const char *p = id;
 
@@ -1172,606 +247,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Process all devices and generate corresponding mtdparts string describing
- * all partitions on all devices.
- *
- * @param buf output buffer holding generated mtdparts string (output)
- * @param buflen buffer size
- * @return 0 on success, 1 otherwise
- */
-static int generate_mtdparts(char *buf, u32 buflen)
-{
-	struct list_head *pentry, *dentry;
-	struct mtd_device *dev;
-	struct part_info *part, *prev_part;
-	char *p = buf;
-	char tmpbuf[32];
-	u32 size, offset, len, part_cnt;
-	u32 maxlen = buflen - 1;
-
-	DEBUGF("--- generate_mtdparts ---\n");
-
-	if (list_empty(&devices)) {
-		buf[0] = '\0';
-		return 0;
-	}
-
-	sprintf(p, "mtdparts=");
-	p += 9;
-
-	list_for_each(dentry, &devices) {
-		dev = list_entry(dentry, struct mtd_device, link);
-
-		/* copy mtd_id */
-		len = strlen(dev->id->mtd_id) + 1;
-		if (len > maxlen)
-			goto cleanup;
-		memcpy(p, dev->id->mtd_id, len - 1);
-		p += len - 1;
-		*(p++) = ':';
-		maxlen -= len;
-
-		/* format partitions */
-		prev_part = NULL;
-		part_cnt = 0;
-		list_for_each(pentry, &dev->parts) {
-			part = list_entry(pentry, struct part_info, link);
-			size = part->size;
-			offset = part->offset;
-			part_cnt++;
-
-			/* partition size */
-			memsize_format(tmpbuf, size);
-			len = strlen(tmpbuf);
-			if (len > maxlen)
-				goto cleanup;
-			memcpy(p, tmpbuf, len);
-			p += len;
-			maxlen -= len;
-
-
-			/* add offset only when there is a gap between
-			 * partitions */
-			if ((!prev_part && (offset != 0)) ||
-					(prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
-
-				memsize_format(tmpbuf, offset);
-				len = strlen(tmpbuf) + 1;
-				if (len > maxlen)
-					goto cleanup;
-				*(p++) = '@';
-				memcpy(p, tmpbuf, len - 1);
-				p += len - 1;
-				maxlen -= len;
-			}
-
-			/* copy name only if user supplied */
-			if(!part->auto_name) {
-				len = strlen(part->name) + 2;
-				if (len > maxlen)
-					goto cleanup;
-
-				*(p++) = '(';
-				memcpy(p, part->name, len - 2);
-				p += len - 2;
-				*(p++) = ')';
-				maxlen -= len;
-			}
-
-			/* ro mask flag */
-			if (part->mask_flags && MTD_WRITEABLE_CMD) {
-				len = 2;
-				if (len > maxlen)
-					goto cleanup;
-				*(p++) = 'r';
-				*(p++) = 'o';
-				maxlen -= 2;
-			}
-
-			/* print ',' separator if there are other partitions
-			 * following */
-			if (dev->num_parts > part_cnt) {
-				if (1 > maxlen)
-					goto cleanup;
-				*(p++) = ',';
-				maxlen--;
-			}
-			prev_part = part;
-		}
-		/* print ';' separator if there are other devices following */
-		if (dentry->next != &devices) {
-			if (1 > maxlen)
-				goto cleanup;
-			*(p++) = ';';
-			maxlen--;
-		}
-	}
-
-	/* we still have at least one char left, as we decremented maxlen at
-	 * the begining */
-	*p = '\0';
-
-	return 0;
-
-cleanup:
-	last_parts[0] = '\0';
-	return 1;
-}
-
-/**
- * Call generate_mtdparts to process all devices and generate corresponding
- * mtdparts string, save it in mtdparts environment variable.
- *
- * @param buf output buffer holding generated mtdparts string (output)
- * @param buflen buffer size
- * @return 0 on success, 1 otherwise
- */
-static int generate_mtdparts_save(char *buf, u32 buflen)
-{
-	int ret;
-
-	ret = generate_mtdparts(buf, buflen);
-
-	if ((buf[0] != '\0') && (ret == 0))
-		setenv("mtdparts", buf);
-	else
-		setenv("mtdparts", NULL);
-
-	return ret;
-}
-
-/**
- * Format and print out a partition list for each device from global device
- * list.
- */
-static void list_partitions(void)
-{
-	struct list_head *dentry, *pentry;
-	struct part_info *part;
-	struct mtd_device *dev;
-	int part_num;
-
-	DEBUGF("\n---list_partitions---\n");
-	list_for_each(dentry, &devices) {
-		dev = list_entry(dentry, struct mtd_device, link);
-		printf("\ndevice %s%d <%s>, # parts = %d\n",
-				MTD_DEV_TYPE(dev->id->type), dev->id->num,
-				dev->id->mtd_id, dev->num_parts);
-		printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
-
-		/* list partitions for given device */
-		part_num = 0;
-		list_for_each(pentry, &dev->parts) {
-			part = list_entry(pentry, struct part_info, link);
-			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
-					part_num, part->name, part->size,
-					part->offset, part->mask_flags);
-
-			part_num++;
-		}
-	}
-	if (list_empty(&devices))
-		printf("no partitions defined\n");
-
-	/* current_dev is not NULL only when we have non empty device list */
-	if (current_dev) {
-		part = jffs2_part_info(current_dev, current_partnum);
-		if (part) {
-			printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
-					MTD_DEV_TYPE(current_dev->id->type),
-					current_dev->id->num, current_partnum,
-					part->name, part->size, part->offset);
-		} else {
-			printf("could not get current partition info\n\n");
-		}
-	}
-
-	printf("\ndefaults:\n");
-	printf("mtdids  : %s\n", mtdids_default);
-	printf("mtdparts: %s\n", mtdparts_default);
-}
-
-/**
- * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
- * corresponding device and verify partition number.
- *
- * @param id string describing device and partition or partition name
- * @param dev pointer to the requested device (output)
- * @param part_num verified partition number (output)
- * @param part pointer to requested partition (output)
- * @return 0 on success, 1 otherwise
- */
-int find_dev_and_part(const char *id, struct mtd_device **dev,
-		u8 *part_num, struct part_info **part)
-{
-	struct list_head *dentry, *pentry;
-	u8 type, dnum, pnum;
-	const char *p;
-
-	DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
-
-	list_for_each(dentry, &devices) {
-		*part_num = 0;
-		*dev = list_entry(dentry, struct mtd_device, link);
-		list_for_each(pentry, &(*dev)->parts) {
-			*part = list_entry(pentry, struct part_info, link);
-			if (strcmp((*part)->name, id) == 0)
-				return 0;
-			(*part_num)++;
-		}
-	}
-
-	p = id;
-	*dev = NULL;
-	*part = NULL;
-	*part_num = 0;
-
-	if (id_parse(p, &p, &type, &dnum) != 0)
-		return 1;
-
-	if ((*p++ != ',') || (*p == '\0')) {
-		printf("no partition number specified\n");
-		return 1;
-	}
-	pnum = simple_strtoul(p, (char **)&p, 0);
-	if (*p != '\0') {
-		printf("unexpected trailing character '%c'\n", *p);
-		return 1;
-	}
-
-	if ((*dev = device_find(type, dnum)) == NULL) {
-		printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
-		return 1;
-	}
-
-	if ((*part = jffs2_part_info(*dev, pnum)) == NULL) {
-		printf("no such partition\n");
-		*dev = NULL;
-		return 1;
-	}
-
-	*part_num = pnum;
-
-	return 0;
-}
-
-/**
- * Find and delete partition. For partition id format see find_dev_and_part().
- *
- * @param id string describing device and partition
- * @return 0 on success, 1 otherwise
- */
-static int delete_partition(const char *id)
-{
-	u8 pnum;
-	struct mtd_device *dev;
-	struct part_info *part;
-
-	if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
-
-		DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
-				MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
-				part->name, part->size, part->offset);
-
-		if (part_del(dev, part) != 0)
-			return 1;
-
-		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
-			printf("generated mtdparts too long, reseting to null\n");
-			return 1;
-		}
-		return 0;
-	}
-
-	printf("partition %s not found\n", id);
-	return 1;
-}
-
-/**
- * Accept character string describing mtd partitions and call device_parse()
- * for each entry. Add created devices to the global devices list.
- *
- * @param mtdparts string specifing mtd partitions
- * @return 0 on success, 1 otherwise
- */
-static int parse_mtdparts(const char *const mtdparts)
-{
-	const char *p = mtdparts;
-	struct mtd_device *dev;
-	int err = 1;
-
-	DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
-
-	/* delete all devices and partitions */
-	if (jffs2_devices_init() != 0) {
-		printf("could not initialise device list\n");
-		return err;
-	}
-
-	/* re-read 'mtdparts' variable, jffs2_devices_init may be updating env */
-	p = getenv("mtdparts");
-
-	if (strncmp(p, "mtdparts=", 9) != 0) {
-		printf("mtdparts variable doesn't start with 'mtdparts='\n");
-		return err;
-	}
-	p += 9;
-
-	while (p && (*p != '\0')) {
-		err = 1;
-		if ((device_parse(p, &p, &dev) != 0) || (!dev))
-			break;
-
-		DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
-				dev->id->num, dev->id->mtd_id);
-
-		/* check if parsed device is already on the list */
-		if (device_find(dev->id->type, dev->id->num) != NULL) {
-			printf("device %s%d redefined, please correct mtdparts variable\n",
-					MTD_DEV_TYPE(dev->id->type), dev->id->num);
-			break;
-		}
-
-		list_add_tail(&dev->link, &devices);
-		err = 0;
-	}
-	if (err == 1) {
-		device_delall(&devices);
-		return 1;
-	}
-
-	return 0;
-}
-
-/**
- * Parse provided string describing mtdids mapping (see file header for mtdids
- * variable format). Allocate memory for each entry and add all found entries
- * to the global mtdids list.
- *
- * @param ids mapping string
- * @return 0 on success, 1 otherwise
- */
-static int parse_mtdids(const char *const ids)
-{
-	const char *p = ids;
-	const char *mtd_id;
-	int mtd_id_len;
-	struct mtdids *id;
-	struct list_head *entry, *n;
-	struct mtdids *id_tmp;
-	u8 type, num;
-	u32 size;
-	int ret = 1;
-
-	DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
-
-	/* clean global mtdids list */
-	list_for_each_safe(entry, n, &mtdids) {
-		id_tmp = list_entry(entry, struct mtdids, link);
-		DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
-		list_del(entry);
-		free(id_tmp);
-	}
-	last_ids[0] = '\0';
-	INIT_LIST_HEAD(&mtdids);
-
-	while(p && (*p != '\0')) {
-
-		ret = 1;
-		/* parse 'nor'|'nand'|'onenand'<dev-num> */
-		if (id_parse(p, &p, &type, &num) != 0)
-			break;
-
-		if (*p != '=') {
-			printf("mtdids: incorrect <dev-num>\n");
-			break;
-		}
-		p++;
-
-		/* check if requested device exists */
-		if (device_validate(type, num, &size) != 0)
-			return 1;
-
-		/* locate <mtd-id> */
-		mtd_id = p;
-		if ((p = strchr(mtd_id, ',')) != NULL) {
-			mtd_id_len = p - mtd_id + 1;
-			p++;
-		} else {
-			mtd_id_len = strlen(mtd_id) + 1;
-		}
-		if (mtd_id_len == 0) {
-			printf("mtdids: no <mtd-id> identifier\n");
-			break;
-		}
-
-		/* check if this id is already on the list */
-		int double_entry = 0;
-		list_for_each(entry, &mtdids) {
-			id_tmp = list_entry(entry, struct mtdids, link);
-			if ((id_tmp->type == type) && (id_tmp->num == num)) {
-				double_entry = 1;
-				break;
-			}
-		}
-		if (double_entry) {
-			printf("device id %s%d redefined, please correct mtdids variable\n",
-					MTD_DEV_TYPE(type), num);
-			break;
-		}
-
-		/* allocate mtdids structure */
-		if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
-			printf("out of memory\n");
-			break;
-		}
-		memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
-		id->num = num;
-		id->type = type;
-		id->size = size;
-		id->mtd_id = (char *)(id + 1);
-		strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
-		id->mtd_id[mtd_id_len - 1] = '\0';
-		INIT_LIST_HEAD(&id->link);
-
-		DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
-				MTD_DEV_TYPE(id->type), id->num,
-				id->size, id->mtd_id);
-
-		list_add_tail(&id->link, &mtdids);
-		ret = 0;
-	}
-	if (ret == 1) {
-		/* clean mtdids list and free allocated memory */
-		list_for_each_safe(entry, n, &mtdids) {
-			id_tmp = list_entry(entry, struct mtdids, link);
-			list_del(entry);
-			free(id_tmp);
-		}
-		return 1;
-	}
-
-	return 0;
-}
-
-/**
- * Parse and initialize global mtdids mapping and create global
- * device/partition list.
- *
- * @return 0 on success, 1 otherwise
- */
-int mtdparts_init(void)
-{
-	static int initialized = 0;
-	const char *ids, *parts;
-	const char *current_partition;
-	int ids_changed;
-	char tmp_ep[PARTITION_MAXLEN];
-
-	DEBUGF("\n---mtdparts_init---\n");
-	if (!initialized) {
-		INIT_LIST_HEAD(&mtdids);
-		INIT_LIST_HEAD(&devices);
-		memset(last_ids, 0, MTDIDS_MAXLEN);
-		memset(last_parts, 0, MTDPARTS_MAXLEN);
-		memset(last_partition, 0, PARTITION_MAXLEN);
-		initialized = 1;
-	}
-
-	/* get variables */
-	ids = getenv("mtdids");
-	parts = getenv("mtdparts");
-	current_partition = getenv("partition");
-
-	/* save it for later parsing, cannot rely on current partition pointer
-	 * as 'partition' variable may be updated during init */
-	tmp_ep[0] = '\0';
-	if (current_partition)
-		strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
-
-	DEBUGF("last_ids  : %s\n", last_ids);
-	DEBUGF("env_ids   : %s\n", ids);
-	DEBUGF("last_parts: %s\n", last_parts);
-	DEBUGF("env_parts : %s\n\n", parts);
-
-	DEBUGF("last_partition : %s\n", last_partition);
-	DEBUGF("env_partition  : %s\n", current_partition);
-
-	/* if mtdids varible is empty try to use defaults */
-	if (!ids) {
-		if (mtdids_default) {
-			DEBUGF("mtdids variable not defined, using default\n");
-			ids = mtdids_default;
-			setenv("mtdids", (char *)ids);
-		} else {
-			printf("mtdids not defined, no default present\n");
-			return 1;
-		}
-	}
-	if (strlen(ids) > MTDIDS_MAXLEN - 1) {
-		printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
-		return 1;
-	}
-
-	/* do no try to use defaults when mtdparts variable is not defined,
-	 * just check the length */
-	if (!parts)
-		printf("mtdparts variable not set, see 'help mtdparts'\n");
-
-	if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
-		printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
-		return 1;
-	}
-
-	/* check if we have already parsed those mtdids */
-	if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
-		ids_changed = 0;
-	} else {
-		ids_changed = 1;
-
-		if (parse_mtdids(ids) != 0) {
-			jffs2_devices_init();
-			return 1;
-		}
-
-		/* ok it's good, save new ids */
-		strncpy(last_ids, ids, MTDIDS_MAXLEN);
-	}
-
-	/* parse partitions if either mtdparts or mtdids were updated */
-	if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
-		if (parse_mtdparts(parts) != 0)
-			return 1;
-
-		if (list_empty(&devices)) {
-			printf("mtdparts_init: no valid partitions\n");
-			return 1;
-		}
-
-		/* ok it's good, save new parts */
-		strncpy(last_parts, parts, MTDPARTS_MAXLEN);
-
-		/* reset first partition from first dev from the list as current */
-		current_dev = list_entry(devices.next, struct mtd_device, link);
-		current_partnum = 0;
-		current_save();
-
-		DEBUGF("mtdparts_init: current_dev  = %s%d, current_partnum = %d\n",
-				MTD_DEV_TYPE(current_dev->id->type),
-				current_dev->id->num, current_partnum);
-	}
-
-	/* mtdparts variable was reset to NULL, delete all devices/partitions */
-	if (!parts && (last_parts[0] != '\0'))
-		return jffs2_devices_init();
-
-	/* do not process current partition if mtdparts variable is null */
-	if (!parts)
-		return 0;
-
-	/* is current partition set in environment? if so, use it */
-	if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
-		struct part_info *p;
-		struct mtd_device *cdev;
-		u8 pnum;
-
-		DEBUGF("--- getting current partition: %s\n", tmp_ep);
-
-		if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
-			current_dev = cdev;
-			current_partnum = pnum;
-			current_save();
-		}
-	} else if (getenv("partition") == NULL) {
-		DEBUGF("no partition variable set, setting...\n");
-		current_save();
-	}
-
-	return 0;
-}
-#else /* #ifdef CONFIG_JFFS2_CMDLINE */
 /*
  * 'Static' version of command line mtdparts_init() routine. Single partition on
  * a single device configuration.
@@ -1908,8 +383,8 @@
 		dev_name = "nor0";
 #endif
 
-		if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
-				(device_validate(id->type, id->num, &size) != 0)) {
+		if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
+				(mtd_device_validate(id->type, id->num, &size) != 0)) {
 			printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
 			free(current_dev);
 			return 1;
@@ -1958,7 +433,7 @@
 
 	return 0;
 }
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
+#endif /* #ifndef CONFIG_CMD_MTDPARTS */
 
 /**
  * Return pointer to the partition of a requested number from a requested
@@ -2145,155 +620,6 @@
 	return 1;
 }
 
-/* command line only */
-#ifdef CONFIG_JFFS2_CMDLINE
-/**
- * Routine implementing u-boot chpart command. Sets new current partition based
- * on the user supplied partition id. For partition id format see find_dev_and_part().
- *
- * @param cmdtp command internal data
- * @param flag command flag
- * @param argc number of arguments supplied to the command
- * @param argv arguments list
- * @return 0 on success, 1 otherwise
- */
-int do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
-{
-/* command line only */
-	struct mtd_device *dev;
-	struct part_info *part;
-	u8 pnum;
-
-	if (mtdparts_init() !=0)
-		return 1;
-
-	if (argc < 2) {
-		printf("no partition id specified\n");
-		return 1;
-	}
-
-	if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
-		return 1;
-
-	current_dev = dev;
-	current_partnum = pnum;
-	current_save();
-
-	printf("partition changed to %s%d,%d\n",
-			MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
-
-	return 0;
-}
-
-/**
- * Routine implementing u-boot mtdparts command. Initialize/update default global
- * partition list and process user partition request (list, add, del).
- *
- * @param cmdtp command internal data
- * @param flag command flag
- * @param argc number of arguments supplied to the command
- * @param argv arguments list
- * @return 0 on success, 1 otherwise
- */
-int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
-{
-	if (argc == 2) {
-		if (strcmp(argv[1], "default") == 0) {
-			setenv("mtdids", (char *)mtdids_default);
-			setenv("mtdparts", (char *)mtdparts_default);
-			setenv("partition", NULL);
-
-			mtdparts_init();
-			return 0;
-		} else if (strcmp(argv[1], "delall") == 0) {
-			/* this may be the first run, initialize lists if needed */
-			mtdparts_init();
-
-			setenv("mtdparts", NULL);
-
-			/* jffs2_devices_init() calls current_save() */
-			return jffs2_devices_init();
-		}
-	}
-
-	/* make sure we are in sync with env variables */
-	if (mtdparts_init() != 0)
-		return 1;
-
-	if (argc == 1) {
-		list_partitions();
-		return 0;
-	}
-
-	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
-#define PART_ADD_DESC_MAXLEN 64
-		char tmpbuf[PART_ADD_DESC_MAXLEN];
-		u8 type, num, len;
-		struct mtd_device *dev;
-		struct mtd_device *dev_tmp;
-		struct mtdids *id;
-		struct part_info *p;
-
-		if (id_parse(argv[2], NULL, &type, &num) != 0)
-			return 1;
-
-		if ((id = id_find(type, num)) == NULL) {
-			printf("no such device %s defined in mtdids variable\n", argv[2]);
-			return 1;
-		}
-
-		len = strlen(id->mtd_id) + 1;	/* 'mtd_id:' */
-		len += strlen(argv[3]);		/* size@offset */
-		len += strlen(argv[4]) + 2;	/* '(' name ')' */
-		if (argv[5] && (strlen(argv[5]) == 2))
-			len += 2;		/* 'ro' */
-
-		if (len >= PART_ADD_DESC_MAXLEN) {
-			printf("too long partition description\n");
-			return 1;
-		}
-		sprintf(tmpbuf, "%s:%s(%s)%s",
-				id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
-		DEBUGF("add tmpbuf: %s\n", tmpbuf);
-
-		if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
-			return 1;
-
-		DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
-				dev->id->num, dev->id->mtd_id);
-
-		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
-			device_add(dev);
-		} else {
-			/* merge new partition with existing ones*/
-			p = list_entry(dev->parts.next, struct part_info, link);
-			if (part_add(dev_tmp, p) != 0) {
-				device_del(dev);
-				return 1;
-			}
-		}
-
-		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
-			printf("generated mtdparts too long, reseting to null\n");
-			return 1;
-		}
-
-		return 0;
-	}
-
-	/* mtdparts del part-id */
-	if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
-		DEBUGF("del: part-id = %s\n", argv[2]);
-
-		return delete_partition(argv[2]);
-	}
-
-	cmd_usage(cmdtp);
-	return 1;
-}
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
 /***************************************************/
 U_BOOT_CMD(
 	fsload,	3,	0,	do_jffs2_fsload,
@@ -2314,49 +640,4 @@
 	"print information about filesystems",
 	"    - print information about filesystems\n"
 );
-
-#ifdef CONFIG_JFFS2_CMDLINE
-U_BOOT_CMD(
-	chpart,	2,	0,	do_jffs2_chpart,
-	"change active partition",
-	"part-id\n"
-	"    - change active partition (e.g. part-id = nand0,1)\n"
-);
-
-U_BOOT_CMD(
-	mtdparts,	6,	0,	do_jffs2_mtdparts,
-	"define flash/nand partitions",
-	"\n"
-	"    - list partition table\n"
-	"mtdparts delall\n"
-	"    - delete all partitions\n"
-	"mtdparts del part-id\n"
-	"    - delete partition (e.g. part-id = nand0,1)\n"
-	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
-	"    - add partition\n"
-	"mtdparts default\n"
-	"    - reset partition table to defaults\n\n"
-	"-----\n\n"
-	"this command uses three environment variables:\n\n"
-	"'partition' - keeps current partition identifier\n\n"
-	"partition  := <part-id>\n"
-	"<part-id>  := <dev-id>,part_num\n\n"
-	"'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
-	"mtdids=<idmap>[,<idmap>,...]\n\n"
-	"<idmap>    := <dev-id>=<mtd-id>\n"
-	"<dev-id>   := 'nand'|'nor'|'onenand'<dev-num>\n"
-	"<dev-num>  := mtd device number, 0...\n"
-	"<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
-	"'mtdparts' - partition list\n\n"
-	"mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
-	"<mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]\n"
-	"<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
-	"<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
-	"<size>     := standard linux memsize OR '-' to denote all remaining space\n"
-	"<offset>   := partition start offset within the device\n"
-	"<name>     := '(' NAME ')'\n"
-	"<ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
-);
-#endif /* #ifdef CONFIG_JFFS2_CMDLINE */
-
 /***************************************************/
diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
new file mode 100644
index 0000000..c8bf2c6
--- /dev/null
+++ b/common/cmd_mtdparts.c
@@ -0,0 +1,1986 @@
+/*
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
+ *
+ * (C) Copyright 2003
+ * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
+ *
+ * (C) Copyright 2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ *   Added support for reading flash partition table from environment.
+ *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
+ *   kernel tree.
+ *
+ *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ *   Copyright 2002 SYSGO Real-Time Solutions 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
+ */
+
+/*
+ * Three environment variables are used by the parsing routines:
+ *
+ * 'partition' - keeps current partition identifier
+ *
+ * partition  := <part-id>
+ * <part-id>  := <dev-id>,part_num
+ *
+ *
+ * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
+ *
+ * mtdids=<idmap>[,<idmap>,...]
+ *
+ * <idmap>    := <dev-id>=<mtd-id>
+ * <dev-id>   := 'nand'|'nor'|'onenand'<dev-num>
+ * <dev-num>  := mtd device number, 0...
+ * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
+ *
+ *
+ * 'mtdparts' - partition list
+ *
+ * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
+ *
+ * <mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]
+ * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
+ * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
+ * <size>     := standard linux memsize OR '-' to denote all remaining space
+ * <offset>   := partition start offset within the device
+ * <name>     := '(' NAME ')'
+ * <ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)
+ *
+ * Notes:
+ * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
+ * - if the above variables are not set defaults for a given target are used
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * mtdids=nor0=edb7312-nor
+ * mtdparts=mtdparts=edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
+ * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ *
+ */
+
+/*
+ * JFFS2/CRAMFS support
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <jffs2/jffs2.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <cramfs/cramfs_fs.h>
+
+#if defined(CONFIG_CMD_NAND)
+#ifdef CONFIG_NAND_LEGACY
+#include <linux/mtd/nand_legacy.h>
+#else /* !CONFIG_NAND_LEGACY */
+#include <linux/mtd/nand.h>
+#include <nand.h>
+#endif /* !CONFIG_NAND_LEGACY */
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <onenand_uboot.h>
+#endif
+
+/* enable/disable debugging messages */
+#define	DEBUG_MTDPARTS
+#undef	DEBUG_MTDPARTS
+
+#ifdef  DEBUG_MTDPARTS
+# define DEBUGF(fmt, args...)	printf(fmt ,##args)
+#else
+# define DEBUGF(fmt, args...)
+#endif
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING		0xFFFFFFFF
+
+/* special offset value, it is used when not provided by user
+ *
+ * this value is used temporarily during parsing, later such offests
+ * are recalculated */
+#define OFFSET_NOT_SPECIFIED	0xFFFFFFFF
+
+/* minimum partition size */
+#define MIN_PART_SIZE		4096
+
+/* this flag needs to be set in part_info struct mask_flags
+ * field for read-only partitions */
+#define MTD_WRITEABLE_CMD		1
+
+/* default values for mtdids and mtdparts variables */
+#if defined(MTDIDS_DEFAULT)
+static const char *const mtdids_default = MTDIDS_DEFAULT;
+#else
+#warning "MTDIDS_DEFAULT not defined!"
+static const char *const mtdids_default = NULL;
+#endif
+
+#if defined(MTDPARTS_DEFAULT)
+static const char *const mtdparts_default = MTDPARTS_DEFAULT;
+#else
+#warning "MTDPARTS_DEFAULT not defined!"
+static const char *const mtdparts_default = NULL;
+#endif
+
+/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
+#define MTDIDS_MAXLEN		128
+#define MTDPARTS_MAXLEN		512
+#define PARTITION_MAXLEN	16
+static char last_ids[MTDIDS_MAXLEN];
+static char last_parts[MTDPARTS_MAXLEN];
+static char last_partition[PARTITION_MAXLEN];
+
+/* low level jffs2 cache cleaning routine */
+extern void jffs2_free_cache(struct part_info *part);
+
+/* mtdids mapping list, filled by parse_ids() */
+struct list_head mtdids;
+
+/* device/partition list, parse_cmdline() parses into here */
+struct list_head devices;
+
+/* current active device and partition number */
+static struct mtd_device *current_dev = NULL;
+static u8 current_partnum = 0;
+
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num);
+
+/* command line only routines */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
+static int device_del(struct mtd_device *dev);
+
+/**
+ * Parses a string into a number.  The number stored at ptr is
+ * potentially suffixed with K (for kilobytes, or 1024 bytes),
+ * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
+ * 1073741824).  If the number is suffixed with K, M, or G, then
+ * the return value is the number multiplied by one kilobyte, one
+ * megabyte, or one gigabyte, respectively.
+ *
+ * @param ptr where parse begins
+ * @param retptr output pointer to next char after parse completes (output)
+ * @return resulting unsigned int
+ */
+static unsigned long memsize_parse (const char *const ptr, const char **retptr)
+{
+	unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
+
+	switch (**retptr) {
+		case 'G':
+		case 'g':
+			ret <<= 10;
+		case 'M':
+		case 'm':
+			ret <<= 10;
+		case 'K':
+		case 'k':
+			ret <<= 10;
+			(*retptr)++;
+		default:
+			break;
+	}
+
+	return ret;
+}
+
+/**
+ * Format string describing supplied size. This routine does the opposite job
+ * to memsize_parse(). Size in bytes is converted to string and if possible
+ * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
+ *
+ * Note, that this routine does not check for buffer overflow, it's the caller
+ * who must assure enough space.
+ *
+ * @param buf output buffer
+ * @param size size to be converted to string
+ */
+static void memsize_format(char *buf, u32 size)
+{
+#define SIZE_GB ((u32)1024*1024*1024)
+#define SIZE_MB ((u32)1024*1024)
+#define SIZE_KB ((u32)1024)
+
+	if ((size % SIZE_GB) == 0)
+		sprintf(buf, "%ug", size/SIZE_GB);
+	else if ((size % SIZE_MB) == 0)
+		sprintf(buf, "%um", size/SIZE_MB);
+	else if (size % SIZE_KB == 0)
+		sprintf(buf, "%uk", size/SIZE_KB);
+	else
+		sprintf(buf, "%u", size);
+}
+
+/**
+ * This routine does global indexing of all partitions. Resulting index for
+ * current partition is saved in 'mtddevnum'. Current partition name in
+ * 'mtddevname'.
+ */
+static void index_partitions(void)
+{
+	char buf[16];
+	u16 mtddevnum;
+	struct part_info *part;
+	struct list_head *dentry;
+	struct mtd_device *dev;
+
+	DEBUGF("--- index partitions ---\n");
+
+	if (current_dev) {
+		mtddevnum = 0;
+		list_for_each(dentry, &devices) {
+			dev = list_entry(dentry, struct mtd_device, link);
+			if (dev == current_dev) {
+				mtddevnum += current_partnum;
+				sprintf(buf, "%d", mtddevnum);
+				setenv("mtddevnum", buf);
+				break;
+			}
+			mtddevnum += dev->num_parts;
+		}
+
+		part = mtd_part_info(current_dev, current_partnum);
+		setenv("mtddevname", part->name);
+
+		DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
+	} else {
+		setenv("mtddevnum", NULL);
+		setenv("mtddevname", NULL);
+
+		DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
+	}
+}
+
+/**
+ * Save current device and partition in environment variable 'partition'.
+ */
+static void current_save(void)
+{
+	char buf[16];
+
+	DEBUGF("--- current_save ---\n");
+
+	if (current_dev) {
+		sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
+					current_dev->id->num, current_partnum);
+
+		setenv("partition", buf);
+		strncpy(last_partition, buf, 16);
+
+		DEBUGF("=> partition %s\n", buf);
+	} else {
+		setenv("partition", NULL);
+		last_partition[0] = '\0';
+
+		DEBUGF("=> partition NULL\n");
+	}
+	index_partitions();
+}
+
+/**
+ * Performs sanity check for supplied NOR flash partition. Table of existing
+ * NOR flash devices is searched and partition device is located. Alignment
+ * with the granularity of NOR flash sectors is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_nor(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_CMD_FLASH)
+	/* info for FLASH chips */
+	extern flash_info_t flash_info[];
+	flash_info_t *flash;
+	int offset_aligned;
+	u32 end_offset, sector_size = 0;
+	int i;
+
+	flash = &flash_info[id->num];
+
+	/* size of last sector */
+	part->sector_size = flash->size -
+		(flash->start[flash->sector_count-1] - flash->start[0]);
+
+	offset_aligned = 0;
+	for (i = 0; i < flash->sector_count; i++) {
+		if ((flash->start[i] - flash->start[0]) == part->offset) {
+			offset_aligned = 1;
+			break;
+		}
+	}
+	if (offset_aligned == 0) {
+		printf("%s%d: partition (%s) start offset alignment incorrect\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	end_offset = part->offset + part->size;
+	offset_aligned = 0;
+	for (i = 0; i < flash->sector_count; i++) {
+		if (i) {
+			sector_size = flash->start[i] - flash->start[i-1];
+			if (part->sector_size < sector_size)
+				part->sector_size = sector_size;
+		}
+		if ((flash->start[i] - flash->start[0]) == end_offset)
+			offset_aligned = 1;
+	}
+
+	if (offset_aligned || flash->size == end_offset)
+		return 0;
+
+	printf("%s%d: partition (%s) size alignment incorrect\n",
+			MTD_DEV_TYPE(id->type), id->num, part->name);
+#endif
+	return 1;
+}
+
+/**
+ * Performs sanity check for supplied NAND flash partition. Table of existing
+ * NAND flash devices is searched and partition device is located. Alignment
+ * with the granularity of nand erasesize is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_nand(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+	/* info for NAND chips */
+	nand_info_t *nand;
+
+	nand = &nand_info[id->num];
+
+	part->sector_size = nand->erasesize;
+
+	if ((unsigned long)(part->offset) % nand->erasesize) {
+		printf("%s%d: partition (%s) start offset alignment incorrect\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	if (part->size % nand->erasesize) {
+		printf("%s%d: partition (%s) size alignment incorrect\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	return 0;
+#else
+	return 1;
+#endif
+}
+
+/**
+ * Performs sanity check for supplied OneNAND flash partition.
+ * Table of existing OneNAND flash devices is searched and partition device
+ * is located. Alignment with the granularity of nand erasesize is verified.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate_onenand(struct mtdids *id, struct part_info *part)
+{
+#if defined(CONFIG_CMD_ONENAND)
+	/* info for OneNAND chips */
+	struct mtd_info *mtd;
+
+	mtd = &onenand_mtd;
+
+	part->sector_size = mtd->erasesize;
+
+	if ((unsigned long)(part->offset) % mtd->erasesize) {
+		printf("%s%d: partition (%s) start offset"
+			"alignment incorrect\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	if (part->size % mtd->erasesize) {
+		printf("%s%d: partition (%s) size alignment incorrect\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	return 0;
+#else
+	return 1;
+#endif
+}
+
+
+/**
+ * Performs sanity check for supplied partition. Offset and size are verified
+ * to be within valid range. Partition type is checked and either
+ * parts_validate_nor() or parts_validate_nand() is called with the argument
+ * of part.
+ *
+ * @param id of the parent device
+ * @param part partition to validate
+ * @return 0 if partition is valid, 1 otherwise
+ */
+static int part_validate(struct mtdids *id, struct part_info *part)
+{
+	if (part->size == SIZE_REMAINING)
+		part->size = id->size - part->offset;
+
+	if (part->offset > id->size) {
+		printf("%s: offset %08x beyond flash size %08x\n",
+				id->mtd_id, part->offset, id->size);
+		return 1;
+	}
+
+	if ((part->offset + part->size) <= part->offset) {
+		printf("%s%d: partition (%s) size too big\n",
+				MTD_DEV_TYPE(id->type), id->num, part->name);
+		return 1;
+	}
+
+	if (part->offset + part->size > id->size) {
+		printf("%s: partitioning exceeds flash size\n", id->mtd_id);
+		return 1;
+	}
+
+	if (id->type == MTD_DEV_TYPE_NAND)
+		return part_validate_nand(id, part);
+	else if (id->type == MTD_DEV_TYPE_NOR)
+		return part_validate_nor(id, part);
+	else if (id->type == MTD_DEV_TYPE_ONENAND)
+		return part_validate_onenand(id, part);
+	else
+		DEBUGF("part_validate: invalid dev type\n");
+
+	return 1;
+}
+
+/**
+ * Delete selected partition from the partion list of the specified device.
+ *
+ * @param dev device to delete partition from
+ * @param part partition to delete
+ * @return 0 on success, 1 otherwise
+ */
+static int part_del(struct mtd_device *dev, struct part_info *part)
+{
+	u8 current_save_needed = 0;
+
+	/* if there is only one partition, remove whole device */
+	if (dev->num_parts == 1)
+		return device_del(dev);
+
+	/* otherwise just delete this partition */
+
+	if (dev == current_dev) {
+		/* we are modyfing partitions for the current device,
+		 * update current */
+		struct part_info *curr_pi;
+		curr_pi = mtd_part_info(current_dev, current_partnum);
+
+		if (curr_pi) {
+			if (curr_pi == part) {
+				printf("current partition deleted, resetting current to 0\n");
+				current_partnum = 0;
+			} else if (part->offset <= curr_pi->offset) {
+				current_partnum--;
+			}
+			current_save_needed = 1;
+		}
+	}
+
+#ifdef CONFIG_NAND_LEGACY
+	jffs2_free_cache(part);
+#endif
+	list_del(&part->link);
+	free(part);
+	dev->num_parts--;
+
+	if (current_save_needed > 0)
+		current_save();
+	else
+		index_partitions();
+
+	return 0;
+}
+
+/**
+ * Delete all partitions from parts head list, free memory.
+ *
+ * @param head list of partitions to delete
+ */
+static void part_delall(struct list_head *head)
+{
+	struct list_head *entry, *n;
+	struct part_info *part_tmp;
+
+	/* clean tmp_list and free allocated memory */
+	list_for_each_safe(entry, n, head) {
+		part_tmp = list_entry(entry, struct part_info, link);
+
+#ifdef CONFIG_NAND_LEGACY
+		jffs2_free_cache(part_tmp);
+#endif
+		list_del(entry);
+		free(part_tmp);
+	}
+}
+
+/**
+ * Add new partition to the supplied partition list. Make sure partitions are
+ * sorted by offset in ascending order.
+ *
+ * @param head list this partition is to be added to
+ * @param new partition to be added
+ */
+static int part_sort_add(struct mtd_device *dev, struct part_info *part)
+{
+	struct list_head *entry;
+	struct part_info *new_pi, *curr_pi;
+
+	/* link partition to parrent dev */
+	part->dev = dev;
+
+	if (list_empty(&dev->parts)) {
+		DEBUGF("part_sort_add: list empty\n");
+		list_add(&part->link, &dev->parts);
+		dev->num_parts++;
+		index_partitions();
+		return 0;
+	}
+
+	new_pi = list_entry(&part->link, struct part_info, link);
+
+	/* get current partition info if we are updating current device */
+	curr_pi = NULL;
+	if (dev == current_dev)
+		curr_pi = mtd_part_info(current_dev, current_partnum);
+
+	list_for_each(entry, &dev->parts) {
+		struct part_info *pi;
+
+		pi = list_entry(entry, struct part_info, link);
+
+		/* be compliant with kernel cmdline, allow only one partition at offset zero */
+		if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
+			printf("cannot add second partition at offset 0\n");
+			return 1;
+		}
+
+		if (new_pi->offset <= pi->offset) {
+			list_add_tail(&part->link, entry);
+			dev->num_parts++;
+
+			if (curr_pi && (pi->offset <= curr_pi->offset)) {
+				/* we are modyfing partitions for the current
+				 * device, update current */
+				current_partnum++;
+				current_save();
+			} else {
+				index_partitions();
+			}
+			return 0;
+		}
+	}
+
+	list_add_tail(&part->link, &dev->parts);
+	dev->num_parts++;
+	index_partitions();
+	return 0;
+}
+
+/**
+ * Add provided partition to the partition list of a given device.
+ *
+ * @param dev device to which partition is added
+ * @param part partition to be added
+ * @return 0 on success, 1 otherwise
+ */
+static int part_add(struct mtd_device *dev, struct part_info *part)
+{
+	/* verify alignment and size */
+	if (part_validate(dev->id, part) != 0)
+		return 1;
+
+	/* partition is ok, add it to the list */
+	if (part_sort_add(dev, part) != 0)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * Parse one partition definition, allocate memory and return pointer to this
+ * location in retpart.
+ *
+ * @param partdef pointer to the partition definition string i.e. <part-def>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retpart pointer to the allocated partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
+{
+	struct part_info *part;
+	unsigned long size;
+	unsigned long offset;
+	const char *name;
+	int name_len;
+	unsigned int mask_flags;
+	const char *p;
+
+	p = partdef;
+	*retpart = NULL;
+	*ret = NULL;
+
+	/* fetch the partition size */
+	if (*p == '-') {
+		/* assign all remaining space to this partition */
+		DEBUGF("'-': remaining size assigned\n");
+		size = SIZE_REMAINING;
+		p++;
+	} else {
+		size = memsize_parse(p, &p);
+		if (size < MIN_PART_SIZE) {
+			printf("partition size too small (%lx)\n", size);
+			return 1;
+		}
+	}
+
+	/* check for offset */
+	offset = OFFSET_NOT_SPECIFIED;
+	if (*p == '@') {
+		p++;
+		offset = memsize_parse(p, &p);
+	}
+
+	/* now look for the name */
+	if (*p == '(') {
+		name = ++p;
+		if ((p = strchr(name, ')')) == NULL) {
+			printf("no closing ) found in partition name\n");
+			return 1;
+		}
+		name_len = p - name + 1;
+		if ((name_len - 1) == 0) {
+			printf("empty partition name\n");
+			return 1;
+		}
+		p++;
+	} else {
+		/* 0x00000000@0x00000000 */
+		name_len = 22;
+		name = NULL;
+	}
+
+	/* test for options */
+	mask_flags = 0;
+	if (strncmp(p, "ro", 2) == 0) {
+		mask_flags |= MTD_WRITEABLE_CMD;
+		p += 2;
+	}
+
+	/* check for next partition definition */
+	if (*p == ',') {
+		if (size == SIZE_REMAINING) {
+			*ret = NULL;
+			printf("no partitions allowed after a fill-up partition\n");
+			return 1;
+		}
+		*ret = ++p;
+	} else if ((*p == ';') || (*p == '\0')) {
+		*ret = p;
+	} else {
+		printf("unexpected character '%c' at the end of partition\n", *p);
+		*ret = NULL;
+		return 1;
+	}
+
+	/*  allocate memory */
+	part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
+	if (!part) {
+		printf("out of memory\n");
+		return 1;
+	}
+	memset(part, 0, sizeof(struct part_info) + name_len);
+	part->size = size;
+	part->offset = offset;
+	part->mask_flags = mask_flags;
+	part->name = (char *)(part + 1);
+
+	if (name) {
+		/* copy user provided name */
+		strncpy(part->name, name, name_len - 1);
+		part->auto_name = 0;
+	} else {
+		/* auto generated name in form of size@offset */
+		sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
+		part->auto_name = 1;
+	}
+
+	part->name[name_len - 1] = '\0';
+	INIT_LIST_HEAD(&part->link);
+
+	DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
+			part->name, part->size,
+			part->offset, part->mask_flags);
+
+	*retpart = part;
+	return 0;
+}
+
+/**
+ * Check device number to be within valid range for given device type.
+ *
+ * @param dev device to validate
+ * @return 0 if device is valid, 1 otherwise
+ */
+int mtd_device_validate(u8 type, u8 num, u32 *size)
+{
+	if (type == MTD_DEV_TYPE_NOR) {
+#if defined(CONFIG_CMD_FLASH)
+		if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
+			extern flash_info_t flash_info[];
+			*size = flash_info[num].size;
+
+			return 0;
+		}
+
+		printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
+				MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
+#else
+		printf("support for FLASH devices not present\n");
+#endif
+	} else if (type == MTD_DEV_TYPE_NAND) {
+#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
+		if (num < CONFIG_SYS_MAX_NAND_DEVICE) {
+#ifndef CONFIG_NAND_LEGACY
+			*size = nand_info[num].size;
+#else
+			extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE];
+			*size = nand_dev_desc[num].totlen;
+#endif
+			return 0;
+		}
+
+		printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
+				MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
+#else
+		printf("support for NAND devices not present\n");
+#endif
+	} else if (type == MTD_DEV_TYPE_ONENAND) {
+#if defined(CONFIG_CMD_ONENAND)
+		*size = onenand_mtd.size;
+		return 0;
+#else
+		printf("support for OneNAND devices not present\n");
+#endif
+	} else
+		printf("Unknown defice type %d\n", type);
+
+	return 1;
+}
+
+/**
+ * Delete all mtd devices from a supplied devices list, free memory allocated for
+ * each device and delete all device partitions.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int device_delall(struct list_head *head)
+{
+	struct list_head *entry, *n;
+	struct mtd_device *dev_tmp;
+
+	/* clean devices list */
+	list_for_each_safe(entry, n, head) {
+		dev_tmp = list_entry(entry, struct mtd_device, link);
+		list_del(entry);
+		part_delall(&dev_tmp->parts);
+		free(dev_tmp);
+	}
+	INIT_LIST_HEAD(&devices);
+
+	return 0;
+}
+
+/**
+ * If provided device exists it's partitions are deleted, device is removed
+ * from device list and device memory is freed.
+ *
+ * @param dev device to be deleted
+ * @return 0 on success, 1 otherwise
+ */
+static int device_del(struct mtd_device *dev)
+{
+	part_delall(&dev->parts);
+	list_del(&dev->link);
+	free(dev);
+
+	if (dev == current_dev) {
+		/* we just deleted current device */
+		if (list_empty(&devices)) {
+			current_dev = NULL;
+		} else {
+			/* reset first partition from first dev from the
+			 * devices list as current */
+			current_dev = list_entry(devices.next, struct mtd_device, link);
+			current_partnum = 0;
+		}
+		current_save();
+		return 0;
+	}
+
+	index_partitions();
+	return 0;
+}
+
+/**
+ * Search global device list and return pointer to the device of type and num
+ * specified.
+ *
+ * @param type device type
+ * @param num device number
+ * @return NULL if requested device does not exist
+ */
+static struct mtd_device* device_find(u8 type, u8 num)
+{
+	struct list_head *entry;
+	struct mtd_device *dev_tmp;
+
+	list_for_each(entry, &devices) {
+		dev_tmp = list_entry(entry, struct mtd_device, link);
+
+		if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
+			return dev_tmp;
+	}
+
+	return NULL;
+}
+
+/**
+ * Add specified device to the global device list.
+ *
+ * @param dev device to be added
+ */
+static void device_add(struct mtd_device *dev)
+{
+	u8 current_save_needed = 0;
+
+	if (list_empty(&devices)) {
+		current_dev = dev;
+		current_partnum = 0;
+		current_save_needed = 1;
+	}
+
+	list_add_tail(&dev->link, &devices);
+
+	if (current_save_needed > 0)
+		current_save();
+	else
+		index_partitions();
+}
+
+/**
+ * Parse device type, name and mtd-id. If syntax is ok allocate memory and
+ * return pointer to the device structure.
+ *
+ * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
+ * @param ret output pointer to next char after parse completes (output)
+ * @param retdev pointer to the allocated device (output)
+ * @return 0 on success, 1 otherwise
+ */
+static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
+{
+	struct mtd_device *dev;
+	struct part_info *part;
+	struct mtdids *id;
+	const char *mtd_id;
+	unsigned int mtd_id_len;
+	const char *p, *pend;
+	LIST_HEAD(tmp_list);
+	struct list_head *entry, *n;
+	u16 num_parts;
+	u32 offset;
+	int err = 1;
+
+	p = mtd_dev;
+	*retdev = NULL;
+	*ret = NULL;
+
+	DEBUGF("===device_parse===\n");
+
+	/* fetch <mtd-id> */
+	mtd_id = p;
+	if (!(p = strchr(mtd_id, ':'))) {
+		printf("no <mtd-id> identifier\n");
+		return 1;
+	}
+	mtd_id_len = p - mtd_id + 1;
+	p++;
+
+	/* verify if we have a valid device specified */
+	if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
+		printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
+		return 1;
+	}
+
+	DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
+			id->type, MTD_DEV_TYPE(id->type),
+			id->num, id->mtd_id);
+	pend = strchr(p, ';');
+	DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
+
+
+	/* parse partitions */
+	num_parts = 0;
+
+	offset = 0;
+	if ((dev = device_find(id->type, id->num)) != NULL) {
+		/* if device already exists start at the end of the last partition */
+		part = list_entry(dev->parts.prev, struct part_info, link);
+		offset = part->offset + part->size;
+	}
+
+	while (p && (*p != '\0') && (*p != ';')) {
+		err = 1;
+		if ((part_parse(p, &p, &part) != 0) || (!part))
+			break;
+
+		/* calculate offset when not specified */
+		if (part->offset == OFFSET_NOT_SPECIFIED)
+			part->offset = offset;
+		else
+			offset = part->offset;
+
+		/* verify alignment and size */
+		if (part_validate(id, part) != 0)
+			break;
+
+		offset += part->size;
+
+		/* partition is ok, add it to the list */
+		list_add_tail(&part->link, &tmp_list);
+		num_parts++;
+		err = 0;
+	}
+	if (err == 1) {
+		part_delall(&tmp_list);
+		return 1;
+	}
+
+	if (num_parts == 0) {
+		printf("no partitions for device %s%d (%s)\n",
+				MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
+		return 1;
+	}
+
+	DEBUGF("\ntotal partitions: %d\n", num_parts);
+
+	/* check for next device presence */
+	if (p) {
+		if (*p == ';') {
+			*ret = ++p;
+		} else if (*p == '\0') {
+			*ret = p;
+		} else {
+			printf("unexpected character '%c' at the end of device\n", *p);
+			*ret = NULL;
+			return 1;
+		}
+	}
+
+	/* allocate memory for mtd_device structure */
+	if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
+		printf("out of memory\n");
+		return 1;
+	}
+	memset(dev, 0, sizeof(struct mtd_device));
+	dev->id = id;
+	dev->num_parts = 0; /* part_sort_add increments num_parts */
+	INIT_LIST_HEAD(&dev->parts);
+	INIT_LIST_HEAD(&dev->link);
+
+	/* move partitions from tmp_list to dev->parts */
+	list_for_each_safe(entry, n, &tmp_list) {
+		part = list_entry(entry, struct part_info, link);
+		list_del(entry);
+		if (part_sort_add(dev, part) != 0) {
+			device_del(dev);
+			return 1;
+		}
+	}
+
+	*retdev = dev;
+
+	DEBUGF("===\n\n");
+	return 0;
+}
+
+/**
+ * Initialize global device list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int mtd_devices_init(void)
+{
+	last_parts[0] = '\0';
+	current_dev = NULL;
+	current_save();
+
+	return device_delall(&devices);
+}
+
+/*
+ * Search global mtdids list and find id of requested type and number.
+ *
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find(u8 type, u8 num)
+{
+	struct list_head *entry;
+	struct mtdids *id;
+
+	list_for_each(entry, &mtdids) {
+		id = list_entry(entry, struct mtdids, link);
+
+		if ((id->type == type) && (id->num == num))
+			return id;
+	}
+
+	return NULL;
+}
+
+/**
+ * Search global mtdids list and find id of a requested mtd_id.
+ *
+ * Note: first argument is not null terminated.
+ *
+ * @param mtd_id string containing requested mtd_id
+ * @param mtd_id_len length of supplied mtd_id
+ * @return pointer to the id if it exists, NULL otherwise
+ */
+static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
+{
+	struct list_head *entry;
+	struct mtdids *id;
+
+	DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
+			mtd_id_len, mtd_id, mtd_id_len);
+
+	list_for_each(entry, &mtdids) {
+		id = list_entry(entry, struct mtdids, link);
+
+		DEBUGF("entry: '%s' (len = %d)\n",
+				id->mtd_id, strlen(id->mtd_id));
+
+		if (mtd_id_len != strlen(id->mtd_id))
+			continue;
+		if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
+			return id;
+	}
+
+	return NULL;
+}
+
+/**
+ * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
+ * return device type and number.
+ *
+ * @param id string describing device id
+ * @param ret_id output pointer to next char after parse completes (output)
+ * @param dev_type parsed device type (output)
+ * @param dev_num parsed device number (output)
+ * @return 0 on success, 1 otherwise
+ */
+int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
+{
+	const char *p = id;
+
+	*dev_type = 0;
+	if (strncmp(p, "nand", 4) == 0) {
+		*dev_type = MTD_DEV_TYPE_NAND;
+		p += 4;
+	} else if (strncmp(p, "nor", 3) == 0) {
+		*dev_type = MTD_DEV_TYPE_NOR;
+		p += 3;
+	} else if (strncmp(p, "onenand", 7) == 0) {
+		*dev_type = MTD_DEV_TYPE_ONENAND;
+		p += 7;
+	} else {
+		printf("incorrect device type in %s\n", id);
+		return 1;
+	}
+
+	if (!isdigit(*p)) {
+		printf("incorrect device number in %s\n", id);
+		return 1;
+	}
+
+	*dev_num = simple_strtoul(p, (char **)&p, 0);
+	if (ret_id)
+		*ret_id = p;
+	return 0;
+}
+
+/**
+ * Process all devices and generate corresponding mtdparts string describing
+ * all partitions on all devices.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts(char *buf, u32 buflen)
+{
+	struct list_head *pentry, *dentry;
+	struct mtd_device *dev;
+	struct part_info *part, *prev_part;
+	char *p = buf;
+	char tmpbuf[32];
+	u32 size, offset, len, part_cnt;
+	u32 maxlen = buflen - 1;
+
+	DEBUGF("--- generate_mtdparts ---\n");
+
+	if (list_empty(&devices)) {
+		buf[0] = '\0';
+		return 0;
+	}
+
+	sprintf(p, "mtdparts=");
+	p += 9;
+
+	list_for_each(dentry, &devices) {
+		dev = list_entry(dentry, struct mtd_device, link);
+
+		/* copy mtd_id */
+		len = strlen(dev->id->mtd_id) + 1;
+		if (len > maxlen)
+			goto cleanup;
+		memcpy(p, dev->id->mtd_id, len - 1);
+		p += len - 1;
+		*(p++) = ':';
+		maxlen -= len;
+
+		/* format partitions */
+		prev_part = NULL;
+		part_cnt = 0;
+		list_for_each(pentry, &dev->parts) {
+			part = list_entry(pentry, struct part_info, link);
+			size = part->size;
+			offset = part->offset;
+			part_cnt++;
+
+			/* partition size */
+			memsize_format(tmpbuf, size);
+			len = strlen(tmpbuf);
+			if (len > maxlen)
+				goto cleanup;
+			memcpy(p, tmpbuf, len);
+			p += len;
+			maxlen -= len;
+
+
+			/* add offset only when there is a gap between
+			 * partitions */
+			if ((!prev_part && (offset != 0)) ||
+					(prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
+
+				memsize_format(tmpbuf, offset);
+				len = strlen(tmpbuf) + 1;
+				if (len > maxlen)
+					goto cleanup;
+				*(p++) = '@';
+				memcpy(p, tmpbuf, len - 1);
+				p += len - 1;
+				maxlen -= len;
+			}
+
+			/* copy name only if user supplied */
+			if(!part->auto_name) {
+				len = strlen(part->name) + 2;
+				if (len > maxlen)
+					goto cleanup;
+
+				*(p++) = '(';
+				memcpy(p, part->name, len - 2);
+				p += len - 2;
+				*(p++) = ')';
+				maxlen -= len;
+			}
+
+			/* ro mask flag */
+			if (part->mask_flags && MTD_WRITEABLE_CMD) {
+				len = 2;
+				if (len > maxlen)
+					goto cleanup;
+				*(p++) = 'r';
+				*(p++) = 'o';
+				maxlen -= 2;
+			}
+
+			/* print ',' separator if there are other partitions
+			 * following */
+			if (dev->num_parts > part_cnt) {
+				if (1 > maxlen)
+					goto cleanup;
+				*(p++) = ',';
+				maxlen--;
+			}
+			prev_part = part;
+		}
+		/* print ';' separator if there are other devices following */
+		if (dentry->next != &devices) {
+			if (1 > maxlen)
+				goto cleanup;
+			*(p++) = ';';
+			maxlen--;
+		}
+	}
+
+	/* we still have at least one char left, as we decremented maxlen at
+	 * the begining */
+	*p = '\0';
+
+	return 0;
+
+cleanup:
+	last_parts[0] = '\0';
+	return 1;
+}
+
+/**
+ * Call generate_mtdparts to process all devices and generate corresponding
+ * mtdparts string, save it in mtdparts environment variable.
+ *
+ * @param buf output buffer holding generated mtdparts string (output)
+ * @param buflen buffer size
+ * @return 0 on success, 1 otherwise
+ */
+static int generate_mtdparts_save(char *buf, u32 buflen)
+{
+	int ret;
+
+	ret = generate_mtdparts(buf, buflen);
+
+	if ((buf[0] != '\0') && (ret == 0))
+		setenv("mtdparts", buf);
+	else
+		setenv("mtdparts", NULL);
+
+	return ret;
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+	struct list_head *dentry, *pentry;
+	struct part_info *part;
+	struct mtd_device *dev;
+	int part_num;
+
+	DEBUGF("\n---list_partitions---\n");
+	list_for_each(dentry, &devices) {
+		dev = list_entry(dentry, struct mtd_device, link);
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
+
+		/* list partitions for given device */
+		part_num = 0;
+		list_for_each(pentry, &dev->parts) {
+			part = list_entry(pentry, struct part_info, link);
+			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					part->offset, part->mask_flags);
+
+			part_num++;
+		}
+	}
+	if (list_empty(&devices))
+		printf("no partitions defined\n");
+
+	/* current_dev is not NULL only when we have non empty device list */
+	if (current_dev) {
+		part = mtd_part_info(current_dev, current_partnum);
+		if (part) {
+			printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
+					MTD_DEV_TYPE(current_dev->id->type),
+					current_dev->id->num, current_partnum,
+					part->name, part->size, part->offset);
+		} else {
+			printf("could not get current partition info\n\n");
+		}
+	}
+
+	printf("\ndefaults:\n");
+	printf("mtdids  : %s\n", mtdids_default);
+	printf("mtdparts: %s\n", mtdparts_default);
+}
+
+/**
+ * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
+ * corresponding device and verify partition number.
+ *
+ * @param id string describing device and partition or partition name
+ * @param dev pointer to the requested device (output)
+ * @param part_num verified partition number (output)
+ * @param part pointer to requested partition (output)
+ * @return 0 on success, 1 otherwise
+ */
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+		u8 *part_num, struct part_info **part)
+{
+	struct list_head *dentry, *pentry;
+	u8 type, dnum, pnum;
+	const char *p;
+
+	DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
+
+	list_for_each(dentry, &devices) {
+		*part_num = 0;
+		*dev = list_entry(dentry, struct mtd_device, link);
+		list_for_each(pentry, &(*dev)->parts) {
+			*part = list_entry(pentry, struct part_info, link);
+			if (strcmp((*part)->name, id) == 0)
+				return 0;
+			(*part_num)++;
+		}
+	}
+
+	p = id;
+	*dev = NULL;
+	*part = NULL;
+	*part_num = 0;
+
+	if (mtd_id_parse(p, &p, &type, &dnum) != 0)
+		return 1;
+
+	if ((*p++ != ',') || (*p == '\0')) {
+		printf("no partition number specified\n");
+		return 1;
+	}
+	pnum = simple_strtoul(p, (char **)&p, 0);
+	if (*p != '\0') {
+		printf("unexpected trailing character '%c'\n", *p);
+		return 1;
+	}
+
+	if ((*dev = device_find(type, dnum)) == NULL) {
+		printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
+		return 1;
+	}
+
+	if ((*part = mtd_part_info(*dev, pnum)) == NULL) {
+		printf("no such partition\n");
+		*dev = NULL;
+		return 1;
+	}
+
+	*part_num = pnum;
+
+	return 0;
+}
+
+/**
+ * Find and delete partition. For partition id format see find_dev_and_part().
+ *
+ * @param id string describing device and partition
+ * @return 0 on success, 1 otherwise
+ */
+static int delete_partition(const char *id)
+{
+	u8 pnum;
+	struct mtd_device *dev;
+	struct part_info *part;
+
+	if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
+
+		DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
+				part->name, part->size, part->offset);
+
+		if (part_del(dev, part) != 0)
+			return 1;
+
+		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+			printf("generated mtdparts too long, reseting to null\n");
+			return 1;
+		}
+		return 0;
+	}
+
+	printf("partition %s not found\n", id);
+	return 1;
+}
+
+/**
+ * Accept character string describing mtd partitions and call device_parse()
+ * for each entry. Add created devices to the global devices list.
+ *
+ * @param mtdparts string specifing mtd partitions
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdparts(const char *const mtdparts)
+{
+	const char *p = mtdparts;
+	struct mtd_device *dev;
+	int err = 1;
+
+	DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
+
+	/* delete all devices and partitions */
+	if (mtd_devices_init() != 0) {
+		printf("could not initialise device list\n");
+		return err;
+	}
+
+	/* re-read 'mtdparts' variable, mtd_devices_init may be updating env */
+	p = getenv("mtdparts");
+
+	if (strncmp(p, "mtdparts=", 9) != 0) {
+		printf("mtdparts variable doesn't start with 'mtdparts='\n");
+		return err;
+	}
+	p += 9;
+
+	while (p && (*p != '\0')) {
+		err = 1;
+		if ((device_parse(p, &p, &dev) != 0) || (!dev))
+			break;
+
+		DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+				dev->id->num, dev->id->mtd_id);
+
+		/* check if parsed device is already on the list */
+		if (device_find(dev->id->type, dev->id->num) != NULL) {
+			printf("device %s%d redefined, please correct mtdparts variable\n",
+					MTD_DEV_TYPE(dev->id->type), dev->id->num);
+			break;
+		}
+
+		list_add_tail(&dev->link, &devices);
+		err = 0;
+	}
+	if (err == 1) {
+		device_delall(&devices);
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse provided string describing mtdids mapping (see file header for mtdids
+ * variable format). Allocate memory for each entry and add all found entries
+ * to the global mtdids list.
+ *
+ * @param ids mapping string
+ * @return 0 on success, 1 otherwise
+ */
+static int parse_mtdids(const char *const ids)
+{
+	const char *p = ids;
+	const char *mtd_id;
+	int mtd_id_len;
+	struct mtdids *id;
+	struct list_head *entry, *n;
+	struct mtdids *id_tmp;
+	u8 type, num;
+	u32 size;
+	int ret = 1;
+
+	DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
+
+	/* clean global mtdids list */
+	list_for_each_safe(entry, n, &mtdids) {
+		id_tmp = list_entry(entry, struct mtdids, link);
+		DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
+		list_del(entry);
+		free(id_tmp);
+	}
+	last_ids[0] = '\0';
+	INIT_LIST_HEAD(&mtdids);
+
+	while(p && (*p != '\0')) {
+
+		ret = 1;
+		/* parse 'nor'|'nand'|'onenand'<dev-num> */
+		if (mtd_id_parse(p, &p, &type, &num) != 0)
+			break;
+
+		if (*p != '=') {
+			printf("mtdids: incorrect <dev-num>\n");
+			break;
+		}
+		p++;
+
+		/* check if requested device exists */
+		if (mtd_device_validate(type, num, &size) != 0)
+			return 1;
+
+		/* locate <mtd-id> */
+		mtd_id = p;
+		if ((p = strchr(mtd_id, ',')) != NULL) {
+			mtd_id_len = p - mtd_id + 1;
+			p++;
+		} else {
+			mtd_id_len = strlen(mtd_id) + 1;
+		}
+		if (mtd_id_len == 0) {
+			printf("mtdids: no <mtd-id> identifier\n");
+			break;
+		}
+
+		/* check if this id is already on the list */
+		int double_entry = 0;
+		list_for_each(entry, &mtdids) {
+			id_tmp = list_entry(entry, struct mtdids, link);
+			if ((id_tmp->type == type) && (id_tmp->num == num)) {
+				double_entry = 1;
+				break;
+			}
+		}
+		if (double_entry) {
+			printf("device id %s%d redefined, please correct mtdids variable\n",
+					MTD_DEV_TYPE(type), num);
+			break;
+		}
+
+		/* allocate mtdids structure */
+		if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
+			printf("out of memory\n");
+			break;
+		}
+		memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
+		id->num = num;
+		id->type = type;
+		id->size = size;
+		id->mtd_id = (char *)(id + 1);
+		strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
+		id->mtd_id[mtd_id_len - 1] = '\0';
+		INIT_LIST_HEAD(&id->link);
+
+		DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
+				MTD_DEV_TYPE(id->type), id->num,
+				id->size, id->mtd_id);
+
+		list_add_tail(&id->link, &mtdids);
+		ret = 0;
+	}
+	if (ret == 1) {
+		/* clean mtdids list and free allocated memory */
+		list_for_each_safe(entry, n, &mtdids) {
+			id_tmp = list_entry(entry, struct mtdids, link);
+			list_del(entry);
+			free(id_tmp);
+		}
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse and initialize global mtdids mapping and create global
+ * device/partition list.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+int mtdparts_init(void)
+{
+	static int initialized = 0;
+	const char *ids, *parts;
+	const char *current_partition;
+	int ids_changed;
+	char tmp_ep[PARTITION_MAXLEN];
+
+	DEBUGF("\n---mtdparts_init---\n");
+	if (!initialized) {
+		INIT_LIST_HEAD(&mtdids);
+		INIT_LIST_HEAD(&devices);
+		memset(last_ids, 0, MTDIDS_MAXLEN);
+		memset(last_parts, 0, MTDPARTS_MAXLEN);
+		memset(last_partition, 0, PARTITION_MAXLEN);
+		initialized = 1;
+	}
+
+	/* get variables */
+	ids = getenv("mtdids");
+	parts = getenv("mtdparts");
+	current_partition = getenv("partition");
+
+	/* save it for later parsing, cannot rely on current partition pointer
+	 * as 'partition' variable may be updated during init */
+	tmp_ep[0] = '\0';
+	if (current_partition)
+		strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
+
+	DEBUGF("last_ids  : %s\n", last_ids);
+	DEBUGF("env_ids   : %s\n", ids);
+	DEBUGF("last_parts: %s\n", last_parts);
+	DEBUGF("env_parts : %s\n\n", parts);
+
+	DEBUGF("last_partition : %s\n", last_partition);
+	DEBUGF("env_partition  : %s\n", current_partition);
+
+	/* if mtdids varible is empty try to use defaults */
+	if (!ids) {
+		if (mtdids_default) {
+			DEBUGF("mtdids variable not defined, using default\n");
+			ids = mtdids_default;
+			setenv("mtdids", (char *)ids);
+		} else {
+			printf("mtdids not defined, no default present\n");
+			return 1;
+		}
+	}
+	if (strlen(ids) > MTDIDS_MAXLEN - 1) {
+		printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
+		return 1;
+	}
+
+	/* do no try to use defaults when mtdparts variable is not defined,
+	 * just check the length */
+	if (!parts)
+		printf("mtdparts variable not set, see 'help mtdparts'\n");
+
+	if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
+		printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
+		return 1;
+	}
+
+	/* check if we have already parsed those mtdids */
+	if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
+		ids_changed = 0;
+	} else {
+		ids_changed = 1;
+
+		if (parse_mtdids(ids) != 0) {
+			mtd_devices_init();
+			return 1;
+		}
+
+		/* ok it's good, save new ids */
+		strncpy(last_ids, ids, MTDIDS_MAXLEN);
+	}
+
+	/* parse partitions if either mtdparts or mtdids were updated */
+	if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
+		if (parse_mtdparts(parts) != 0)
+			return 1;
+
+		if (list_empty(&devices)) {
+			printf("mtdparts_init: no valid partitions\n");
+			return 1;
+		}
+
+		/* ok it's good, save new parts */
+		strncpy(last_parts, parts, MTDPARTS_MAXLEN);
+
+		/* reset first partition from first dev from the list as current */
+		current_dev = list_entry(devices.next, struct mtd_device, link);
+		current_partnum = 0;
+		current_save();
+
+		DEBUGF("mtdparts_init: current_dev  = %s%d, current_partnum = %d\n",
+				MTD_DEV_TYPE(current_dev->id->type),
+				current_dev->id->num, current_partnum);
+	}
+
+	/* mtdparts variable was reset to NULL, delete all devices/partitions */
+	if (!parts && (last_parts[0] != '\0'))
+		return mtd_devices_init();
+
+	/* do not process current partition if mtdparts variable is null */
+	if (!parts)
+		return 0;
+
+	/* is current partition set in environment? if so, use it */
+	if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
+		struct part_info *p;
+		struct mtd_device *cdev;
+		u8 pnum;
+
+		DEBUGF("--- getting current partition: %s\n", tmp_ep);
+
+		if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
+			current_dev = cdev;
+			current_partnum = pnum;
+			current_save();
+		}
+	} else if (getenv("partition") == NULL) {
+		DEBUGF("no partition variable set, setting...\n");
+		current_save();
+	}
+
+	return 0;
+}
+
+/**
+ * Return pointer to the partition of a requested number from a requested
+ * device.
+ *
+ * @param dev device that is to be searched for a partition
+ * @param part_num requested partition number
+ * @return pointer to the part_info, NULL otherwise
+ */
+static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num)
+{
+	struct list_head *entry;
+	struct part_info *part;
+	int num;
+
+	if (!dev)
+		return NULL;
+
+	DEBUGF("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n",
+			part_num, MTD_DEV_TYPE(dev->id->type),
+			dev->id->num, dev->id->mtd_id);
+
+	if (part_num >= dev->num_parts) {
+		printf("invalid partition number %d for device %s%d (%s)\n",
+				part_num, MTD_DEV_TYPE(dev->id->type),
+				dev->id->num, dev->id->mtd_id);
+		return NULL;
+	}
+
+	/* locate partition number, return it */
+	num = 0;
+	list_for_each(entry, &dev->parts) {
+		part = list_entry(entry, struct part_info, link);
+
+		if (part_num == num++) {
+			return part;
+		}
+	}
+
+	return NULL;
+}
+
+/***************************************************/
+/* U-boot commands				   */
+/***************************************************/
+/* command line only */
+/**
+ * Routine implementing u-boot chpart command. Sets new current partition based
+ * on the user supplied partition id. For partition id format see find_dev_and_part().
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+/* command line only */
+	struct mtd_device *dev;
+	struct part_info *part;
+	u8 pnum;
+
+	if (mtdparts_init() !=0)
+		return 1;
+
+	if (argc < 2) {
+		printf("no partition id specified\n");
+		return 1;
+	}
+
+	if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
+		return 1;
+
+	current_dev = dev;
+	current_partnum = pnum;
+	current_save();
+
+	printf("partition changed to %s%d,%d\n",
+			MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
+
+	return 0;
+}
+
+/**
+ * Routine implementing u-boot mtdparts command. Initialize/update default global
+ * partition list and process user partition request (list, add, del).
+ *
+ * @param cmdtp command internal data
+ * @param flag command flag
+ * @param argc number of arguments supplied to the command
+ * @param argv arguments list
+ * @return 0 on success, 1 otherwise
+ */
+int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	if (argc == 2) {
+		if (strcmp(argv[1], "default") == 0) {
+			setenv("mtdids", (char *)mtdids_default);
+			setenv("mtdparts", (char *)mtdparts_default);
+			setenv("partition", NULL);
+
+			mtdparts_init();
+			return 0;
+		} else if (strcmp(argv[1], "delall") == 0) {
+			/* this may be the first run, initialize lists if needed */
+			mtdparts_init();
+
+			setenv("mtdparts", NULL);
+
+			/* mtd_devices_init() calls current_save() */
+			return mtd_devices_init();
+		}
+	}
+
+	/* make sure we are in sync with env variables */
+	if (mtdparts_init() != 0)
+		return 1;
+
+	if (argc == 1) {
+		list_partitions();
+		return 0;
+	}
+
+	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
+	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+#define PART_ADD_DESC_MAXLEN 64
+		char tmpbuf[PART_ADD_DESC_MAXLEN];
+		u8 type, num, len;
+		struct mtd_device *dev;
+		struct mtd_device *dev_tmp;
+		struct mtdids *id;
+		struct part_info *p;
+
+		if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
+			return 1;
+
+		if ((id = id_find(type, num)) == NULL) {
+			printf("no such device %s defined in mtdids variable\n", argv[2]);
+			return 1;
+		}
+
+		len = strlen(id->mtd_id) + 1;	/* 'mtd_id:' */
+		len += strlen(argv[3]);		/* size@offset */
+		len += strlen(argv[4]) + 2;	/* '(' name ')' */
+		if (argv[5] && (strlen(argv[5]) == 2))
+			len += 2;		/* 'ro' */
+
+		if (len >= PART_ADD_DESC_MAXLEN) {
+			printf("too long partition description\n");
+			return 1;
+		}
+		sprintf(tmpbuf, "%s:%s(%s)%s",
+				id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
+		DEBUGF("add tmpbuf: %s\n", tmpbuf);
+
+		if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
+			return 1;
+
+		DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
+				dev->id->num, dev->id->mtd_id);
+
+		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+			device_add(dev);
+		} else {
+			/* merge new partition with existing ones*/
+			p = list_entry(dev->parts.next, struct part_info, link);
+			if (part_add(dev_tmp, p) != 0) {
+				device_del(dev);
+				return 1;
+			}
+		}
+
+		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+			printf("generated mtdparts too long, reseting to null\n");
+			return 1;
+		}
+
+		return 0;
+	}
+
+	/* mtdparts del part-id */
+	if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
+		DEBUGF("del: part-id = %s\n", argv[2]);
+
+		return delete_partition(argv[2]);
+	}
+
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+/***************************************************/
+U_BOOT_CMD(
+	chpart,	2,	0,	do_chpart,
+	"change active partition",
+	"part-id\n"
+	"    - change active partition (e.g. part-id = nand0,1)\n"
+);
+
+U_BOOT_CMD(
+	mtdparts,	6,	0,	do_mtdparts,
+	"define flash/nand partitions",
+	"\n"
+	"    - list partition table\n"
+	"mtdparts delall\n"
+	"    - delete all partitions\n"
+	"mtdparts del part-id\n"
+	"    - delete partition (e.g. part-id = nand0,1)\n"
+	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition\n"
+	"mtdparts default\n"
+	"    - reset partition table to defaults\n\n"
+	"-----\n\n"
+	"this command uses three environment variables:\n\n"
+	"'partition' - keeps current partition identifier\n\n"
+	"partition  := <part-id>\n"
+	"<part-id>  := <dev-id>,part_num\n\n"
+	"'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
+	"mtdids=<idmap>[,<idmap>,...]\n\n"
+	"<idmap>    := <dev-id>=<mtd-id>\n"
+	"<dev-id>   := 'nand'|'nor'|'onenand'<dev-num>\n"
+	"<dev-num>  := mtd device number, 0...\n"
+	"<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
+	"'mtdparts' - partition list\n\n"
+	"mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
+	"<mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]\n"
+	"<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
+	"<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
+	"<size>     := standard linux memsize OR '-' to denote all remaining space\n"
+	"<offset>   := partition start offset within the device\n"
+	"<name>     := '(' NAME ')'\n"
+	"<ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
+);
+/***************************************************/
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 11f9096..04b3200 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -29,7 +29,7 @@
 #include <jffs2/jffs2.h>
 #include <nand.h>
 
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 
 /* parition handling routines */
 int mtdparts_init(void);
@@ -105,7 +105,7 @@
 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
 {
 	int idx = nand_curr_device;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	struct mtd_device *dev;
 	struct part_info *part;
 	u8 pnum;
@@ -153,7 +153,7 @@
 		*size = nand->size - *off;
 	}
 
-#if  defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if  defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 out:
 #endif
 	printf("device %d ", idx);
@@ -502,7 +502,7 @@
 
 	s = strchr(cmd, '.');
 	if (s != NULL &&
-	    (strcmp(s, ".jffs2") && !strcmp(s, ".e") && !strcmp(s, ".i"))) {
+	    (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
 		printf("Unknown nand load suffix '%s'\n", s);
 		show_boot_progress(-53);
 		return 1;
@@ -511,7 +511,7 @@
 	printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
 
 	cnt = nand->writesize;
-	r = nand_read(nand, offset, &cnt, (u_char *) addr);
+	r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
 	if (r) {
 		puts("** Read error\n");
 		show_boot_progress (-56);
@@ -543,8 +543,7 @@
 	}
 	show_boot_progress (57);
 
-	/* FIXME: skip bad blocks */
-	r = nand_read(nand, offset, &cnt, (u_char *) addr);
+	r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
 	if (r) {
 		puts("** Read error\n");
 		show_boot_progress (-58);
@@ -590,7 +589,7 @@
 	char *boot_device = NULL;
 	int idx;
 	ulong addr, offset = 0;
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 	struct mtd_device *dev;
 	struct part_info *part;
 	u8 pnum;
@@ -635,7 +634,7 @@
 		offset = simple_strtoul(argv[3], NULL, 16);
 		break;
 	default:
-#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
 usage:
 #endif
 		cmd_usage(cmdtp);
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 02b18ec..95eebb5 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -75,7 +75,12 @@
 static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
 #define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
+static int env_id = 1;
 
+int get_env_id (void)
+{
+	return env_id;
+}
 /************************************************************************
  * Command interface: print one or all environment variables
  */
@@ -160,6 +165,7 @@
 		return 1;
 	}
 
+	env_id++;
 	/*
 	 * search if variable with this name already exists
 	 */
@@ -277,18 +283,6 @@
 		*++env = '\0';
 	}
 
-#ifdef CONFIG_NET_MULTI
-	if (strncmp(name, "eth", 3) == 0) {
-		char *end;
-		int   num = simple_strtoul(name+3, &end, 10);
-
-		if (strcmp(end, "addr") == 0) {
-			eth_set_enetaddr(num, argv[2]);
-		}
-	}
-#endif
-
-
 	/* Delete only ? */
 	if ((argc < 3) || argv[2] == NULL) {
 		env_crc_update ();
@@ -336,18 +330,8 @@
 	 * entry in the enviornment is changed
 	 */
 
-	if (strcmp(argv[1],"ethaddr") == 0) {
-		char *s = argv[2];	/* always use only one arg */
-		char *e;
-		for (i=0; i<6; ++i) {
-			bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-			if (s) s = (*e) ? e+1 : e;
-		}
-#ifdef CONFIG_NET_MULTI
-		eth_set_enetaddr(0, argv[2]);
-#endif
+	if (strcmp(argv[1],"ethaddr") == 0)
 		return 0;
-	}
 
 	if (strcmp(argv[1],"ipaddr") == 0) {
 		char *s = argv[2];	/* always use only one arg */
diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c
new file mode 100644
index 0000000..b2e0f4f
--- /dev/null
+++ b/common/cmd_ubifs.c
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2008
+ * Stefan Roese, DENX Software Engineering, sr@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
+ *
+ */
+
+
+/*
+ * UBIFS command support
+ */
+
+#undef DEBUG
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+
+static int ubifs_initialized;
+static int ubifs_mounted;
+
+/* Prototypes */
+int ubifs_init(void);
+int ubifs_mount(char *vol_name);
+int ubifs_ls(char *dir_name);
+int ubifs_load(char *filename, u32 addr, u32 size);
+
+int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *vol_name;
+	int ret;
+
+	vol_name = argv[1];
+	debug("Using volume %s\n", vol_name);
+
+	if (ubifs_initialized == 0) {
+		ubifs_init();
+		ubifs_initialized = 1;
+	}
+
+	ret = ubifs_mount(vol_name);
+	if (ret)
+		return -1;
+
+	ubifs_mounted = 1;
+
+	return 0;
+}
+
+int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename = "/";
+	int ret;
+
+	if (!ubifs_mounted) {
+		printf("UBIFS not mounted, use ubifs mount to mount volume first!\n");
+		return -1;
+	}
+
+	if (argc == 2)
+		filename = argv[1];
+	debug("Using filename %s\n", filename);
+
+	ret = ubifs_ls(filename);
+	if (ret)
+		printf("%s not found!\n", filename);
+
+	return ret;
+}
+
+int do_ubifs_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *filename;
+	int ret;
+	u32 addr;
+	u32 size = 0;
+
+	if (!ubifs_mounted) {
+		printf("UBIFS not mounted, use ubifs mount to mount volume first!\n");
+		return -1;
+	}
+
+	if (argc < 3) {
+		printf("Usage:\n%s\n", cmdtp->usage);
+		return -1;
+	}
+
+	addr = simple_strtoul(argv[1], NULL, 16);
+	filename = argv[2];
+
+	if (argc == 4)
+		size = simple_strtoul(argv[3], NULL, 16);
+	debug("Loading file '%s' to address 0x%08x (size %d)\n", filename, addr, size);
+
+	ret = ubifs_load(filename, addr, size);
+	if (ret)
+		printf("%s not found!\n", filename);
+
+	return ret;
+}
+
+U_BOOT_CMD(
+	ubifsmount, 2, 0, do_ubifs_mount,
+	"ubifsmount- mount UBIFS volume\n",
+	"\n");
+
+U_BOOT_CMD(ubifsls, 2, 0, do_ubifs_ls,
+	   "ubifsls - list files in a directory\n",
+	   "[directory]\n"
+	   "    - list files in a 'directory' (default '/')\n");
+
+U_BOOT_CMD(ubifsload, 4, 0, do_ubifs_load,
+	   "ubifsload- load file from an UBIFS filesystem\n",
+	   "<addr> <filename> [bytes]\n"
+	   "    - load file 'filename' to address 'addr'\n");
diff --git a/common/lcd.c b/common/lcd.c
index 2bcdba2..4155170 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -84,7 +84,7 @@
 static void *lcd_logo (void);
 
 
-#if LCD_BPP == LCD_COLOR8
+#if (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16)
 extern void lcd_setcolreg (ushort regno,
 				ushort red, ushort green, ushort blue);
 #endif
@@ -622,19 +622,18 @@
  */
 int lcd_display_bitmap(ulong bmp_image, int x, int y)
 {
-#ifdef CONFIG_ATMEL_LCD
-	uint *cmap;
-#elif !defined(CONFIG_MCC200)
-	ushort *cmap;
+#if !defined(CONFIG_MCC200)
+	ushort *cmap = NULL;
 #endif
+	ushort *cmap_base = NULL;
 	ushort i, j;
 	uchar *fb;
 	bmp_image_t *bmp=(bmp_image_t *)bmp_image;
 	uchar *bmap;
 	ushort padded_line;
-	unsigned long width, height;
+	unsigned long width, height, byte_width;
 	unsigned long pwidth = panel_info.vl_col;
-	unsigned colors,bpix;
+	unsigned colors, bpix, bmp_bpix;
 	unsigned long compression;
 #if defined(CONFIG_PXA250)
 	struct pxafb_info *fbi = &panel_info.pxa;
@@ -647,22 +646,24 @@
 		(bmp->header.signature[1]=='M'))) {
 		printf ("Error: no valid bmp image at %lx\n", bmp_image);
 		return 1;
-}
+	}
 
 	width = le32_to_cpu (bmp->header.width);
 	height = le32_to_cpu (bmp->header.height);
-	colors = 1<<le16_to_cpu (bmp->header.bit_count);
+	bmp_bpix = le16_to_cpu(bmp->header.bit_count);
+	colors = 1 << bmp_bpix;
 	compression = le32_to_cpu (bmp->header.compression);
 
 	bpix = NBITS(panel_info.vl_bpix);
 
-	if ((bpix != 1) && (bpix != 8)) {
-		printf ("Error: %d bit/pixel mode not supported by U-Boot\n",
-			bpix);
+	if ((bpix != 1) && (bpix != 8) && (bpix != 16)) {
+		printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+			bpix, bmp_bpix);
 		return 1;
 	}
 
-	if (bpix != le16_to_cpu(bmp->header.bit_count)) {
+	/* We support displaying 8bpp BMPs on 16bpp LCDs */
+	if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16)) {
 		printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
 			bpix,
 			le16_to_cpu(bmp->header.bit_count));
@@ -674,17 +675,17 @@
 
 #if !defined(CONFIG_MCC200)
 	/* MCC200 LCD doesn't need CMAP, supports 1bpp b&w only */
-	if (bpix==8) {
+	if (bmp_bpix == 8) {
 #if defined(CONFIG_PXA250)
 		cmap = (ushort *)fbi->palette;
 #elif defined(CONFIG_MPC823)
 		cmap = (ushort *)&(cp->lcd_cmap[255*sizeof(ushort)]);
-#elif defined(CONFIG_ATMEL_LCD)
-		cmap = (uint *) (panel_info.mmio + ATMEL_LCDC_LUT(0));
-#else
-# error "Don't know location of color map"
+#elif !defined(CONFIG_ATMEL_LCD)
+		cmap = panel_info.cmap;
 #endif
 
+		cmap_base = cmap;
+
 		/* Set color map */
 		for (i=0; i<colors; ++i) {
 			bmp_color_table_entry_t cte = bmp->color_table[i];
@@ -698,10 +699,10 @@
 #else
 			*cmap = colreg;
 #endif
-#if defined(CONFIG_PXA250)
-			cmap++;
-#elif defined(CONFIG_MPC823)
+#if defined(CONFIG_MPC823)
 			cmap--;
+#else
+			cmap++;
 #endif
 #else /* CONFIG_ATMEL_LCD */
 			lcd_setcolreg(i, cte.red, cte.green, cte.blue);
@@ -738,17 +739,59 @@
 	bmap = (uchar *)bmp + le32_to_cpu (bmp->header.data_offset);
 	fb   = (uchar *) (lcd_base +
 		(y + height - 1) * lcd_line_length + x);
-	for (i = 0; i < height; ++i) {
-		WATCHDOG_RESET();
-		for (j = 0; j < width ; j++)
+
+	switch (bmp_bpix) {
+	case 1: /* pass through */
+	case 8:
+		if (bpix != 16)
+			byte_width = width;
+		else
+			byte_width = width * 2;
+
+		for (i = 0; i < height; ++i) {
+			WATCHDOG_RESET();
+			for (j = 0; j < width; j++) {
+				if (bpix != 16) {
 #if defined(CONFIG_PXA250) || defined(CONFIG_ATMEL_LCD)
-			*(fb++) = *(bmap++);
+					*(fb++) = *(bmap++);
 #elif defined(CONFIG_MPC823) || defined(CONFIG_MCC200)
-			*(fb++)=255-*(bmap++);
+					*(fb++) = 255 - *(bmap++);
 #endif
-		bmap += (width - padded_line);
-		fb   -= (width + lcd_line_length);
-	}
+				} else {
+					*(uint16_t *)fb = cmap_base[*(bmap++)];
+					fb += sizeof(uint16_t) / sizeof(*fb);
+				}
+			}
+			bmap += (width - padded_line);
+			fb   -= (byte_width + lcd_line_length);
+		}
+		break;
+
+#if defined(CONFIG_BMP_16BPP)
+	case 16:
+		for (i = 0; i < height; ++i) {
+			WATCHDOG_RESET();
+			for (j = 0; j < width; j++) {
+#if defined(CONFIG_ATMEL_LCD_BGR555)
+				*(fb++) = ((bmap[0] & 0x1f) << 2) |
+					(bmap[1] & 0x03);
+				*(fb++) = (bmap[0] & 0xe0) |
+					((bmap[1] & 0x7c) >> 2);
+				bmap += 2;
+#else
+				*(fb++) = *(bmap++);
+				*(fb++) = *(bmap++);
+#endif
+			}
+			bmap += (padded_line - width) * 2;
+			fb   -= (width * 2 + lcd_line_length);
+		}
+		break;
+#endif /* CONFIG_BMP_16BPP */
+
+	default:
+		break;
+	};
 
 	return (0);
 }
diff --git a/common/lynxkdi.c b/common/lynxkdi.c
index 5f12b0d..17b0607 100644
--- a/common/lynxkdi.c
+++ b/common/lynxkdi.c
@@ -33,7 +33,7 @@
 	kbd = gd->bd;
 	parms->clock_ref = kbd->bi_busfreq;
 	parms->dramsz = kbd->bi_memsize;
-	memcpy (parms->ethaddr, kbd->bi_enetaddr, 6);
+	eth_getenv_enetaddr("ethaddr", parms->ethaddr);
 	mtspr (SPRN_SPRG2, 0x0020);
 
 	/* Do a simple check for Bluecat so we can pass the
diff --git a/cpu/arm920t/at91rm9200/ether.c b/cpu/arm920t/at91rm9200/ether.c
index f20e070..b00b948 100644
--- a/cpu/arm920t/at91rm9200/ether.c
+++ b/cpu/arm920t/at91rm9200/ether.c
@@ -155,6 +155,7 @@
 {
 	int ret;
 	int i;
+	uchar enetaddr[6];
 
 	p_mac = AT91C_BASE_EMAC;
 
@@ -190,9 +191,10 @@
 	rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
 	rbfp = &rbfdt[0];
 
-	p_mac->EMAC_SA2L = (bd->bi_enetaddr[3] << 24) | (bd->bi_enetaddr[2] << 16)
-			 | (bd->bi_enetaddr[1] <<  8) | (bd->bi_enetaddr[0]);
-	p_mac->EMAC_SA2H = (bd->bi_enetaddr[5] <<  8) | (bd->bi_enetaddr[4]);
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
+			 | (enetaddr[1] <<  8) | (enetaddr[0]);
+	p_mac->EMAC_SA2H = (enetaddr[5] <<  8) | (enetaddr[4]);
 
 	p_mac->EMAC_RBQP = (long) (&rbfdt[0]);
 	p_mac->EMAC_RSR &= ~(AT91C_EMAC_RSR_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
diff --git a/cpu/arm926ejs/at91/u-boot.lds b/cpu/arm926ejs/at91/u-boot.lds
index 4778d1e..ebb1f93 100644
--- a/cpu/arm926ejs/at91/u-boot.lds
+++ b/cpu/arm926ejs/at91/u-boot.lds
@@ -37,7 +37,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/cpu/arm_cortexa8/omap3/sys_info.c b/cpu/arm_cortexa8/omap3/sys_info.c
index 28a1020..b385b91 100644
--- a/cpu/arm_cortexa8/omap3/sys_info.c
+++ b/cpu/arm_cortexa8/omap3/sys_info.c
@@ -36,6 +36,32 @@
 static sdrc_t *sdrc_base = (sdrc_t *)OMAP34XX_SDRC_BASE;
 static ctrl_t *ctrl_base = (ctrl_t *)OMAP34XX_CTRL_BASE;
 
+/*****************************************************************
+ * dieid_num_r(void) - read and set die ID
+ *****************************************************************/
+void dieid_num_r(void)
+{
+	ctrl_id_t *id_base = (ctrl_id_t *)OMAP34XX_ID_L4_IO_BASE;
+	char *uid_s, die_id[34];
+	u32 id[4];
+
+	memset(die_id, 0, sizeof(die_id));
+
+	uid_s = getenv("dieid#");
+
+	if (uid_s == NULL) {
+		id[3] = readl(&id_base->die_id_0);
+		id[2] = readl(&id_base->die_id_1);
+		id[1] = readl(&id_base->die_id_2);
+		id[0] = readl(&id_base->die_id_3);
+		sprintf(die_id, "%08x%08x%08x%08x", id[0], id[1], id[2], id[3]);
+		setenv("dieid#", die_id);
+		uid_s = die_id;
+	}
+
+	printf("Die ID #%s\n", uid_s);
+}
+
 /******************************************
  * get_cpu_type(void) - extract cpu info
  ******************************************/
diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile
index f20675a..e98bd3d 100644
--- a/cpu/i386/Makefile
+++ b/cpu/i386/Makefile
@@ -29,8 +29,7 @@
 LIB	= $(obj)lib$(CPU).a
 
 START	= start.o start16.o resetvec.o
-COBJS	= serial.o interrupts.o cpu.o timer.o sc520.o
-SOBJS	= sc520_asm.o
+COBJS	= serial.o interrupts.o exceptions.o cpu.o
 
 SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c
index b9af5f8..d91e33b 100644
--- a/cpu/i386/cpu.c
+++ b/cpu/i386/cpu.c
@@ -46,6 +46,10 @@
 	     "orl  $0x22, %eax\n" \
 	     "movl %eax, %cr0\n" );
 
+	/* Initialize core interrupt and exception functionality of CPU */
+	cpu_init_interrupts ();
+	cpu_init_exceptions ();
+
 	return 0;
 }
 
diff --git a/cpu/i386/exceptions.c b/cpu/i386/exceptions.c
new file mode 100644
index 0000000..bc3d434
--- /dev/null
+++ b/cpu/i386/exceptions.c
@@ -0,0 +1,229 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * 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 <asm/interrupt.h>
+
+asm (".globl exp_return\n"
+     "exp_return:\n"
+     "     addl  $12, %esp\n"
+     "     pop   %esp\n"
+     "     popa\n"
+     "     iret\n");
+
+char exception_stack[4096];
+
+/*
+ * For detailed description of each exception, refer to:
+ * Intel® 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 1: Basic Architecture
+ * Order Number: 253665-029US, November 2008
+ * Table 6-1. Exceptions and Interrupts
+ */
+DECLARE_EXCEPTION(0, divide_error_entry);
+DECLARE_EXCEPTION(1, debug_entry);
+DECLARE_EXCEPTION(2, nmi_interrupt_entry);
+DECLARE_EXCEPTION(3, breakpoint_entry);
+DECLARE_EXCEPTION(4, overflow_entry);
+DECLARE_EXCEPTION(5, bound_range_exceeded_entry);
+DECLARE_EXCEPTION(6, invalid_opcode_entry);
+DECLARE_EXCEPTION(7, device_not_available_entry);
+DECLARE_EXCEPTION(8, double_fault_entry);
+DECLARE_EXCEPTION(9, coprocessor_segment_overrun_entry);
+DECLARE_EXCEPTION(10, invalid_tss_entry);
+DECLARE_EXCEPTION(11, segment_not_present_entry);
+DECLARE_EXCEPTION(12, stack_segment_fault_entry);
+DECLARE_EXCEPTION(13, general_protection_entry);
+DECLARE_EXCEPTION(14, page_fault_entry);
+DECLARE_EXCEPTION(15, reserved_exception_entry);
+DECLARE_EXCEPTION(16, floating_point_error_entry);
+DECLARE_EXCEPTION(17, alignment_check_entry);
+DECLARE_EXCEPTION(18, machine_check_entry);
+DECLARE_EXCEPTION(19, simd_floating_point_exception_entry);
+DECLARE_EXCEPTION(20, reserved_exception_entry);
+DECLARE_EXCEPTION(21, reserved_exception_entry);
+DECLARE_EXCEPTION(22, reserved_exception_entry);
+DECLARE_EXCEPTION(23, reserved_exception_entry);
+DECLARE_EXCEPTION(24, reserved_exception_entry);
+DECLARE_EXCEPTION(25, reserved_exception_entry);
+DECLARE_EXCEPTION(26, reserved_exception_entry);
+DECLARE_EXCEPTION(27, reserved_exception_entry);
+DECLARE_EXCEPTION(28, reserved_exception_entry);
+DECLARE_EXCEPTION(29, reserved_exception_entry);
+DECLARE_EXCEPTION(30, reserved_exception_entry);
+DECLARE_EXCEPTION(31, reserved_exception_entry);
+
+__isr__ reserved_exception_entry(int cause, int ip, int seg)
+{
+	printf("Reserved Exception %d at %04x:%08x\n", cause, seg, ip);
+}
+
+__isr__ divide_error_entry(int cause, int ip, int seg)
+{
+	printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ debug_entry(int cause, int ip, int seg)
+{
+	printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
+}
+
+__isr__ nmi_interrupt_entry(int cause, int ip, int seg)
+{
+	printf("NMI Interrupt at %04x:%08x\n", seg, ip);
+}
+
+__isr__ breakpoint_entry(int cause, int ip, int seg)
+{
+	printf("Breakpoint at %04x:%08x\n", seg, ip);
+}
+
+__isr__ overflow_entry(int cause, int ip, int seg)
+{
+	printf("Overflow at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ bound_range_exceeded_entry(int cause, int ip, int seg)
+{
+	printf("BOUND Range Exceeded at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ invalid_opcode_entry(int cause, int ip, int seg)
+{
+	printf("Invalid Opcode (UnDefined Opcode) at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ device_not_available_entry(int cause, int ip, int seg)
+{
+	printf("Device Not Available (No Math Coprocessor) at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ double_fault_entry(int cause, int ip, int seg)
+{
+	printf("Double fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ coprocessor_segment_overrun_entry(int cause, int ip, int seg)
+{
+	printf("Co-processor segment overrun at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ invalid_tss_entry(int cause, int ip, int seg)
+{
+	printf("Invalid TSS at %04x:%08x\n", seg, ip);
+}
+
+__isr__ segment_not_present_entry(int cause, int ip, int seg)
+{
+	printf("Segment Not Present at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ stack_segment_fault_entry(int cause, int ip, int seg)
+{
+	printf("Stack Segment Fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ general_protection_entry(int cause, int ip, int seg)
+{
+	printf("General Protection at %04x:%08x\n", seg, ip);
+}
+
+__isr__ page_fault_entry(int cause, int ip, int seg)
+{
+	printf("Page fault at %04x:%08x\n", seg, ip);
+	while(1);
+}
+
+__isr__ floating_point_error_entry(int cause, int ip, int seg)
+{
+	printf("Floating-Point Error (Math Fault) at %04x:%08x\n", seg, ip);
+}
+
+__isr__ alignment_check_entry(int cause, int ip, int seg)
+{
+	printf("Alignment check at %04x:%08x\n", seg, ip);
+}
+
+__isr__ machine_check_entry(int cause, int ip, int seg)
+{
+	printf("Machine Check at %04x:%08x\n", seg, ip);
+}
+
+__isr__ simd_floating_point_exception_entry(int cause, int ip, int seg)
+{
+	printf("SIMD Floating-Point Exception at %04x:%08x\n", seg, ip);
+}
+
+int cpu_init_exceptions(void)
+{
+	/* Just in case... */
+	disable_interrupts();
+
+	/* Setup exceptions */
+	set_vector(0x00, exp_0);
+	set_vector(0x01, exp_1);
+	set_vector(0x02, exp_2);
+	set_vector(0x03, exp_3);
+	set_vector(0x04, exp_4);
+	set_vector(0x05, exp_5);
+	set_vector(0x06, exp_6);
+	set_vector(0x07, exp_7);
+	set_vector(0x08, exp_8);
+	set_vector(0x09, exp_9);
+	set_vector(0x0a, exp_10);
+	set_vector(0x0b, exp_11);
+	set_vector(0x0c, exp_12);
+	set_vector(0x0d, exp_13);
+	set_vector(0x0e, exp_14);
+	set_vector(0x0f, exp_15);
+	set_vector(0x10, exp_16);
+	set_vector(0x11, exp_17);
+	set_vector(0x12, exp_18);
+	set_vector(0x13, exp_19);
+	set_vector(0x14, exp_20);
+	set_vector(0x15, exp_21);
+	set_vector(0x16, exp_22);
+	set_vector(0x17, exp_23);
+	set_vector(0x18, exp_24);
+	set_vector(0x19, exp_25);
+	set_vector(0x1a, exp_26);
+	set_vector(0x1b, exp_27);
+	set_vector(0x1c, exp_28);
+	set_vector(0x1d, exp_29);
+	set_vector(0x1e, exp_30);
+	set_vector(0x1f, exp_31);
+
+	/* It is now safe to enable interrupts */
+	enable_interrupts();
+
+	return 0;
+}
diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c
index badb30b..063ea42 100644
--- a/cpu/i386/interrupts.c
+++ b/cpu/i386/interrupts.c
@@ -22,10 +22,6 @@
  */
 
 #include <common.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include <asm/ibmpc.h>
 #include <asm/interrupt.h>
 
 
@@ -41,361 +37,34 @@
 struct idt_entry idt[256];
 
 
-#define MAX_IRQ 16
-
-typedef struct irq_handler {
-	struct irq_handler *next;
-	interrupt_handler_t* isr_func;
-	void *isr_data;
-} irq_handler_t;
-
-#define IRQ_DISABLED   1
-
-typedef struct {
-	irq_handler_t *handler;
-	unsigned long status;
-} irq_desc_t;
-
-static irq_desc_t irq_table[MAX_IRQ];
-
-asm ("irq_return:\n"
+asm (".globl irq_return\n"
+     "irq_return:\n"
      "     addl  $4, %esp\n"
      "     popa\n"
      "     iret\n");
 
-asm ("exp_return:\n"
-     "     addl  $12, %esp\n"
-     "     pop   %esp\n"
-     "     popa\n"
-     "     iret\n");
-
-char exception_stack[4096];
-
-#define DECLARE_INTERRUPT(x) \
-	asm(".globl irq_"#x"\n" \
-		    "irq_"#x":\n" \
-		    "pusha \n" \
-		    "pushl $"#x"\n" \
-		    "pushl $irq_return\n" \
-		    "jmp   do_irq\n"); \
-	void __attribute__ ((regparm(0))) irq_##x(void)
-
-#define DECLARE_EXCEPTION(x, f) \
-	asm(".globl exp_"#x"\n" \
-		    "exp_"#x":\n" \
-		    "pusha \n" \
-		    "movl     %esp, %ebx\n" \
-		    "movl     $exception_stack, %eax\n" \
-		    "movl     %eax, %esp \n" \
-		    "pushl    %ebx\n" \
-		    "movl     32(%esp), %ebx\n" \
-		    "xorl     %edx, %edx\n" \
-		    "movw     36(%esp), %dx\n" \
-		    "pushl    %edx\n" \
-		    "pushl    %ebx\n" \
-		    "pushl    $"#x"\n" \
-		    "pushl    $exp_return\n" \
-		    "jmp      "#f"\n"); \
-	void __attribute__ ((regparm(0))) exp_##x(void)
-
-DECLARE_EXCEPTION(0, divide_exception_entry);      /* Divide exception */
-DECLARE_EXCEPTION(1, debug_exception_entry);       /* Debug exception */
-DECLARE_EXCEPTION(2, nmi_entry);                   /* NMI */
-DECLARE_EXCEPTION(3, unknown_exception_entry);     /* Breakpoint/Coprocessor Error */
-DECLARE_EXCEPTION(4, unknown_exception_entry);     /* Overflow */
-DECLARE_EXCEPTION(5, unknown_exception_entry);     /* Bounds */
-DECLARE_EXCEPTION(6, invalid_instruction_entry);   /* Invalid instruction */
-DECLARE_EXCEPTION(7, unknown_exception_entry);     /* Device not present */
-DECLARE_EXCEPTION(8, double_fault_entry);          /* Double fault */
-DECLARE_EXCEPTION(9, unknown_exception_entry);     /* Co-processor segment overrun */
-DECLARE_EXCEPTION(10, invalid_tss_exception_entry);/* Invalid TSS */
-DECLARE_EXCEPTION(11, seg_fault_entry);            /* Segment not present */
-DECLARE_EXCEPTION(12, stack_fault_entry);          /* Stack overflow */
-DECLARE_EXCEPTION(13, gpf_entry);                  /* GPF */
-DECLARE_EXCEPTION(14, page_fault_entry);           /* PF */
-DECLARE_EXCEPTION(15, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(16, fp_exception_entry);         /* Floating point */
-DECLARE_EXCEPTION(17, alignment_check_entry);      /* alignment check */
-DECLARE_EXCEPTION(18, machine_check_entry);        /* machine check */
-DECLARE_EXCEPTION(19, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(20, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(21, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(22, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(23, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(24, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(25, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(26, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(27, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(28, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(29, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(30, unknown_exception_entry);    /* Reserved */
-DECLARE_EXCEPTION(31, unknown_exception_entry);    /* Reserved */
-
-DECLARE_INTERRUPT(0);
-DECLARE_INTERRUPT(1);
-DECLARE_INTERRUPT(3);
-DECLARE_INTERRUPT(4);
-DECLARE_INTERRUPT(5);
-DECLARE_INTERRUPT(6);
-DECLARE_INTERRUPT(7);
-DECLARE_INTERRUPT(8);
-DECLARE_INTERRUPT(9);
-DECLARE_INTERRUPT(10);
-DECLARE_INTERRUPT(11);
-DECLARE_INTERRUPT(12);
-DECLARE_INTERRUPT(13);
-DECLARE_INTERRUPT(14);
-DECLARE_INTERRUPT(15);
-
 void __attribute__ ((regparm(0))) default_isr(void);
 asm ("default_isr: iret\n");
 
-void disable_irq(int irq)
-{
-	if (irq >= MAX_IRQ) {
-		return;
-	}
-	irq_table[irq].status |= IRQ_DISABLED;
-
-}
-
-void enable_irq(int irq)
-{
-	if (irq >= MAX_IRQ) {
-		return;
-	}
-	irq_table[irq].status &= ~IRQ_DISABLED;
-}
-
-/* masks one specific IRQ in the PIC */
-static void unmask_irq(int irq)
-{
-	int imr_port;
-
-	if (irq >= MAX_IRQ) {
-		return;
-	}
-	if (irq > 7) {
-		imr_port = SLAVE_PIC + IMR;
-	} else {
-		imr_port = MASTER_PIC + IMR;
-	}
-
-	outb(inb(imr_port)&~(1<<(irq&7)), imr_port);
-}
-
-
-/* unmasks one specific IRQ in the PIC */
-static void mask_irq(int irq)
-{
-	int imr_port;
-
-	if (irq >= MAX_IRQ) {
-		return;
-	}
-	if (irq > 7) {
-		imr_port = SLAVE_PIC + IMR;
-	} else {
-		imr_port = MASTER_PIC + IMR;
-	}
-
-	outb(inb(imr_port)|(1<<(irq&7)), imr_port);
-}
-
-
-/* issue a Specific End Of Interrupt instruciton */
-static void specific_eoi(int irq)
-{
-	/* If it is on the slave PIC this have to be performed on
-	 * both the master and the slave PICs */
-	if (irq > 7) {
-		outb(OCW2_SEOI|(irq&7), SLAVE_PIC + OCW2);
-		irq = SEOI_IR2;               /* also do IR2 on master */
-	}
-	outb(OCW2_SEOI|irq, MASTER_PIC + OCW2);
-}
-
-void __attribute__ ((regparm(0))) do_irq(int irq)
-{
-
-	mask_irq(irq);
-
-	if (irq_table[irq].status & IRQ_DISABLED) {
-		unmask_irq(irq);
-		specific_eoi(irq);
-		return;
-	}
-
-
-	if (NULL != irq_table[irq].handler) {
-		irq_handler_t *handler;
-		for (handler = irq_table[irq].handler;
-		     NULL!= handler; handler = handler->next) {
-			handler->isr_func(handler->isr_data);
-		}
-	} else {
-		if ((irq & 7) != 7) {
-			printf("Spurious irq %d\n", irq);
-		}
-	}
-	unmask_irq(irq);
-	specific_eoi(irq);
-}
-
-
-void __attribute__ ((regparm(0))) unknown_exception_entry(int cause, int ip, int seg)
-{
-	printf("Unknown Exception %d at %04x:%08x\n", cause, seg, ip);
-}
-
-void __attribute__ ((regparm(0))) divide_exception_entry(int cause, int ip, int seg)
-{
-	printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) debug_exception_entry(int cause, int ip, int seg)
-{
-	printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) nmi_entry(int cause, int ip, int seg)
-{
-	printf("NMI Interrupt at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) invalid_instruction_entry(int cause, int ip, int seg)
-{
-	printf("Invalid Instruction at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) double_fault_entry(int cause, int ip, int seg)
-{
-	printf("Double fault at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) invalid_tss_exception_entry(int cause, int ip, int seg)
-{
-	printf("Invalid TSS at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) seg_fault_entry(int cause, int ip, int seg)
-{
-	printf("Segmentation fault at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) stack_fault_entry(int cause, int ip, int seg)
-{
-	printf("Stack fault at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) gpf_entry(int cause, int ip, int seg)
-{
-	printf("General protection fault at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) page_fault_entry(int cause, int ip, int seg)
-{
-	printf("Page fault at %04x:%08x\n", seg, ip);
-	while(1);
-}
-
-void __attribute__ ((regparm(0))) fp_exception_entry(int cause, int ip, int seg)
-{
-	printf("Floating point exception at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) alignment_check_entry(int cause, int ip, int seg)
-{
-	printf("Alignment check at %04x:%08x\n", seg, ip);
-}
-
-void __attribute__ ((regparm(0))) machine_check_entry(int cause, int ip, int seg)
-{
-	printf("Machine check exception at %04x:%08x\n", seg, ip);
-}
-
-
-void irq_install_handler(int ino, interrupt_handler_t *func, void *pdata)
-{
-	int status;
-
-	if (ino>MAX_IRQ) {
-		return;
-	}
-
-	if (NULL != irq_table[ino].handler) {
-		return;
-	}
-
-	status = disable_interrupts();
-	irq_table[ino].handler = malloc(sizeof(irq_handler_t));
-	if (NULL == irq_table[ino].handler) {
-		return;
-	}
-
-	memset(irq_table[ino].handler, 0, sizeof(irq_handler_t));
-
-	irq_table[ino].handler->isr_func = func;
-	irq_table[ino].handler->isr_data = pdata;
-	if (status) {
-		enable_interrupts();
-	}
-
-	unmask_irq(ino);
-
-	return;
-}
-
-void irq_free_handler(int ino)
-{
-	int status;
-	if (ino>MAX_IRQ) {
-		return;
-	}
-
-	status = disable_interrupts();
-	mask_irq(ino);
-	if (NULL == irq_table[ino].handler) {
-		return;
-	}
-	free(irq_table[ino].handler);
-	irq_table[ino].handler=NULL;
-	if (status) {
-		enable_interrupts();
-	}
-	return;
-}
-
-
 asm ("idt_ptr:\n"
 	".word	0x800\n" /* size of the table 8*256 bytes */
 	".long	idt\n"	 /* offset */
 	".word	0x18\n");/* data segment */
 
-void set_vector(int intnum, void *routine)
+void set_vector(u8 intnum, void *routine)
 {
-	idt[intnum].base_high = (u16)((u32)(routine)>>16);
-	idt[intnum].base_low = (u16)((u32)(routine)&0xffff);
+	idt[intnum].base_high = (u16)((u32)(routine + gd->reloc_off) >> 16);
+	idt[intnum].base_low = (u16)((u32)(routine + gd->reloc_off) & 0xffff);
 }
 
 
-int interrupt_init(void)
+int cpu_init_interrupts(void)
 {
 	int i;
 
 	/* Just in case... */
 	disable_interrupts();
 
-	/* Initialize the IDT and stuff */
-
-
-	memset(irq_table, 0, sizeof(irq_table));
-
 	/* Setup the IDT */
 	for (i=0;i<256;i++) {
 		idt[i].access = 0x8e;
@@ -406,89 +75,6 @@
 
 	asm ("cs lidt idt_ptr\n");
 
-	/* Setup exceptions */
-	set_vector(0x00, exp_0);
-	set_vector(0x01, exp_1);
-	set_vector(0x02, exp_2);
-	set_vector(0x03, exp_3);
-	set_vector(0x04, exp_4);
-	set_vector(0x05, exp_5);
-	set_vector(0x06, exp_6);
-	set_vector(0x07, exp_7);
-	set_vector(0x08, exp_8);
-	set_vector(0x09, exp_9);
-	set_vector(0x0a, exp_10);
-	set_vector(0x0b, exp_11);
-	set_vector(0x0c, exp_12);
-	set_vector(0x0d, exp_13);
-	set_vector(0x0e, exp_14);
-	set_vector(0x0f, exp_15);
-	set_vector(0x10, exp_16);
-	set_vector(0x11, exp_17);
-	set_vector(0x12, exp_18);
-	set_vector(0x13, exp_19);
-	set_vector(0x14, exp_20);
-	set_vector(0x15, exp_21);
-	set_vector(0x16, exp_22);
-	set_vector(0x17, exp_23);
-	set_vector(0x18, exp_24);
-	set_vector(0x19, exp_25);
-	set_vector(0x1a, exp_26);
-	set_vector(0x1b, exp_27);
-	set_vector(0x1c, exp_28);
-	set_vector(0x1d, exp_29);
-	set_vector(0x1e, exp_30);
-	set_vector(0x1f, exp_31);
-
-
-	/* Setup interrupts */
-	set_vector(0x20, irq_0);
-	set_vector(0x21, irq_1);
-	set_vector(0x23, irq_3);
-	set_vector(0x24, irq_4);
-	set_vector(0x25, irq_5);
-	set_vector(0x26, irq_6);
-	set_vector(0x27, irq_7);
-	set_vector(0x28, irq_8);
-	set_vector(0x29, irq_9);
-	set_vector(0x2a, irq_10);
-	set_vector(0x2b, irq_11);
-	set_vector(0x2c, irq_12);
-	set_vector(0x2d, irq_13);
-	set_vector(0x2e, irq_14);
-	set_vector(0x2f, irq_15);
-	/* vectors 0x30-0x3f are reserved for irq 16-31 */
-
-
-	/* Mask all interrupts */
-	outb(0xff, MASTER_PIC + IMR);
-	outb(0xff, SLAVE_PIC + IMR);
-
-	/* Master PIC */
-	outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
-	outb(0x20, MASTER_PIC + ICW2);          /* Place master PIC interrupts at INT20 */
-	outb(IR2, MASTER_PIC + ICW3);		/* ICW3, One slevc PIC is present */
-	outb(ICW4_PM, MASTER_PIC + ICW4);
-
-	for (i=0;i<8;i++) {
-		outb(OCW2_SEOI|i, MASTER_PIC + OCW2);
-	}
-
-	/* Slave PIC */
-	outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
-	outb(0x28, SLAVE_PIC + ICW2);	        /* Place slave PIC interrupts at INT28 */
-	outb(0x02, SLAVE_PIC + ICW3);		/* Slave ID */
-	outb(ICW4_PM, SLAVE_PIC + ICW4);
-
-	for (i=0;i<8;i++) {
-		outb(OCW2_SEOI|i, SLAVE_PIC + OCW2);
-	}
-
-
-	/* enable cascade interrerupt */
-	outb(0xfb, MASTER_PIC + IMR);
-	outb(0xff, SLAVE_PIC + IMR);
-
 	/* It is now safe to enable interrupts */
 	enable_interrupts();
 
diff --git a/cpu/i386/sc520.c b/cpu/i386/sc520.c
deleted file mode 100644
index b958f8d..0000000
--- a/cpu/i386/sc520.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * (C) Copyright 2002
- * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
- *
- * 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
- */
-
-/* stuff specific for the sc520,
- * but idependent of implementation */
-
-#include <config.h>
-#include <common.h>
-#include <config.h>
-#include <pci.h>
-#ifdef CONFIG_SC520_SSI
-#include <asm/ic/ssi.h>
-#endif
-#include <asm/io.h>
-#include <asm/pci.h>
-#include <asm/ic/sc520.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/*
- * utility functions for boards based on the AMD sc520
- *
- * void write_mmcr_byte(u16 mmcr, u8 data)
- * void write_mmcr_word(u16 mmcr, u16 data)
- * void write_mmcr_long(u16 mmcr, u32 data)
- *
- * u8   read_mmcr_byte(u16 mmcr)
- * u16  read_mmcr_word(u16 mmcr)
- * u32  read_mmcr_long(u16 mmcr)
- *
- * void init_sc520(void)
- * unsigned long init_sc520_dram(void)
- * void pci_sc520_init(struct pci_controller *hose)
- *
- * void reset_timer(void)
- * ulong get_timer(ulong base)
- * void set_timer(ulong t)
- * void udelay(unsigned long usec)
- *
- */
-
-static u32 mmcr_base= 0xfffef000;
-
-void write_mmcr_byte(u16 mmcr, u8 data)
-{
-	writeb(data, mmcr+mmcr_base);
-}
-
-void write_mmcr_word(u16 mmcr, u16 data)
-{
-	writew(data, mmcr+mmcr_base);
-}
-
-void write_mmcr_long(u16 mmcr, u32 data)
-{
-	writel(data, mmcr+mmcr_base);
-}
-
-u8 read_mmcr_byte(u16 mmcr)
-{
-	return readb(mmcr+mmcr_base);
-}
-
-u16 read_mmcr_word(u16 mmcr)
-{
-	return readw(mmcr+mmcr_base);
-}
-
-u32 read_mmcr_long(u16 mmcr)
-{
-	return readl(mmcr+mmcr_base);
-}
-
-
-void init_sc520(void)
-{
-	/* Set the UARTxCTL register at it's slower,
-	 * baud clock giving us a 1.8432 MHz reference
-	 */
-	write_mmcr_byte(SC520_UART1CTL, 7);
-	write_mmcr_byte(SC520_UART2CTL, 7);
-
-	/* first set the timer pin mapping */
-	write_mmcr_byte(SC520_CLKSEL, 0x72);	/* no clock frequency selected, use 1.1892MHz */
-
-	/* enable PCI bus arbitrer */
-	write_mmcr_byte(SC520_SYSARBCTL,0x02);  /* enable concurrent mode */
-
-	write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */
-	write_mmcr_word(SC520_HBCTL,0x04);      /* enable posted-writes */
-
-
-	if (CONFIG_SYS_SC520_HIGH_SPEED) {
-		write_mmcr_byte(SC520_CPUCTL, 0x2);	/* set it to 133 MHz and write back */
-		gd->cpu_clk = 133000000;
-		printf("## CPU Speed set to 133MHz\n");
-	} else {
-		write_mmcr_byte(SC520_CPUCTL, 1);	/* set CPU to 100 MHz and write back cache */
-		printf("## CPU Speed set to 100MHz\n");
-		gd->cpu_clk = 100000000;
-	}
-
-
-	/* wait at least one millisecond */
-	asm("movl	$0x2000,%%ecx\n"
-	    "wait_loop:	pushl %%ecx\n"
-	    "popl	%%ecx\n"
-	    "loop wait_loop\n": : : "ecx");
-
-	/* turn on the SDRAM write buffer */
-	write_mmcr_byte(SC520_DBCTL, 0x11);
-
-	/* turn on the cache and disable write through */
-	asm("movl	%%cr0, %%eax\n"
-	    "andl	$0x9fffffff, %%eax\n"
-	    "movl	%%eax, %%cr0\n"  : : : "eax");
-}
-
-unsigned long init_sc520_dram(void)
-{
-	bd_t *bd = gd->bd;
-
-	u32 dram_present=0;
-	u32 dram_ctrl;
-#ifdef CONFIG_SYS_SDRAM_DRCTMCTL
-	/* these memory control registers are set up in the assember part,
-	 * in sc520_asm.S, during 'mem_init'.  If we muck with them here,
-	 * after we are running a stack in RAM, we have troubles.  Besides,
-	 * these refresh and delay values are better ? simply specified
-	 * outright in the include/configs/{cfg} file since the HW designer
-	 * simply dictates it.
-	 */
-#else
-	int val;
-
-	int cas_precharge_delay = CONFIG_SYS_SDRAM_PRECHARGE_DELAY;
-	int refresh_rate        = CONFIG_SYS_SDRAM_REFRESH_RATE;
-	int ras_cas_delay       = CONFIG_SYS_SDRAM_RAS_CAS_DELAY;
-
-	/* set SDRAM speed here */
-
-	refresh_rate/=78;
-	if (refresh_rate<=1) {
-		val = 0;  /* 7.8us */
-	} else if (refresh_rate==2) {
-		val = 1;  /* 15.6us */
-	} else if (refresh_rate==3 || refresh_rate==4) {
-		val = 2;  /* 31.2us */
-	} else {
-		val = 3;  /* 62.4us */
-	}
-
-	write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4));
-
-	val = read_mmcr_byte(SC520_DRCTMCTL);
-	val &= 0xf0;
-
-	if (cas_precharge_delay==3) {
-		val |= 0x04;   /* 3T */
-	} else if (cas_precharge_delay==4) {
-		val |= 0x08;   /* 4T */
-	} else if (cas_precharge_delay>4) {
-		val |= 0x0c;
-	}
-
-	if (ras_cas_delay > 3) {
-		val |= 2;
-	} else {
-		val |= 1;
-	}
-	write_mmcr_byte(SC520_DRCTMCTL, val);
-#endif
-
-	/* We read-back the configuration of the dram
-	 * controller that the assembly code wrote */
-	dram_ctrl = read_mmcr_long(SC520_DRCBENDADR);
-
-	bd->bi_dram[0].start = 0;
-	if (dram_ctrl & 0x80) {
-		/* bank 0 enabled */
-		dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22;
-		bd->bi_dram[0].size = bd->bi_dram[1].start;
-
-	} else {
-		bd->bi_dram[0].size = 0;
-		bd->bi_dram[1].start = bd->bi_dram[0].start;
-	}
-
-	if (dram_ctrl & 0x8000) {
-		/* bank 1 enabled */
-		dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14;
-		bd->bi_dram[1].size = bd->bi_dram[2].start -  bd->bi_dram[1].start;
-	} else {
-		bd->bi_dram[1].size = 0;
-		bd->bi_dram[2].start = bd->bi_dram[1].start;
-	}
-
-	if (dram_ctrl & 0x800000) {
-		/* bank 2 enabled */
-		dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6;
-		bd->bi_dram[2].size = bd->bi_dram[3].start -  bd->bi_dram[2].start;
-	} else {
-		bd->bi_dram[2].size = 0;
-		bd->bi_dram[3].start = bd->bi_dram[2].start;
-	}
-
-	if (dram_ctrl & 0x80000000) {
-		/* bank 3 enabled */
-		dram_present  = (dram_ctrl & 0x7f000000) >> 2;
-		bd->bi_dram[3].size = dram_present -  bd->bi_dram[3].start;
-	} else {
-		bd->bi_dram[3].size = 0;
-	}
-
-
-#if 0
-	printf("Configured %d bytes of dram\n", dram_present);
-#endif
-	gd->ram_size = dram_present;
-
-	return dram_present;
-}
-
-
-#ifdef CONFIG_PCI
-
-
-static struct {
-	u8 priority;
-	u16 level_reg;
-	u8 level_bit;
-} sc520_irq[] = {
-	{ SC520_IRQ0,  SC520_MPICMODE,  0x01 },
-	{ SC520_IRQ1,  SC520_MPICMODE,  0x02 },
-	{ SC520_IRQ2,  SC520_SL1PICMODE, 0x02 },
-	{ SC520_IRQ3,  SC520_MPICMODE,  0x08 },
-	{ SC520_IRQ4,  SC520_MPICMODE,  0x10 },
-	{ SC520_IRQ5,  SC520_MPICMODE,  0x20 },
-	{ SC520_IRQ6,  SC520_MPICMODE,  0x40 },
-	{ SC520_IRQ7,  SC520_MPICMODE,  0x80 },
-
-	{ SC520_IRQ8,  SC520_SL1PICMODE, 0x01 },
-	{ SC520_IRQ9,  SC520_SL1PICMODE, 0x02 },
-	{ SC520_IRQ10, SC520_SL1PICMODE, 0x04 },
-	{ SC520_IRQ11, SC520_SL1PICMODE, 0x08 },
-	{ SC520_IRQ12, SC520_SL1PICMODE, 0x10 },
-	{ SC520_IRQ13, SC520_SL1PICMODE, 0x20 },
-	{ SC520_IRQ14, SC520_SL1PICMODE, 0x40 },
-	{ SC520_IRQ15, SC520_SL1PICMODE, 0x80 }
-};
-
-
-/* The interrupt used for PCI INTA-INTD  */
-int sc520_pci_ints[15] = {
-	-1, -1, -1, -1, -1, -1, -1, -1,
-		-1, -1, -1, -1, -1, -1, -1
-};
-
-/* utility function to configure a pci interrupt */
-int pci_sc520_set_irq(int pci_pin, int irq)
-{
-	int i;
-
-# if 1
-	printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq);
-#endif
-	if (irq < 0 || irq > 15) {
-		return -1; /* illegal irq */
-	}
-
-	if (pci_pin < 0 || pci_pin > 15) {
-		return -1; /* illegal pci int pin */
-	}
-
-	/* first disable any non-pci interrupt source that use
-	 * this level */
-	for (i=SC520_GPTMR0MAP;i<=SC520_GP10IMAP;i++) {
-		if (i>=SC520_PCIINTAMAP&&i<=SC520_PCIINTDMAP) {
-			continue;
-		}
-		if (read_mmcr_byte(i) == sc520_irq[irq].priority) {
-			write_mmcr_byte(i, SC520_IRQ_DISABLED);
-		}
-	}
-
-	/* Set the trigger to level */
-	write_mmcr_byte(sc520_irq[irq].level_reg,
-			read_mmcr_byte(sc520_irq[irq].level_reg) | sc520_irq[irq].level_bit);
-
-
-	if (pci_pin < 4) {
-		/* PCI INTA-INTD */
-		/* route the interrupt */
-		write_mmcr_byte(SC520_PCIINTAMAP + pci_pin, sc520_irq[irq].priority);
-
-
-	} else {
-		/* GPIRQ0-GPIRQ10 used for additional PCI INTS */
-		write_mmcr_byte(SC520_GP0IMAP + pci_pin - 4, sc520_irq[irq].priority);
-
-		/* also set the polarity in this case */
-		write_mmcr_word(SC520_INTPINPOL,
-				read_mmcr_word(SC520_INTPINPOL) | (1 << (pci_pin-4)));
-
-	}
-
-	/* register the pin */
-	sc520_pci_ints[pci_pin] = irq;
-
-
-	return 0; /* OK */
-}
-
-void pci_sc520_init(struct pci_controller *hose)
-{
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
-
-	/* System memory space */
-	pci_set_region(hose->regions + 0,
-		       SC520_PCI_MEMORY_BUS,
-		       SC520_PCI_MEMORY_PHYS,
-		       SC520_PCI_MEMORY_SIZE,
-		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-
-	/* PCI memory space */
-	pci_set_region(hose->regions + 1,
-		       SC520_PCI_MEM_BUS,
-		       SC520_PCI_MEM_PHYS,
-		       SC520_PCI_MEM_SIZE,
-		       PCI_REGION_MEM);
-
-	/* ISA/PCI memory space */
-	pci_set_region(hose->regions + 2,
-		       SC520_ISA_MEM_BUS,
-		       SC520_ISA_MEM_PHYS,
-		       SC520_ISA_MEM_SIZE,
-		       PCI_REGION_MEM);
-
-	/* PCI I/O space */
-	pci_set_region(hose->regions + 3,
-		       SC520_PCI_IO_BUS,
-		       SC520_PCI_IO_PHYS,
-		       SC520_PCI_IO_SIZE,
-		       PCI_REGION_IO);
-
-	/* ISA/PCI I/O space */
-	pci_set_region(hose->regions + 4,
-		       SC520_ISA_IO_BUS,
-		       SC520_ISA_IO_PHYS,
-		       SC520_ISA_IO_SIZE,
-		       PCI_REGION_IO);
-
-	hose->region_count = 5;
-
-	pci_setup_type1(hose,
-			SC520_REG_ADDR,
-			SC520_REG_DATA);
-
-	pci_register_hose(hose);
-
-	hose->last_busno = pci_hose_scan(hose);
-
-	/* enable target memory acceses on host brige */
-	pci_write_config_word(0, PCI_COMMAND,
-			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
-}
-
-
-#endif
-
-#ifdef CONFIG_SYS_TIMER_SC520
-
-
-void reset_timer(void)
-{
-	write_mmcr_word(SC520_GPTMR0CNT, 0);
-	write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-
-}
-
-ulong get_timer(ulong base)
-{
-	/* fixme: 30 or 33 */
-	return	read_mmcr_word(SC520_GPTMR0CNT) / 33;
-}
-
-void set_timer(ulong t)
-{
-	/* FixMe: use two cascade coupled timers */
-	write_mmcr_word(SC520_GPTMR0CTL, 0x4001);
-	write_mmcr_word(SC520_GPTMR0CNT, t*33);
-	write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-}
-
-
-void udelay(unsigned long usec)
-{
-	int m=0;
-	long u;
-
-	read_mmcr_word(SC520_SWTMRMILLI);
-	read_mmcr_word(SC520_SWTMRMICRO);
-
-#if 0
-	/* do not enable this line, udelay is used in the serial driver -> recursion */
-	printf("udelay: %ld m.u %d.%d  tm.tu %d.%d\n", usec, m, u, tm, tu);
-#endif
-	while (1) {
-
-		m += read_mmcr_word(SC520_SWTMRMILLI);
-		u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000);
-
-		if (usec <= u) {
-			break;
-		}
-	}
-}
-
-#endif
-
-int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase)
-{
-	u8 temp=0;
-
-	if (freq >= 8192) {
-		temp |= CTL_CLK_SEL_4;
-	} else if (freq >= 4096) {
-		temp |= CTL_CLK_SEL_8;
-	} else if (freq >= 2048) {
-		temp |= CTL_CLK_SEL_16;
-	} else if (freq >= 1024) {
-		temp |= CTL_CLK_SEL_32;
-	} else if (freq >= 512) {
-		temp |= CTL_CLK_SEL_64;
-	} else if (freq >= 256) {
-		temp |= CTL_CLK_SEL_128;
-	} else if (freq >= 128) {
-		temp |= CTL_CLK_SEL_256;
-	} else {
-		temp |= CTL_CLK_SEL_512;
-	}
-
-	if (!lsb_first) {
-		temp |= MSBF_ENB;
-	}
-
-	if (inv_clock) {
-		temp |= CLK_INV_ENB;
-	}
-
-	if (inv_phase) {
-		temp |= PHS_INV_ENB;
-	}
-
-	write_mmcr_byte(SC520_SSICTL, temp);
-
-	return 0;
-}
-
-u8 ssi_txrx_byte(u8 data)
-{
-	write_mmcr_byte(SC520_SSIXMIT, data);
-	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
-	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMITRCV);
-	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
-	return read_mmcr_byte(SC520_SSIRCV);
-}
-
-
-void ssi_tx_byte(u8 data)
-{
-	write_mmcr_byte(SC520_SSIXMIT, data);
-	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
-	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMIT);
-}
-
-u8 ssi_rx_byte(void)
-{
-	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
-	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_RCV);
-	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
-	return read_mmcr_byte(SC520_SSIRCV);
-}
-
-#ifdef CONFIG_SYS_RESET_SC520
-void reset_cpu(ulong addr)
-{
-	printf("Resetting using SC520 MMCR\n");
-	/* Write a '1' to the SYS_RST of the RESCFG MMCR */
-	write_mmcr_word(SC520_RESCFG, 0x0001);
-
-	/* NOTREACHED */
-}
-#endif
diff --git a/board/keymile/mgsuvd/Makefile b/cpu/i386/sc520/Makefile
similarity index 64%
copy from board/keymile/mgsuvd/Makefile
copy to cpu/i386/sc520/Makefile
index 2c5732d..87835b2 100644
--- a/board/keymile/mgsuvd/Makefile
+++ b/cpu/i386/sc520/Makefile
@@ -1,6 +1,12 @@
 #
-# (C) Copyright 2007
-# Heiko Schocher, DENX Software Engineering, hs@denx.de.
+# (C) Copyright 2008
+# Graeme Russ, graeme.russ@gmail.com.
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2002
+# Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
 #
 # See file CREDITS for list of people who contributed to this
 # project.
@@ -22,20 +28,22 @@
 #
 
 include $(TOPDIR)/config.mk
-ifneq ($(OBJTREE),$(SRCTREE))
-$(shell mkdir -p $(obj)../common)
-endif
 
-LIB	= $(obj)lib$(BOARD).a
+LIB	:= $(obj)lib$(SOC).a
 
-COBJS	= $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
-		mgsuvd_hdlc_enet.o
+COBJS-$(CONFIG_SYS_SC520) += sc520.o
+COBJS-$(CONFIG_SYS_SC520_SSI) += sc520_ssi.o
+COBJS-$(CONFIG_SYS_SC520_TIMER) += sc520_timer.o
+COBJS-$(CONFIG_PCI) += sc520_pci.o
 
-SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
-OBJS	:= $(addprefix $(obj),$(COBJS))
-SOBJS	:= $(addprefix $(obj),$(SOBJS))
+SOBJS-$(CONFIG_SYS_SC520) += sc520_asm.o
 
-$(LIB):	$(obj).depend $(OBJS)
+SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+
+all: $(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
 	$(AR) $(ARFLAGS) $@ $(OBJS)
 
 #########################################################################
@@ -45,4 +53,4 @@
 
 sinclude $(obj).depend
 
-#########################################################################
+#########################################################################
\ No newline at end of file
diff --git a/cpu/i386/sc520/sc520.c b/cpu/i386/sc520/sc520.c
new file mode 100644
index 0000000..ae3b500
--- /dev/null
+++ b/cpu/i386/sc520/sc520.c
@@ -0,0 +1,239 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * 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
+ */
+
+/* stuff specific for the sc520,
+ * but idependent of implementation */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/ic/sc520.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * utility functions for boards based on the AMD sc520
+ *
+ * void write_mmcr_byte(u16 mmcr, u8 data)
+ * void write_mmcr_word(u16 mmcr, u16 data)
+ * void write_mmcr_long(u16 mmcr, u32 data)
+ *
+ * u8   read_mmcr_byte(u16 mmcr)
+ * u16  read_mmcr_word(u16 mmcr)
+ * u32  read_mmcr_long(u16 mmcr)
+ *
+ * void init_sc520(void)
+ * unsigned long init_sc520_dram(void)
+ */
+
+static u32 mmcr_base= 0xfffef000;
+
+void write_mmcr_byte(u16 mmcr, u8 data)
+{
+	writeb(data, mmcr+mmcr_base);
+}
+
+void write_mmcr_word(u16 mmcr, u16 data)
+{
+	writew(data, mmcr+mmcr_base);
+}
+
+void write_mmcr_long(u16 mmcr, u32 data)
+{
+	writel(data, mmcr+mmcr_base);
+}
+
+u8 read_mmcr_byte(u16 mmcr)
+{
+	return readb(mmcr+mmcr_base);
+}
+
+u16 read_mmcr_word(u16 mmcr)
+{
+	return readw(mmcr+mmcr_base);
+}
+
+u32 read_mmcr_long(u16 mmcr)
+{
+	return readl(mmcr+mmcr_base);
+}
+
+
+void init_sc520(void)
+{
+	/* Set the UARTxCTL register at it's slower,
+	 * baud clock giving us a 1.8432 MHz reference
+	 */
+	write_mmcr_byte(SC520_UART1CTL, 7);
+	write_mmcr_byte(SC520_UART2CTL, 7);
+
+	/* first set the timer pin mapping */
+	write_mmcr_byte(SC520_CLKSEL, 0x72);	/* no clock frequency selected, use 1.1892MHz */
+
+	/* enable PCI bus arbitrer */
+	write_mmcr_byte(SC520_SYSARBCTL,0x02);  /* enable concurrent mode */
+
+	write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */
+	write_mmcr_word(SC520_HBCTL,0x04);      /* enable posted-writes */
+
+
+	if (CONFIG_SYS_SC520_HIGH_SPEED) {
+		write_mmcr_byte(SC520_CPUCTL, 0x2);	/* set it to 133 MHz and write back */
+		gd->cpu_clk = 133000000;
+		printf("## CPU Speed set to 133MHz\n");
+	} else {
+		write_mmcr_byte(SC520_CPUCTL, 1);	/* set CPU to 100 MHz and write back cache */
+		printf("## CPU Speed set to 100MHz\n");
+		gd->cpu_clk = 100000000;
+	}
+
+
+	/* wait at least one millisecond */
+	asm("movl	$0x2000,%%ecx\n"
+	    "wait_loop:	pushl %%ecx\n"
+	    "popl	%%ecx\n"
+	    "loop wait_loop\n": : : "ecx");
+
+	/* turn on the SDRAM write buffer */
+	write_mmcr_byte(SC520_DBCTL, 0x11);
+
+	/* turn on the cache and disable write through */
+	asm("movl	%%cr0, %%eax\n"
+	    "andl	$0x9fffffff, %%eax\n"
+	    "movl	%%eax, %%cr0\n"  : : : "eax");
+}
+
+unsigned long init_sc520_dram(void)
+{
+	bd_t *bd = gd->bd;
+
+	u32 dram_present=0;
+	u32 dram_ctrl;
+#ifdef CONFIG_SYS_SDRAM_DRCTMCTL
+	/* these memory control registers are set up in the assember part,
+	 * in sc520_asm.S, during 'mem_init'.  If we muck with them here,
+	 * after we are running a stack in RAM, we have troubles.  Besides,
+	 * these refresh and delay values are better ? simply specified
+	 * outright in the include/configs/{cfg} file since the HW designer
+	 * simply dictates it.
+	 */
+#else
+	int val;
+
+	int cas_precharge_delay = CONFIG_SYS_SDRAM_PRECHARGE_DELAY;
+	int refresh_rate        = CONFIG_SYS_SDRAM_REFRESH_RATE;
+	int ras_cas_delay       = CONFIG_SYS_SDRAM_RAS_CAS_DELAY;
+
+	/* set SDRAM speed here */
+
+	refresh_rate/=78;
+	if (refresh_rate<=1) {
+		val = 0;  /* 7.8us */
+	} else if (refresh_rate==2) {
+		val = 1;  /* 15.6us */
+	} else if (refresh_rate==3 || refresh_rate==4) {
+		val = 2;  /* 31.2us */
+	} else {
+		val = 3;  /* 62.4us */
+	}
+
+	write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4));
+
+	val = read_mmcr_byte(SC520_DRCTMCTL);
+	val &= 0xf0;
+
+	if (cas_precharge_delay==3) {
+		val |= 0x04;   /* 3T */
+	} else if (cas_precharge_delay==4) {
+		val |= 0x08;   /* 4T */
+	} else if (cas_precharge_delay>4) {
+		val |= 0x0c;
+	}
+
+	if (ras_cas_delay > 3) {
+		val |= 2;
+	} else {
+		val |= 1;
+	}
+	write_mmcr_byte(SC520_DRCTMCTL, val);
+#endif
+
+	/* We read-back the configuration of the dram
+	 * controller that the assembly code wrote */
+	dram_ctrl = read_mmcr_long(SC520_DRCBENDADR);
+
+	bd->bi_dram[0].start = 0;
+	if (dram_ctrl & 0x80) {
+		/* bank 0 enabled */
+		dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22;
+		bd->bi_dram[0].size = bd->bi_dram[1].start;
+
+	} else {
+		bd->bi_dram[0].size = 0;
+		bd->bi_dram[1].start = bd->bi_dram[0].start;
+	}
+
+	if (dram_ctrl & 0x8000) {
+		/* bank 1 enabled */
+		dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14;
+		bd->bi_dram[1].size = bd->bi_dram[2].start -  bd->bi_dram[1].start;
+	} else {
+		bd->bi_dram[1].size = 0;
+		bd->bi_dram[2].start = bd->bi_dram[1].start;
+	}
+
+	if (dram_ctrl & 0x800000) {
+		/* bank 2 enabled */
+		dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6;
+		bd->bi_dram[2].size = bd->bi_dram[3].start -  bd->bi_dram[2].start;
+	} else {
+		bd->bi_dram[2].size = 0;
+		bd->bi_dram[3].start = bd->bi_dram[2].start;
+	}
+
+	if (dram_ctrl & 0x80000000) {
+		/* bank 3 enabled */
+		dram_present  = (dram_ctrl & 0x7f000000) >> 2;
+		bd->bi_dram[3].size = dram_present -  bd->bi_dram[3].start;
+	} else {
+		bd->bi_dram[3].size = 0;
+	}
+
+
+#if 0
+	printf("Configured %d bytes of dram\n", dram_present);
+#endif
+	gd->ram_size = dram_present;
+
+	return dram_present;
+}
+
+#ifdef CONFIG_SYS_SC520_RESET
+void reset_cpu(ulong addr)
+{
+	printf("Resetting using SC520 MMCR\n");
+	/* Write a '1' to the SYS_RST of the RESCFG MMCR */
+	write_mmcr_word(SC520_RESCFG, 0x0001);
+
+	/* NOTREACHED */
+}
+#endif
diff --git a/cpu/i386/sc520_asm.S b/cpu/i386/sc520/sc520_asm.S
similarity index 99%
rename from cpu/i386/sc520_asm.S
rename to cpu/i386/sc520/sc520_asm.S
index 59ed2b8..2042d9b 100644
--- a/cpu/i386/sc520_asm.S
+++ b/cpu/i386/sc520/sc520_asm.S
@@ -105,7 +105,6 @@
  */
 
 #include <config.h>
-#ifdef CONFIG_SC520
 
 .section .text
 .equ            DRCCTL,     0x0fffef010   /* DRAM control register */
@@ -580,5 +579,3 @@
 out:
 	movl	%ebx, %eax
 	jmp	*%ebp
-
-#endif /* CONFIG_SC520 */
diff --git a/cpu/i386/sc520/sc520_pci.c b/cpu/i386/sc520/sc520_pci.c
new file mode 100644
index 0000000..38b837e
--- /dev/null
+++ b/cpu/i386/sc520/sc520_pci.c
@@ -0,0 +1,171 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * 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
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/pci.h>
+#include <asm/ic/sc520.h>
+
+static struct {
+	u8 priority;
+	u16 level_reg;
+	u8 level_bit;
+} sc520_irq[] = {
+	{ SC520_IRQ0,  SC520_MPICMODE,  0x01 },
+	{ SC520_IRQ1,  SC520_MPICMODE,  0x02 },
+	{ SC520_IRQ2,  SC520_SL1PICMODE, 0x02 },
+	{ SC520_IRQ3,  SC520_MPICMODE,  0x08 },
+	{ SC520_IRQ4,  SC520_MPICMODE,  0x10 },
+	{ SC520_IRQ5,  SC520_MPICMODE,  0x20 },
+	{ SC520_IRQ6,  SC520_MPICMODE,  0x40 },
+	{ SC520_IRQ7,  SC520_MPICMODE,  0x80 },
+
+	{ SC520_IRQ8,  SC520_SL1PICMODE, 0x01 },
+	{ SC520_IRQ9,  SC520_SL1PICMODE, 0x02 },
+	{ SC520_IRQ10, SC520_SL1PICMODE, 0x04 },
+	{ SC520_IRQ11, SC520_SL1PICMODE, 0x08 },
+	{ SC520_IRQ12, SC520_SL1PICMODE, 0x10 },
+	{ SC520_IRQ13, SC520_SL1PICMODE, 0x20 },
+	{ SC520_IRQ14, SC520_SL1PICMODE, 0x40 },
+	{ SC520_IRQ15, SC520_SL1PICMODE, 0x80 }
+};
+
+
+/* The interrupt used for PCI INTA-INTD  */
+int sc520_pci_ints[15] = {
+	-1, -1, -1, -1, -1, -1, -1, -1,
+		-1, -1, -1, -1, -1, -1, -1
+};
+
+/* utility function to configure a pci interrupt */
+int pci_sc520_set_irq(int pci_pin, int irq)
+{
+	int i;
+
+# if 1
+	printf("set_irq(): map INT%c to IRQ%d\n", pci_pin + 'A', irq);
+#endif
+	if (irq < 0 || irq > 15) {
+		return -1; /* illegal irq */
+	}
+
+	if (pci_pin < 0 || pci_pin > 15) {
+		return -1; /* illegal pci int pin */
+	}
+
+	/* first disable any non-pci interrupt source that use
+	 * this level */
+	for (i=SC520_GPTMR0MAP;i<=SC520_GP10IMAP;i++) {
+		if (i>=SC520_PCIINTAMAP&&i<=SC520_PCIINTDMAP) {
+			continue;
+		}
+		if (read_mmcr_byte(i) == sc520_irq[irq].priority) {
+			write_mmcr_byte(i, SC520_IRQ_DISABLED);
+		}
+	}
+
+	/* Set the trigger to level */
+	write_mmcr_byte(sc520_irq[irq].level_reg,
+			read_mmcr_byte(sc520_irq[irq].level_reg) | sc520_irq[irq].level_bit);
+
+
+	if (pci_pin < 4) {
+		/* PCI INTA-INTD */
+		/* route the interrupt */
+		write_mmcr_byte(SC520_PCIINTAMAP + pci_pin, sc520_irq[irq].priority);
+
+
+	} else {
+		/* GPIRQ0-GPIRQ10 used for additional PCI INTS */
+		write_mmcr_byte(SC520_GP0IMAP + pci_pin - 4, sc520_irq[irq].priority);
+
+		/* also set the polarity in this case */
+		write_mmcr_word(SC520_INTPINPOL,
+				read_mmcr_word(SC520_INTPINPOL) | (1 << (pci_pin-4)));
+
+	}
+
+	/* register the pin */
+	sc520_pci_ints[pci_pin] = irq;
+
+
+	return 0; /* OK */
+}
+
+void pci_sc520_init(struct pci_controller *hose)
+{
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	/* System memory space */
+	pci_set_region(hose->regions + 0,
+		       SC520_PCI_MEMORY_BUS,
+		       SC520_PCI_MEMORY_PHYS,
+		       SC520_PCI_MEMORY_SIZE,
+		       PCI_REGION_MEM | PCI_REGION_MEMORY);
+
+	/* PCI memory space */
+	pci_set_region(hose->regions + 1,
+		       SC520_PCI_MEM_BUS,
+		       SC520_PCI_MEM_PHYS,
+		       SC520_PCI_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	/* ISA/PCI memory space */
+	pci_set_region(hose->regions + 2,
+		       SC520_ISA_MEM_BUS,
+		       SC520_ISA_MEM_PHYS,
+		       SC520_ISA_MEM_SIZE,
+		       PCI_REGION_MEM);
+
+	/* PCI I/O space */
+	pci_set_region(hose->regions + 3,
+		       SC520_PCI_IO_BUS,
+		       SC520_PCI_IO_PHYS,
+		       SC520_PCI_IO_SIZE,
+		       PCI_REGION_IO);
+
+	/* ISA/PCI I/O space */
+	pci_set_region(hose->regions + 4,
+		       SC520_ISA_IO_BUS,
+		       SC520_ISA_IO_PHYS,
+		       SC520_ISA_IO_SIZE,
+		       PCI_REGION_IO);
+
+	hose->region_count = 5;
+
+	pci_setup_type1(hose,
+			SC520_REG_ADDR,
+			SC520_REG_DATA);
+
+	pci_register_hose(hose);
+
+	hose->last_busno = pci_hose_scan(hose);
+
+	/* enable target memory acceses on host brige */
+	pci_write_config_word(0, PCI_COMMAND,
+			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+}
diff --git a/cpu/i386/sc520/sc520_ssi.c b/cpu/i386/sc520/sc520_ssi.c
new file mode 100644
index 0000000..dd667ca
--- /dev/null
+++ b/cpu/i386/sc520/sc520_ssi.c
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * 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
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <asm/ic/ssi.h>
+#include <asm/ic/sc520.h>
+
+int ssi_set_interface(int freq, int lsb_first, int inv_clock, int inv_phase)
+{
+	u8 temp=0;
+
+	if (freq >= 8192) {
+		temp |= CTL_CLK_SEL_4;
+	} else if (freq >= 4096) {
+		temp |= CTL_CLK_SEL_8;
+	} else if (freq >= 2048) {
+		temp |= CTL_CLK_SEL_16;
+	} else if (freq >= 1024) {
+		temp |= CTL_CLK_SEL_32;
+	} else if (freq >= 512) {
+		temp |= CTL_CLK_SEL_64;
+	} else if (freq >= 256) {
+		temp |= CTL_CLK_SEL_128;
+	} else if (freq >= 128) {
+		temp |= CTL_CLK_SEL_256;
+	} else {
+		temp |= CTL_CLK_SEL_512;
+	}
+
+	if (!lsb_first) {
+		temp |= MSBF_ENB;
+	}
+
+	if (inv_clock) {
+		temp |= CLK_INV_ENB;
+	}
+
+	if (inv_phase) {
+		temp |= PHS_INV_ENB;
+	}
+
+	write_mmcr_byte(SC520_SSICTL, temp);
+
+	return 0;
+}
+
+u8 ssi_txrx_byte(u8 data)
+{
+	write_mmcr_byte(SC520_SSIXMIT, data);
+	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMITRCV);
+	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+	return read_mmcr_byte(SC520_SSIRCV);
+}
+
+
+void ssi_tx_byte(u8 data)
+{
+	write_mmcr_byte(SC520_SSIXMIT, data);
+	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_XMIT);
+}
+
+u8 ssi_rx_byte(void)
+{
+	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+	write_mmcr_byte(SC520_SSICMD, SSICMD_CMD_SEL_RCV);
+	while ((read_mmcr_byte(SC520_SSISTA)) & SSISTA_BSY);
+	return read_mmcr_byte(SC520_SSIRCV);
+}
diff --git a/cpu/i386/sc520/sc520_timer.c b/cpu/i386/sc520/sc520_timer.c
new file mode 100644
index 0000000..2cb8656
--- /dev/null
+++ b/cpu/i386/sc520/sc520_timer.c
@@ -0,0 +1,82 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
+ *
+ * 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
+ */
+
+/* stuff specific for the sc520, but independent of implementation */
+
+#include <common.h>
+#include <asm/interrupt.h>
+#include <asm/ic/sc520.h>
+
+void sc520_timer_isr(void)
+{
+	/* Ack the GP Timer Interrupt */
+	write_mmcr_byte (SC520_GPTMRSTA, 0x02);
+}
+
+int timer_init(void)
+{
+	/* Map GP Timer 1 to Master PIC IR0  */
+	write_mmcr_byte (SC520_GPTMR1MAP, 0x01);
+
+	/* Disable GP Timers 1 & 2 - Allow configuration writes */
+	write_mmcr_word (SC520_GPTMR1CTL, 0x4000);
+	write_mmcr_word (SC520_GPTMR2CTL, 0x4000);
+
+	/* Reset GP Timers 1 & 2 */
+	write_mmcr_word (SC520_GPTMR1CNT, 0x0000);
+	write_mmcr_word (SC520_GPTMR2CNT, 0x0000);
+
+	/* Setup GP Timer 2 as a 100kHz (10us) prescaler */
+	write_mmcr_word (SC520_GPTMR2MAXCMPA, 83);
+	write_mmcr_word (SC520_GPTMR2CTL, 0xc001);
+
+	/* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */
+	write_mmcr_word (SC520_GPTMR1MAXCMPA, 100);
+	write_mmcr_word (SC520_GPTMR1CTL, 0xe009);
+
+	/* Clear the GP Timers status register */
+	write_mmcr_byte (SC520_GPTMRSTA, 0x07);
+
+	/* Register the SC520 specific timer interrupt handler */
+	register_timer_isr (sc520_timer_isr);
+
+	/* Install interrupt handler for GP Timer 1 */
+	irq_install_handler (0, timer_isr, NULL);
+	unmask_irq (0);
+
+	return 0;
+}
+
+void udelay(unsigned long usec)
+{
+	int m = 0;
+	long u;
+
+	read_mmcr_word (SC520_SWTMRMILLI);
+	read_mmcr_word (SC520_SWTMRMICRO);
+
+	do {
+		m += read_mmcr_word (SC520_SWTMRMILLI);
+		u = read_mmcr_word (SC520_SWTMRMICRO) + (m * 1000);
+	} while (u < usec);
+}
diff --git a/cpu/i386/start.S b/cpu/i386/start.S
index b6175b1..59089ef 100644
--- a/cpu/i386/start.S
+++ b/cpu/i386/start.S
@@ -173,7 +173,41 @@
 	jmp	die
 
 bss_ok:
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* indicate progress */
+	movw	$0x06, %ax
+	movl	$.progress6, %ebp
+	jmp	show_boot_progress_asm
+.progress6:
 
+	/* copy text section to ram, size must be 4-byte aligned */
+	movl	$CONFIG_SYS_BL_START_RAM, %edi		/* destination address */
+	movl	$TEXT_BASE, %esi		/* source address */
+	movl	$_i386boot_text_size, %ecx	/* number of bytes to copy */
+	movl	%ecx, %eax
+	andl	$3, %eax
+	jz	text_copy			/* Already 4-byte aligned */
+	subl    $4, %eax			/* Add extra bytes to size */
+	addl	%eax, %ecx
+text_copy:
+	shrl	$2, %ecx			/* copy 4 byte each time */
+	cld
+	cmpl	$0, %ecx
+	je	text_ok
+text_segment:
+	movsl
+	loop	text_segment
+	jmp	text_ok
+text_fail:
+	/* indicate (lack of) progress */
+	movw	$0x86, %ax
+	movl	$.progress5a, %ebp
+	jmp	show_boot_progress_asm
+.progress5a:
+	jmp	die
+
+text_ok:
+#endif
 	wbinvd
 
 
@@ -183,7 +217,14 @@
 	jmp	show_boot_progress_asm
 .progress4:
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* Jump to the RAM copy of start_i386boot */
+	movl	$start_i386boot, %ebp
+	addl	$(CONFIG_SYS_BL_START_RAM - TEXT_BASE), %ebp
+	call	*%ebp		/* Enter, U-boot! */
+#else
 	call	start_i386boot  /* Enter, U-boot! */
+#endif
 
 	/* indicate (lack of) progress */
 	movw	$0x85, %ax
diff --git a/cpu/i386/timer.c b/cpu/i386/timer.c
deleted file mode 100644
index 46db23f..0000000
--- a/cpu/i386/timer.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * (C) Copyright 2002
- * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
- *
- * 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 <asm/io.h>
-#include <asm/i8254.h>
-#include <asm/ibmpc.h>
-
-
-static volatile unsigned long system_ticks;
-static int timer_init_done =0;
-
-static void timer_isr(void *unused)
-{
-	system_ticks++;
-}
-
-unsigned long get_system_ticks(void)
-{
-	return system_ticks;
-}
-
-#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
-#define TIMER2_VALUE 0x0a8e /* 440Hz */
-
-int timer_init(void)
-{
-	system_ticks = 0;
-
-	irq_install_handler(0, timer_isr, NULL);
-
-	/* initialize timer 0 and 2
-	 *
-	 * Timer 0 is used to increment system_tick 1000 times/sec
-	 * Timer 1 was used for DRAM refresh in early PC's
-	 * Timer 2 is used to drive the speaker
-	 * (to stasrt a beep: write 3 to port 0x61,
-	 * to stop it again: write 0)
-	 */
-
-	outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
-	outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
-	outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
-
-	outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
-	outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
-	outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
-
-	timer_init_done = 1;
-
-	return 0;
-}
-
-
-#ifdef CONFIG_SYS_TIMER_GENERIC
-
-/* the unit for these is CONFIG_SYS_HZ */
-
-/* FixMe: implement these */
-void reset_timer (void)
-{
-	system_ticks = 0;
-}
-
-ulong get_timer (ulong base)
-{
-	return (system_ticks - base);
-}
-
-void set_timer (ulong t)
-{
-	system_ticks = t;
-}
-
-static u16 read_pit(void)
-{
-	u8 low;
-	outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
-	low = inb(PIT_BASE + PIT_T0);
-	return ((inb(PIT_BASE + PIT_T0) << 8) | low);
-}
-
-/* this is not very exact */
-void udelay (unsigned long usec)
-{
-	int counter;
-	int wraps;
-
-	if (!timer_init_done) {
-		return;
-	}
-	counter = read_pit();
-	wraps = usec/1000;
-	usec = usec%1000;
-
-	usec*=1194;
-	usec/=1000;
-	usec+=counter;
-	if (usec > 1194) {
-		usec-=1194;
-		wraps++;
-	}
-
-	while (1) {
-		int new_count = read_pit();
-
-		if (((new_count < usec) && !wraps) || wraps < 0) {
-			break;
-		}
-
-		if (new_count > counter) {
-			wraps--;
-		}
-		counter = new_count;
-	}
-
-}
-
-#if 0
-/* this is a version with debug output */
-void _udelay (unsigned long usec)
-{
-	int counter;
-	int wraps;
-
-	int usec1, usec2, usec3;
-	int wraps1, wraps2, wraps3, wraps4;
-	int ctr1, ctr2, ctr3, nct1, nct2;
-	int i;
-	usec1=usec;
-	if (!timer_init_done) {
-		return;
-	}
-	counter = read_pit();
-	ctr1 = counter;
-	wraps = usec/1000;
-	usec = usec%1000;
-
-	usec2 = usec;
-	wraps1 = wraps;
-
-	usec*=1194;
-	usec/=1000;
-	usec+=counter;
-	if (usec > 1194) {
-		usec-=1194;
-		wraps++;
-	}
-
-	usec3 = usec;
-	wraps2 = wraps;
-
-	ctr2 = wraps3 = nct1 = 4711;
-	ctr3 = wraps4 = nct2 = 4711;
-	i=0;
-	while (1) {
-		int new_count = read_pit();
-		i++;
-		if ((new_count < usec && !wraps) || wraps < 0) {
-			break;
-		}
-
-		if (new_count > counter) {
-			wraps--;
-		}
-		if (ctr2==4711) {
-			ctr2 = counter;
-			wraps3 = wraps;
-			nct1 = new_count;
-		} else {
-			ctr3 = counter;
-			wraps4 = wraps;
-			nct2 = new_count;
-		}
-
-		counter = new_count;
-	}
-
-	printf("udelay(%d)\n", usec1);
-	printf("counter %d\n", ctr1);
-	printf("1: wraps %d, usec %d\n", wraps1, usec2);
-	printf("2: wraps %d, usec %d\n", wraps2, usec3);
-	printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
-	printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
-
-	printf("%d %d %d %d %d\n",
-	       read_pit(), read_pit(), read_pit(),
-	       read_pit(), read_pit());
-}
-#endif
-#endif
diff --git a/cpu/ixp/npe/npe.c b/cpu/ixp/npe/npe.c
index 03e3bf7..2e68689 100644
--- a/cpu/ixp/npe/npe.c
+++ b/cpu/ixp/npe/npe.c
@@ -565,25 +565,19 @@
 	struct eth_device *dev;
 	int eth_num = 0;
 	struct npe *p_npe = NULL;
+	uchar enetaddr[6];
 
 	for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
 
 		/* See if we can actually bring up the interface, otherwise, skip it */
-		switch (eth_num) {
-		default:		/* fall through */
-		case 0:
-			if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
-				continue;
-			}
-			break;
 #ifdef CONFIG_HAS_ETH1
-		case 1:
-			if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
+		if (eth_num == 1) {
+			if (!eth_getenv_enetaddr("eth1addr", enetaddr))
 				continue;
-			}
-			break;
+		} else
 #endif
-		}
+			if (!eth_getenv_enetaddr("ethaddr", enetaddr))
+				continue;
 
 		/* Allocate device structure */
 		dev = (struct eth_device *)malloc(sizeof(*dev));
@@ -603,22 +597,14 @@
 		}
 		memset(p_npe, 0, sizeof(struct npe));
 
-		switch (eth_num) {
-		default:		/* fall through */
-		case 0:
-			memcpy(dev->enetaddr, bis->bi_enetaddr, 6);
-			p_npe->eth_id = 0;
-			p_npe->phy_no = CONFIG_PHY_ADDR;
-			break;
-
+		p_npe->eth_id = eth_num;
+		memcpy(dev->enetaddr, enetaddr, 6);
 #ifdef CONFIG_HAS_ETH1
-		case 1:
-			memcpy(dev->enetaddr, bis->bi_enet1addr, 6);
-			p_npe->eth_id = 1;
+		if (eth_num == 1)
 			p_npe->phy_no = CONFIG_PHY1_ADDR;
-			break;
+		else
 #endif
-		}
+			p_npe->phy_no = CONFIG_PHY_ADDR;
 
 		sprintf(dev->name, "NPE%d", eth_num);
 		dev->priv = (void *)p_npe;
diff --git a/cpu/mcf5227x/config.mk b/cpu/mcf5227x/config.mk
index 8d60fd6..8eab49d 100644
--- a/cpu/mcf5227x/config.mk
+++ b/cpu/mcf5227x/config.mk
@@ -24,8 +24,8 @@
 #
 
 PLATFORM_RELFLAGS += -ffixed-d7 -msep-data
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
-PLATFORM_CPPFLAGS += -mcpu=5208 -fPIC
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
+PLATFORM_CPPFLAGS += -mcpu=52277 -fPIC
 else
 PLATFORM_CPPFLAGS += -m5307 -fPIC
 endif
diff --git a/cpu/mcf523x/config.mk b/cpu/mcf523x/config.mk
index 93645a3..fc79454 100644
--- a/cpu/mcf523x/config.mk
+++ b/cpu/mcf523x/config.mk
@@ -24,7 +24,7 @@
 #
 
 PLATFORM_RELFLAGS += -ffixed-d7 -msep-data
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
 PLATFORM_CPPFLAGS += -mcpu=5235 -fPIC
 else
 PLATFORM_CPPFLAGS += -m5307 -fPIC
diff --git a/cpu/mcf52x2/config.mk b/cpu/mcf52x2/config.mk
index 650e340..8292736 100644
--- a/cpu/mcf52x2/config.mk
+++ b/cpu/mcf52x2/config.mk
@@ -34,7 +34,7 @@
 is5282:=$(shell grep CONFIG_M5282 $(TOPDIR)/include/$(cfg))
 
 
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
 
 ifneq (,$(findstring CONFIG_M5249,$(is5249)))
 PLATFORM_CPPFLAGS += -mcpu=5249
diff --git a/cpu/mcf532x/config.mk b/cpu/mcf532x/config.mk
index 16a0bc3..0cb90ac 100644
--- a/cpu/mcf532x/config.mk
+++ b/cpu/mcf532x/config.mk
@@ -24,7 +24,7 @@
 #
 
 PLATFORM_RELFLAGS += -ffixed-d7 -msep-data
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
 PLATFORM_CPPFLAGS += -mcpu=5329 -fPIC
 else
 PLATFORM_CPPFLAGS += -m5307 -fPIC
diff --git a/cpu/mcf5445x/config.mk b/cpu/mcf5445x/config.mk
index 67efa07..b0b49f7 100644
--- a/cpu/mcf5445x/config.mk
+++ b/cpu/mcf5445x/config.mk
@@ -24,7 +24,7 @@
 #
 
 PLATFORM_RELFLAGS += -ffixed-d7 -msep-data
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
 PLATFORM_CPPFLAGS += -mcpu=54455 -fPIC
 else
 PLATFORM_CPPFLAGS += -m5407 -fPIC
diff --git a/cpu/mcf5445x/start.S b/cpu/mcf5445x/start.S
index d5a7f93..26fb2ce 100644
--- a/cpu/mcf5445x/start.S
+++ b/cpu/mcf5445x/start.S
@@ -243,9 +243,9 @@
 	nop
 #elif defined(CONFIG_M54451EVB)
 	/* Issue LEMR */
-	move.l	#(CONFIG_SYS_SDRAM_MODE), (%a2)
+	move.l	#(CONFIG_SYS_SDRAM_MODE), (%a1)
 	nop
-	move.l	#(CONFIG_SYS_SDRAM_EMOD), (%a2)
+	move.l	#(CONFIG_SYS_SDRAM_EMOD), (%a1)
 	nop
 #endif
 
diff --git a/cpu/mcf547x_8x/config.mk b/cpu/mcf547x_8x/config.mk
index 567b281..83102ab 100644
--- a/cpu/mcf547x_8x/config.mk
+++ b/cpu/mcf547x_8x/config.mk
@@ -24,7 +24,7 @@
 #
 
 PLATFORM_RELFLAGS += -ffixed-d7 -msep-data
-ifeq ($(findstring 4.2,$(shell $(CC) --version)),4.2)
+ifneq ($(findstring 4.1,$(shell $(CC) --version)),4.1)
 PLATFORM_CPPFLAGS += -mcpu=5485 -fPIC
 else
 PLATFORM_CPPFLAGS += -m5407 -fPIC
diff --git a/cpu/mcf547x_8x/cpu_init.c b/cpu/mcf547x_8x/cpu_init.c
index 1ba5783..96a3132 100644
--- a/cpu/mcf547x_8x/cpu_init.c
+++ b/cpu/mcf547x_8x/cpu_init.c
@@ -49,14 +49,14 @@
 	volatile xlbarb_t *xlbarb = (volatile xlbarb_t *) MMAP_XARB;
 
 	xlbarb->adrto = 0x2000;
-	xlbarb->datto = 0x2000;
+	xlbarb->datto = 0x2500;
 	xlbarb->busto = 0x3000;
 
-	xlbarb->cfg = XARB_SR_AT | XARB_SR_DT;
+	xlbarb->cfg = XARB_CFG_AT | XARB_CFG_DT;
 
 	/* Master Priority Enable */
-	xlbarb->pri = 0;
 	xlbarb->prien = 0xff;
+	xlbarb->pri = 0;
 
 #if (defined(CONFIG_SYS_CS0_BASE) && defined(CONFIG_SYS_CS0_MASK) && defined(CONFIG_SYS_CS0_CTRL))
 	fbcs->csar0 = CONFIG_SYS_CS0_BASE;
diff --git a/cpu/mpc512x/cpu.c b/cpu/mpc512x/cpu.c
index b9069b0..be532af 100644
--- a/cpu/mpc512x/cpu.c
+++ b/cpu/mpc512x/cpu.c
@@ -148,15 +148,17 @@
 	 * avoid fixing up by path because that
 	 * produces scary error messages
 	 */
+	uchar enetaddr[6];
 
 	/*
 	 * old device trees have ethernet nodes with
 	 * device_type = "network"
 	 */
+	eth_getenv_enetaddr("ethaddr", enetaddr);
 	do_fixup_by_prop(blob, "device_type", "network", 8,
-		"local-mac-address", bd->bi_enetaddr, 6, 0);
+		"local-mac-address", enetaddr, 6, 0);
 	do_fixup_by_prop(blob, "device_type", "network", 8,
-		"address", bd->bi_enetaddr, 6, 0);
+		"address", enetaddr, 6, 0);
 	/*
 	 * old device trees have soc nodes with
 	 * device_type = "soc"
diff --git a/cpu/mpc5xx/u-boot.lds b/cpu/mpc5xx/u-boot.lds
index bf52179..cb17ca5 100644
--- a/cpu/mpc5xx/u-boot.lds
+++ b/cpu/mpc5xx/u-boot.lds
@@ -65,10 +65,8 @@
   PROVIDE (etext = .);
   .rodata    :
   {
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc5xxx/cpu.c b/cpu/mpc5xxx/cpu.c
index 9c6ab76..f6258c7 100644
--- a/cpu/mpc5xxx/cpu.c
+++ b/cpu/mpc5xxx/cpu.c
@@ -28,6 +28,7 @@
 #include <common.h>
 #include <watchdog.h>
 #include <command.h>
+#include <net.h>
 #include <mpc5xxx.h>
 #include <netdev.h>
 #include <asm/io.h>
@@ -121,6 +122,7 @@
 	int div = in_8((void*)CONFIG_SYS_MBAR + 0x204) & 0x0020 ? 8 : 4;
 	char * cpu_path = "/cpus/" OF_CPU;
 #ifdef CONFIG_MPC5xxx_FEC
+	uchar enetaddr[6];
 	char * eth_path = "/" OF_SOC "/ethernet@3000";
 #endif
 
@@ -131,8 +133,9 @@
 	do_fixup_by_path_u32(blob, "/" OF_SOC, "system-frequency",
 				bd->bi_busfreq*div, 1);
 #ifdef CONFIG_MPC5xxx_FEC
-	do_fixup_by_path(blob, eth_path, "mac-address", bd->bi_enetaddr, 6, 0);
-	do_fixup_by_path(blob, eth_path, "local-mac-address", bd->bi_enetaddr, 6, 0);
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	do_fixup_by_path(blob, eth_path, "mac-address", enetaddr, 6, 0);
+	do_fixup_by_path(blob, eth_path, "local-mac-address", enetaddr, 6, 0);
 #endif
 }
 #endif
diff --git a/cpu/mpc5xxx/ide.c b/cpu/mpc5xxx/ide.c
index df5b4ac..9e8f29b 100644
--- a/cpu/mpc5xxx/ide.c
+++ b/cpu/mpc5xxx/ide.c
@@ -42,7 +42,7 @@
 	struct mpc5xxx_sdma *psdma = (struct mpc5xxx_sdma *) MPC5XXX_SDMA;
 
 	reg = *(vu_long *) MPC5XXX_GPS_PORT_CONFIG;
-#if defined(CONFIG_TOTAL5200)
+#if defined(CONFIG_SYS_ATA_CS_ON_I2C2)
 	/* ATA cs0/1 on i2c2 clk/io */
 	reg = (reg & ~0x03000000ul) | 0x02000000ul;
 #else
diff --git a/cpu/mpc5xxx/u-boot-customlayout.lds b/cpu/mpc5xxx/u-boot-customlayout.lds
index f6bb858..9563690 100644
--- a/cpu/mpc5xxx/u-boot-customlayout.lds
+++ b/cpu/mpc5xxx/u-boot-customlayout.lds
@@ -68,10 +68,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc5xxx/u-boot.lds b/cpu/mpc5xxx/u-boot.lds
index 8d1fa60..a6d4ff3 100644
--- a/cpu/mpc5xxx/u-boot.lds
+++ b/cpu/mpc5xxx/u-boot.lds
@@ -57,10 +57,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc8220/u-boot.lds b/cpu/mpc8220/u-boot.lds
index 2a12a69..436423c 100644
--- a/cpu/mpc8220/u-boot.lds
+++ b/cpu/mpc8220/u-boot.lds
@@ -57,10 +57,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc824x/u-boot.lds b/cpu/mpc824x/u-boot.lds
index 8c7e135..46f7087 100644
--- a/cpu/mpc824x/u-boot.lds
+++ b/cpu/mpc824x/u-boot.lds
@@ -57,10 +57,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc8260/ether_fcc.c b/cpu/mpc8260/ether_fcc.c
index 3ab57eb..5ac02a0 100644
--- a/cpu/mpc8260/ether_fcc.c
+++ b/cpu/mpc8260/ether_fcc.c
@@ -654,7 +654,7 @@
 
 	puts ("FCC Ethernet External loopback test\n");
 
-	memcpy (NetOurEther, gd->bd->bi_enetaddr, 6);
+	eth_getenv_enetaddr("ethaddr", NetOurEther);
 
 	/*
 	 * global initialisations for all FCC channels
@@ -841,7 +841,7 @@
 		 * So, far we have only been given one Ethernet address. We use
 		 * the same address for all channels
 		 */
-#define ea gd->bd->bi_enetaddr
+#define ea NetOurEther
 		fpp->fen_paddrh = (ea[5] << 8) + ea[4];
 		fpp->fen_paddrm = (ea[3] << 8) + ea[2];
 		fpp->fen_paddrl = (ea[1] << 8) + ea[0];
diff --git a/cpu/mpc8260/ether_scc.c b/cpu/mpc8260/ether_scc.c
index 3671ef1..432111d 100644
--- a/cpu/mpc8260/ether_scc.c
+++ b/cpu/mpc8260/ether_scc.c
@@ -199,6 +199,7 @@
     volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
     scc_enet_t *pram_ptr;
     uint dpaddr;
+    uchar ea[6];
 
     rxIdx = 0;
     txIdx = 0;
@@ -261,11 +262,10 @@
     pram_ptr->sen_gaddr3 = 0x0;   /* Group Address Filter 3 (unused) */
     pram_ptr->sen_gaddr4 = 0x0;   /* Group Address Filter 4 (unused) */
 
-#  define ea bis->bi_enetaddr
+    eth_getenv_enetaddr("ethaddr", ea);
     pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
     pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
     pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
-#  undef ea
 
     pram_ptr->sen_pper   = 0x0;   /* Persistence (unused) */
 
diff --git a/cpu/mpc8260/u-boot.lds b/cpu/mpc8260/u-boot.lds
index d65a939..b3a103d 100644
--- a/cpu/mpc8260/u-boot.lds
+++ b/cpu/mpc8260/u-boot.lds
@@ -57,10 +57,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
index 9e0a05d..876f5c7 100644
--- a/cpu/mpc83xx/cpu.c
+++ b/cpu/mpc83xx/cpu.c
@@ -35,6 +35,10 @@
 #include <tsec.h>
 #include <netdev.h>
 #include <fsl_esdhc.h>
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+#include <asm/immap_qe.h>
+#include <asm/io.h>
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -399,3 +403,33 @@
 	return 0;
 #endif
 }
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+
+#if !defined(CONFIG_MPC8360)
+#error "CONFIG_BOOTCOUNT_LIMIT only for MPC8360 implemented"
+#endif
+
+#if !defined(CONFIG_BOOTCOUNT_ADDR)
+#define CONFIG_BOOTCOUNT_ADDR	(0x110000 + QE_MURAM_SIZE - 2 * sizeof(unsigned long))
+#endif
+
+#include <asm/io.h>
+
+void bootcount_store (ulong a)
+{
+	void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+	out_be32 (reg, a);
+	out_be32 (reg + 4, BOOTCOUNT_MAGIC);
+}
+
+ulong bootcount_load (void)
+{
+	void *reg = (void *)(CONFIG_SYS_IMMR + CONFIG_BOOTCOUNT_ADDR);
+
+	if (in_be32 (reg + 4) != BOOTCOUNT_MAGIC)
+		return 0;
+	else
+		return in_be32 (reg);
+}
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c
index 491c2e5..8e9c875 100644
--- a/cpu/mpc83xx/cpu_init.c
+++ b/cpu/mpc83xx/cpu_init.c
@@ -106,7 +106,7 @@
 #ifdef CONFIG_SYS_SCCR_ENCCM
 	/* Encryption clock mode */
 	im->clk.sccr = (im->clk.sccr & ~SCCR_ENCCM) |
-		       (CONFIG_SYS_SCCR_ENCCM << SCCR_PCICM_SHIFT);
+		       (CONFIG_SYS_SCCR_ENCCM << SCCR_ENCCM_SHIFT);
 #endif
 
 #ifdef CONFIG_SYS_SCCR_PCICM
diff --git a/cpu/mpc83xx/fdt.c b/cpu/mpc83xx/fdt.c
index f890775..4cc9047 100644
--- a/cpu/mpc83xx/fdt.c
+++ b/cpu/mpc83xx/fdt.c
@@ -32,6 +32,20 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && defined(CONFIG_MPC8360)
+#include <asm/immap_qe.h>
+
+void fdt_fixup_muram (void *blob)
+{
+	ulong data[2];
+
+	data[0] = 0;
+	data[1] = QE_MURAM_SIZE - 2 * sizeof(unsigned long);
+	do_fixup_by_path(blob, "/qe/muram/data-only", "reg",
+		      data, sizeof (data), 0);
+}
+#endif
+
 void ft_cpu_setup(void *blob, bd_t *bd)
 {
 	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
@@ -83,4 +97,8 @@
 #endif
 
 	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT)
+	fdt_fixup_muram (blob);
+#endif
 }
diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c
index 5fe8964..a42b230 100644
--- a/cpu/mpc83xx/pci.c
+++ b/cpu/mpc83xx/pci.c
@@ -91,7 +91,7 @@
 	hose->regions[i].size = gd->ram_size;
 	hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
 
-	hose->first_busno = 0;
+	hose->first_busno = pci_last_busno() + 1;
 	hose->last_busno = 0xff;
 
 	pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80,
@@ -227,8 +227,8 @@
 
 		path = fdt_getprop(blob, nodeoffset, "pci1", NULL);
 		if (path) {
-			tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
-			tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+			tmp[0] = cpu_to_be32(pci_hose[1].first_busno);
+			tmp[1] = cpu_to_be32(pci_hose[1].last_busno);
 			do_fixup_by_path(blob, path, "bus-range",
 				&tmp, sizeof(tmp), 1);
 
diff --git a/cpu/mpc83xx/pcie.c b/cpu/mpc83xx/pcie.c
index 12b5f69..77f8906 100644
--- a/cpu/mpc83xx/pcie.c
+++ b/cpu/mpc83xx/pcie.c
@@ -60,6 +60,9 @@
 #define cfg_write(val, addr, type, op) \
 	do { op((type *)(addr), (val)); } while (0)
 
+#define cfg_read_err(val) do { *val = -1; } while (0)
+#define cfg_write_err(val) do { } while (0)
+
 #define PCIE_OP(rw, size, type, op)					\
 static int pcie_##rw##_config_##size(struct pci_controller *hose,	\
 				     pci_dev_t dev, int offset,		\
@@ -68,8 +71,10 @@
 	int ret;							\
 									\
 	ret = mpc83xx_pcie_remap_cfg(hose, dev);			\
-	if (ret)							\
-		return ret;						\
+	if (ret) {							\
+		cfg_##rw##_err(val); 					\
+		return ret; 						\
+	}								\
 	cfg_##rw(val, (void *)hose->cfg_addr + offset, type, op);	\
 	return 0;							\
 }
@@ -86,7 +91,6 @@
 {
 	extern void disable_addr_trans(void); /* start.S */
 	static struct pci_controller pcie_hose[PCIE_MAX_BUSES];
-	static int max_bus;
 	struct pci_controller *hose = &pcie_hose[bus];
 	int i;
 
@@ -117,7 +121,7 @@
 	hose->regions[i].size = 0x100000;
 	hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
 
-	hose->first_busno = max_bus;
+	hose->first_busno = pci_last_busno() + 1;
 	hose->last_busno = 0xff;
 
 	if (bus == 0)
@@ -145,7 +149,6 @@
 	 * Hose scan.
 	 */
 	hose->last_busno = pci_hose_scan(hose);
-	max_bus = hose->last_busno + 1;
 }
 
 #else
diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c
index 42a4e67..4704d20 100644
--- a/cpu/mpc83xx/spd_sdram.c
+++ b/cpu/mpc83xx/spd_sdram.c
@@ -219,7 +219,8 @@
 	ddr->cs_config[0] = ( 1 << 31
 			    | (odt_rd_cfg << 20)
 			    | (odt_wr_cfg << 16)
-			    | (spd.nrow_addr - 12) << 8
+			    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+			    | ((spd.nrow_addr - 12) << 8)
 			    | (spd.ncol_addr - 8) );
 	debug("\n");
 	debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds);
@@ -231,8 +232,9 @@
 		ddr->cs_config[1] = ( 1<<31
 				    | (odt_rd_cfg << 20)
 				    | (odt_wr_cfg << 16)
-				    | (spd.nrow_addr-12) << 8
-				    | (spd.ncol_addr-8) );
+				    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+				    | ((spd.nrow_addr - 12) << 8)
+				    | (spd.ncol_addr - 8) );
 		debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds);
 		debug("cs1_config = 0x%08x\n",ddr->cs_config[1]);
 	}
@@ -242,7 +244,8 @@
 	ddr->cs_config[2] = ( 1 << 31
 			    | (odt_rd_cfg << 20)
 			    | (odt_wr_cfg << 16)
-			    | (spd.nrow_addr - 12) << 8
+			    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+			    | ((spd.nrow_addr - 12) << 8)
 			    | (spd.ncol_addr - 8) );
 	debug("\n");
 	debug("cs2_bnds = 0x%08x\n",ddr->csbnds[2].csbnds);
@@ -254,8 +257,9 @@
 		ddr->cs_config[3] = ( 1<<31
 				    | (odt_rd_cfg << 20)
 				    | (odt_wr_cfg << 16)
-				    | (spd.nrow_addr-12) << 8
-				    | (spd.ncol_addr-8) );
+				    | ((spd.nbanks == 8 ? 1 : 0) << 14)
+				    | ((spd.nrow_addr - 12) << 8)
+				    | (spd.ncol_addr - 8) );
 		debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds);
 		debug("cs3_config = 0x%08x\n",ddr->cs_config[3]);
 	}
@@ -319,7 +323,20 @@
 	ddrc_clk = gd->mem_clk / 1000000;
 	effective_data_rate = 0;
 
-	if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
+	if (max_data_rate >= 460) { /* it is DDR2-800, 667, 533 */
+		if (spd.cas_lat & 0x08)
+			caslat = 3;
+		else
+			caslat = 4;
+		if (ddrc_clk <= 460 && ddrc_clk > 350)
+			effective_data_rate = 400;
+		else if (ddrc_clk <=350 && ddrc_clk > 280)
+			effective_data_rate = 333;
+		else if (ddrc_clk <= 280 && ddrc_clk > 230)
+			effective_data_rate = 266;
+		else
+			effective_data_rate = 200;
+	} else if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
 		if (ddrc_clk <= 460 && ddrc_clk > 350) {
 			/* DDR controller clk at 350~460 */
 			effective_data_rate = 400; /* 5ns */
@@ -466,6 +483,8 @@
 	} else {
 		twr_clk = picos_to_clk(spd.twr * 250);
 		twtr_clk = picos_to_clk(spd.twtr * 250);
+		if (twtr_clk < 2)
+			twtr_clk = 2;
 	}
 
 	/*
@@ -529,7 +548,7 @@
 	if (spd.mem_type == SPD_MEMTYPE_DDR2
 	    && (odt_wr_cfg || odt_rd_cfg)
 	    && (caslat < 4)) {
-		add_lat = trcd_clk - 1;
+		add_lat = 4 - caslat;
 		if ((add_lat + caslat) < 4) {
 			add_lat = 0;
 		}
@@ -566,6 +585,9 @@
 
 		/* Convert SPD value from quarter nanos to picos. */
 		trtp_clk = picos_to_clk(spd.trtp * 250);
+		if (trtp_clk < 2)
+			trtp_clk = 2;
+		trtp_clk += add_lat;
 
 		cke_min_clk = 3;	/* By the book. */
 		four_act = picos_to_clk(37500);	/* By the book. 1k pages? */
@@ -579,7 +601,9 @@
 	if (spd.mem_type == SPD_MEMTYPE_DDR2) {
 		if (effective_data_rate == 266) {
 			cpo = 0x4;		/* READ_LAT + 1/2 */
-		} else if (effective_data_rate == 333 || effective_data_rate == 400) {
+		} else if (effective_data_rate == 333) {
+			cpo = 0x6;		/* READ_LAT + 1 */
+		} else if (effective_data_rate == 400) {
 			cpo = 0x7;		/* READ_LAT + 5/4 */
 		} else {
 			/* Automatic calibration */
diff --git a/cpu/mpc83xx/u-boot.lds b/cpu/mpc83xx/u-boot.lds
index 3a08f64..7d57ee4 100644
--- a/cpu/mpc83xx/u-boot.lds
+++ b/cpu/mpc83xx/u-boot.lds
@@ -55,10 +55,8 @@
     *(.fixup)
     *(.got1)
     . = ALIGN(16);
-    *(.rodata)
-    *(.rodata1)
-    *(.rodata.str1.4)
     *(.eh_frame)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
   }
   .fini      : { *(.fini)    } =0
   .ctors     : { *(.ctors)   }
diff --git a/cpu/mpc85xx/ddr-gen3.c b/cpu/mpc85xx/ddr-gen3.c
index 8dc2b3a..99c325a 100644
--- a/cpu/mpc85xx/ddr-gen3.c
+++ b/cpu/mpc85xx/ddr-gen3.c
@@ -79,8 +79,8 @@
 	out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
 	out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
 
-	/* Do not enable the memory */
-	temp_sdram_cfg = in_be32(&ddr->sdram_cfg);
+	/* Set, but do not enable the memory */
+	temp_sdram_cfg = regs->ddr_sdram_cfg;
 	temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
 	out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
 	/*
diff --git a/cpu/mpc8xx/start.S b/cpu/mpc8xx/start.S
index 45c902e..8864c37 100644
--- a/cpu/mpc8xx/start.S
+++ b/cpu/mpc8xx/start.S
@@ -142,7 +142,7 @@
 	lis	r3, IDC_DISABLE@h	/* Disable data cache */
 	mtspr	DC_CST, r3
 
-#if !(defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || defined (CONFIG_FLAGADM))
+#if !defined(CONFIG_SYS_DELAYED_ICACHE)
 					/* On IP860 and PCU E,
 					 * we cannot enable IC yet
 					 */
diff --git a/cpu/ppc4xx/4xx_pci.c b/cpu/ppc4xx/4xx_pci.c
index 6fd36de..99b8e2f 100644
--- a/cpu/ppc4xx/4xx_pci.c
+++ b/cpu/ppc4xx/4xx_pci.c
@@ -550,10 +550,12 @@
 	out32r( PCIX0_POM0SA, 0 ); /* disable */
 	out32r( PCIX0_POM1SA, 0 ); /* disable */
 	out32r( PCIX0_POM2SA, 0 ); /* disable */
-#if defined(CONFIG_440SPE) || \
-    defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#if defined(CONFIG_440SPE)
 	out32r( PCIX0_POM0LAL, 0x10000000 );
 	out32r( PCIX0_POM0LAH, 0x0000000c );
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+	out32r( PCIX0_POM0LAL, 0x20000000 );
+	out32r( PCIX0_POM0LAH, 0x0000000c );
 #else
 	out32r( PCIX0_POM0LAL, 0x00000000 );
 	out32r( PCIX0_POM0LAH, 0x00000003 );
diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c
index b5d81f2..577d33f 100644
--- a/cpu/ppc4xx/cpu_init.c
+++ b/cpu/ppc4xx/cpu_init.c
@@ -321,34 +321,10 @@
  */
 int cpu_init_r (void)
 {
-#if defined(CONFIG_405GP)  || defined(CONFIG_405EP)
-	bd_t *bd = gd->bd;
-	unsigned long reg;
 #if defined(CONFIG_405GP)
 	uint pvr = get_pvr();
-#endif
 
 	/*
-	 * Write Ethernetaddress into on-chip register
-	 */
-	reg = 0x00000000;
-	reg |= bd->bi_enetaddr[0];           /* set high address */
-	reg = reg << 8;
-	reg |= bd->bi_enetaddr[1];
-	out32 (EMAC_IAH, reg);
-
-	reg = 0x00000000;
-	reg |= bd->bi_enetaddr[2];           /* set low address  */
-	reg = reg << 8;
-	reg |= bd->bi_enetaddr[3];
-	reg = reg << 8;
-	reg |= bd->bi_enetaddr[4];
-	reg = reg << 8;
-	reg |= bd->bi_enetaddr[5];
-	out32 (EMAC_IAL, reg);
-
-#if defined(CONFIG_405GP)
-	/*
 	 * Set edge conditioning circuitry on PPC405GPr
 	 * for compatibility to existing PPC405GP designs.
 	 */
@@ -356,7 +332,6 @@
 		mtdcr(ecr, 0x60606000);
 	}
 #endif  /* defined(CONFIG_405GP) */
-#endif  /* defined(CONFIG_405GP) || defined(CONFIG_405EP) */
 
-	return (0);
+	return 0;
 }
diff --git a/cpu/pxa/interrupts.c b/cpu/pxa/interrupts.c
index 40d8bf2..2bc5c50 100644
--- a/cpu/pxa/interrupts.c
+++ b/cpu/pxa/interrupts.c
@@ -28,6 +28,7 @@
 
 #include <common.h>
 #include <asm/arch/pxa-regs.h>
+#include <div64.h>
 
 #ifdef CONFIG_USE_IRQ
 #error: interrupts not implemented yet
@@ -41,6 +42,20 @@
 #error "Timer frequency unknown - please config PXA CPU type"
 #endif
 
+static inline unsigned long long tick_to_time(unsigned long long tick)
+{
+	tick *= CONFIG_SYS_HZ;
+	do_div(tick, TIMER_FREQ_HZ);
+	return tick;
+}
+
+static inline unsigned long long us_to_tick(unsigned long long us)
+{
+	us = us * TIMER_FREQ_HZ + 999999;
+	do_div(us, 1000000);
+	return us;
+}
+
 int interrupt_init (void)
 {
 	/* nothing happens here - we don't setup any IRQs */
@@ -75,33 +90,20 @@
 
 ulong get_timer_masked (void)
 {
-	unsigned long long ticks = get_ticks();
-
-	return (((ticks / TIMER_FREQ_HZ) * 1000) +
-	        ((ticks % TIMER_FREQ_HZ) * 1000) / TIMER_FREQ_HZ);
+	return tick_to_time(get_ticks());
 }
 
 void udelay_masked (unsigned long usec)
 {
+	unsigned long long tmp;
 	ulong tmo;
-	ulong endtime;
-	signed long diff;
 
-	if (usec >= 1000) {
-		tmo = usec / 1000;
-		tmo *= TIMER_FREQ_HZ;
-		tmo /= 1000;
-	} else {
-		tmo = usec * TIMER_FREQ_HZ;
-		tmo /= (1000*1000);
-	}
+	tmo = us_to_tick(usec);
+	tmp = get_ticks() + tmo;	/* get current timestamp */
 
-	endtime = get_ticks() + tmo;
+	while (get_ticks() < tmp)	/* loop till event */
+		 /*NOP*/;
 
-	do {
-		ulong now = get_ticks();
-		diff = endtime - now;
-	} while (diff >= 0);
 }
 
 /*
diff --git a/cpu/sh4/cpu.c b/cpu/sh4/cpu.c
index 52b6cfd..be410ab 100644
--- a/cpu/sh4/cpu.c
+++ b/cpu/sh4/cpu.c
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <netdev.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
diff --git a/disk/part.c b/disk/part.c
index e353cee..fdc49d3 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -184,7 +184,7 @@
 			printf ("            Supports 48-bit addressing\n");
 #endif
 #if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
-		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%qd x %ld)\n",
+		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
 			mb_quot, mb_rem,
 			gb_quot, gb_rem,
 			lba,
diff --git a/doc/README.enetaddr b/doc/README.enetaddr
new file mode 100644
index 0000000..1d75aa3
--- /dev/null
+++ b/doc/README.enetaddr
@@ -0,0 +1,99 @@
+---------------------------------
+ Ethernet Address (MAC) Handling
+---------------------------------
+
+There are a variety of places in U-Boot where the MAC address is used, parsed,
+and stored.  This document covers proper usage of each location and the moving
+of data between them.
+
+-----------
+ Locations
+-----------
+
+Here are the places where MAC addresses might be stored:
+
+ - board-specific location (eeprom, dedicated flash, ...)
+	Note: only used when mandatory due to hardware design etc...
+
+ - environment ("ethaddr", "eth1addr", ...) (see CONFIG_ETHADDR)
+	Note: this is the preferred way to permanently store MAC addresses
+
+ - ethernet data (struct eth_device -> enetaddr)
+	Note: these are temporary copies of the MAC address which exist only
+	      after the respective init steps have run and only to make usage
+	      in other places easier (to avoid constant env lookup/parsing)
+
+ - struct bd_info and/or device tree
+	Note: these are temporary copies of the MAC address only for the
+	      purpose of passing this information to an OS kernel we are about
+	      to boot
+
+-------
+ Usage
+-------
+
+If the hardware design mandates that the MAC address is stored in some special
+place (like EEPROM etc...), then the board specific init code (such as the
+board-specific misc_init_r() function) is responsible for locating the MAC
+address(es) and initializing the respective environment variable(s) from it.
+Note that this shall be done if, and only if, the environment does not already
+contain these environment variables, i.e. existing variable definitions must
+not be overwritten.
+
+During runtime, the ethernet layer will use the environment variables to sync
+the MAC addresses to the ethernet structures.  All ethernet driver code should
+then only use the enetaddr member of the eth_device structure.  This is done
+on every network command, so the ethernet copies will stay in sync.
+
+Any other code that wishes to access the MAC address should query the
+environment directly.  The helper functions documented below should make
+working with this storage much smoother.
+
+---------
+ Helpers
+---------
+
+To assist in the management of these layers, a few helper functions exist.  You
+should use these rather than attempt to do any kind of parsing/manipulation
+yourself as many common errors have arisen in the past.
+
+	* void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
+
+Convert a string representation of a MAC address to the binary version.
+char *addr = "00:11:22:33:44:55";
+uchar enetaddr[6];
+eth_parse_enetaddr(addr, enetaddr);
+/* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */
+
+	* int eth_getenv_enetaddr(char *name, uchar *enetaddr);
+
+Look up an environment variable and convert the stored address.  If the address
+is valid, then the function returns 1.  Otherwise, the function returns 0.  In
+all cases, the enetaddr memory is initialized.  If the env var is not found,
+then it is set to all zeros.  The common function is_valid_ether_addr() is used
+to determine address validity.
+uchar enetaddr[6];
+if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+	/* "ethaddr" is not set in the environment */
+	... try and setup "ethaddr" in the env ...
+}
+/* enetaddr is now set to the value stored in the ethaddr env var */
+
+	* int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
+
+Store the MAC address into the named environment variable.  The return value is
+the same as the setenv() function.
+uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+eth_setenv_enetaddr("ethaddr", enetaddr);
+/* the "ethaddr" env var should now be set to "00:11:22:33:44:55" */
+
+	* the %pM format modifier
+
+The %pM format modifier can be used with any standard printf function to format
+the binary 6 byte array representation of a MAC address.
+uchar enetaddr[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+printf("The MAC is %pM\n", enetaddr);
+
+char buf[20];
+sprintf(buf, "%pM", enetaddr);
+/* the buf variable is now set to "00:11:22:33:44:55" */
diff --git a/doc/README.sh7785lcr b/doc/README.sh7785lcr
index c8d8ccd..56455fc 100644
--- a/doc/README.sh7785lcr
+++ b/doc/README.sh7785lcr
@@ -33,6 +33,38 @@
  0x40000000 - 0x5fffffff	| DDR SDRAM	| (cannot use)
 
 
+configuration for This board:
+=============================
+
+You can choose configuration as follows:
+
+ - make sh7785lcr_config
+ - make sh7785lcr_32bit_config
+
+When you use "make sh7785lcr_config", there is build U-Boot for 29-bit
+address mode. This mode can use 128MB DDR-SDRAM.
+
+When you use "make sh7785lcr_32bit_config", there is build U-Boot for 32-bit
+extended address mode. This mode can use 384MB DDR-SDRAM. And if you run
+"pmb" command, this mode can use 512MB DDR-SDRAM.
+
+ * 32-bit extended address mode PMB mapping *
+  a) on start-up
+   virt		| phys		| size		| device
+   -------------+---------------+---------------+---------------
+   0x88000000	| 0x48000000	| 384MB		| DDR-SDRAM (Cacheable)
+   0xa0000000	| 0x00000000	| 64MB		| NOR Flash
+   0xa4000000	| 0x04000000	| 16MB		| PLD
+   0xa6000000	| 0x08000000	| 16MB		| USB
+   0xa8000000	| 0x48000000	| 384MB		| DDR-SDRAM (Non-cacheable)
+
+  b) after "pmb" command
+   virt		| phys		| size		| device
+   -------------+---------------+---------------+---------------
+   0x80000000	| 0x40000000	| 512MB		| DDR-SDRAM (Cacheable)
+   0xa0000000	| 0x40000000	| 512MB		| DDR-SDRAM (Non-cacheable)
+
+
 This board specific command:
 ============================
 
@@ -41,6 +73,7 @@
  - hwtest
  - printmac
  - setmac
+ - pmb (sh7785lcr_32bit_config only)
 
 
 1. hwtest
@@ -80,3 +113,11 @@
 
 i.e)
 => setmac 00:00:87:**:**:**
+
+
+4. pmb
+
+This command change PMB for DDR-SDRAM all mapping. However you cannot use
+NOR Flash and USB Host on U-Boot when you run this command.
+i.e)
+=> pmb
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index dd618ed..f10144f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -25,7 +25,8 @@
 
 LIB 	:= $(obj)libgpio.a
 
-COBJS-$(CONFIG_PCA953X)	+= pca953x.o
+COBJS-$(CONFIG_MX31_GPIO)	+= mx31_gpio.o
+COBJS-$(CONFIG_PCA953X)		+= pca953x.o
 
 COBJS	:= $(COBJS-y)
 SRCS 	:= $(COBJS:.o=.c)
diff --git a/drivers/gpio/mx31_gpio.c b/drivers/gpio/mx31_gpio.c
new file mode 100644
index 0000000..737aafa
--- /dev/null
+++ b/drivers/gpio/mx31_gpio.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@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
+ */
+#include <common.h>
+#include <asm/arch/mx31.h>
+#include <asm/arch/mx31-regs.h>
+
+/* GPIO port description */
+static unsigned long gpio_ports[] = {
+	[0] = GPIO1_BASE,
+	[1] = GPIO2_BASE,
+	[2] = GPIO3_BASE,
+};
+
+int mx31_gpio_direction(unsigned int gpio, enum mx31_gpio_direction direction)
+{
+	unsigned int port = gpio >> 5;
+	u32 l;
+
+	if (port >= ARRAY_SIZE(gpio_ports))
+		return 1;
+
+	gpio &= 0x1f;
+
+	l = __REG(gpio_ports[port] + GPIO_GDIR);
+	switch (direction) {
+	case MX31_GPIO_DIRECTION_OUT:
+		l |= 1 << gpio;
+		break;
+	case MX31_GPIO_DIRECTION_IN:
+		l &= ~(1 << gpio);
+	}
+	__REG(gpio_ports[port] + GPIO_GDIR) = l;
+
+	return 0;
+}
+
+void mx31_gpio_set(unsigned int gpio, unsigned int value)
+{
+	unsigned int port = gpio >> 5;
+	u32 l;
+
+	if (port >= ARRAY_SIZE(gpio_ports))
+		return;
+
+	gpio &= 0x1f;
+
+	l = __REG(gpio_ports[port] + GPIO_DR);
+	if (value)
+		l |= 1 << gpio;
+	else
+		l &= ~(1 << gpio);
+	__REG(gpio_ports[port] + GPIO_DR) = l;
+}
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index ce646fd..6ab7d3d 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -42,6 +42,9 @@
 #define CONFIG_SYS_SPD_BUS_NUM 0
 #endif
 static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM;
+#if defined(CONFIG_I2C_MUX)
+static unsigned int i2c_bus_num_mux __attribute__ ((section ("data"))) = 0;
+#endif
 
 static unsigned int i2c_bus_speed[2] = {CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED};
 
@@ -369,6 +372,19 @@
 
 int i2c_set_bus_num(unsigned int bus)
 {
+#if defined(CONFIG_I2C_MUX)
+	if (bus < CONFIG_SYS_MAX_I2C_BUS) {
+		i2c_bus_num = bus;
+	} else {
+		int	ret;
+
+		ret = i2x_mux_select_mux(bus);
+		if (ret)
+			return ret;
+		i2c_bus_num = 0;
+	}
+	i2c_bus_num_mux = bus;
+#else
 #ifdef CONFIG_SYS_I2C2_OFFSET
 	if (bus > 1) {
 #else
@@ -378,7 +394,7 @@
 	}
 
 	i2c_bus_num = bus;
-
+#endif
 	return 0;
 }
 
@@ -396,7 +412,11 @@
 
 unsigned int i2c_get_bus_num(void)
 {
+#if defined(CONFIG_I2C_MUX)
+	return i2c_bus_num_mux;
+#else
 	return i2c_bus_num;
+#endif
 }
 
 unsigned int i2c_get_bus_speed(void)
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index da6cec1..ed5f5b2 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -40,7 +40,7 @@
 #ifdef CONFIG_LPC2292
 #include <asm/arch/hardware.h>
 #endif
-#ifdef	CONFIG_MPC866			/* only valid for MPC866 */
+#if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
 #include <asm/io.h>
 #endif
 #include <i2c.h>
diff --git a/drivers/misc/ali512x.c b/drivers/misc/ali512x.c
index d6a2c1f..cda3b0d 100644
--- a/drivers/misc/ali512x.c
+++ b/drivers/misc/ali512x.c
@@ -34,7 +34,7 @@
 
 #include <common.h>
 #include <asm/io.h>
-#include <asm/ic/ali512x.h>
+#include <ali512x.h>
 
 
 /* ALI M5123 Logical device numbers:
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index a66feac..391d169 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1806,8 +1806,9 @@
 	if (qry->num_erase_regions > 1) {
 		/* reverse geometry if top boot part */
 		if (info->cfi_version < 0x3131) {
-			/* CFI < 1.1, guess by device id (only M29W320ET now) */
-			if (info->device_id == 0x2256) {
+			/* CFI < 1.1, guess by device id (M29W320{DT,ET} only) */
+			if (info->device_id == 0x22CA ||
+			    info->device_id == 0x2256) {
 				cfi_reverse_geometry(qry);
 			}
 		}
diff --git a/drivers/net/3c589.c b/drivers/net/3c589.c
index 0cf8dff..f2c7d32 100644
--- a/drivers/net/3c589.c
+++ b/drivers/net/3c589.c
@@ -259,10 +259,13 @@
 
 	/* set mac addr */
 	{
-		unsigned char *mac_addr = bd->bi_enetaddr;
+		uchar mac_addr[6];
 		int i;
 
-		el_get_mac_addr( mac_addr );
+		if (!eth_getenv_enetaddr("ethaddr", mac_addr)) {
+			el_get_mac_addr(mac_addr);
+			eth_setenv_enetaddr("ethaddr", mac_addr);
+		}
 
 		GO_WINDOW(2);
 		VX_BUSY_WAIT;
diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c
index 1978269..918373b 100644
--- a/drivers/net/4xx_enet.c
+++ b/drivers/net/4xx_enet.c
@@ -1927,24 +1927,22 @@
 		memcpy(ethaddr[eth_num], "\0\0\0\0\0\0", 6);
 
 	for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) {
+		int ethaddr_idx = eth_num + CONFIG_EMAC_NR_START;
 		switch (eth_num) {
 		default:		/* fall through */
 		case 0:
-			memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
-			       bis->bi_enetaddr, 6);
+			eth_getenv_enetaddr("ethaddr", ethaddr[ethaddr_idx]);
 			hw_addr[eth_num] = 0x0;
 			break;
 #ifdef CONFIG_HAS_ETH1
 		case 1:
-			memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
-			       bis->bi_enet1addr, 6);
+			eth_getenv_enetaddr("eth1addr", ethaddr[ethaddr_idx]);
 			hw_addr[eth_num] = 0x100;
 			break;
 #endif
 #ifdef CONFIG_HAS_ETH2
 		case 2:
-			memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
-			       bis->bi_enet2addr, 6);
+			eth_getenv_enetaddr("eth2addr", ethaddr[ethaddr_idx]);
 #if defined(CONFIG_460GT)
 			hw_addr[eth_num] = 0x300;
 #else
@@ -1954,8 +1952,7 @@
 #endif
 #ifdef CONFIG_HAS_ETH3
 		case 3:
-			memcpy(ethaddr[eth_num + CONFIG_EMAC_NR_START],
-			       bis->bi_enet3addr, 6);
+			eth_getenv_enetaddr("eth3addr", ethaddr[ethaddr_idx]);
 #if defined(CONFIG_460GT)
 			hw_addr[eth_num] = 0x400;
 #else
diff --git a/drivers/net/bcm570x.c b/drivers/net/bcm570x.c
index 185764e..c250d44 100644
--- a/drivers/net/bcm570x.c
+++ b/drivers/net/bcm570x.c
@@ -450,8 +450,8 @@
 			    + 1);
 	strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
 
-	memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6);
-	LM_SetMacAddress (pDevice, bis->bi_enetaddr);
+	eth_getenv_enetaddr("ethaddr", pDevice->NodeAddress);
+	LM_SetMacAddress (pDevice);
 	/* Init queues  .. */
 	QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
 		      MAX_RX_PACKET_DESC_COUNT);
diff --git a/drivers/net/bcm570x_lm.h b/drivers/net/bcm570x_lm.h
index 2ea6ca8..c07b767 100644
--- a/drivers/net/bcm570x_lm.h
+++ b/drivers/net/bcm570x_lm.h
@@ -371,7 +371,7 @@
 LM_STATUS LM_MulticastAdd (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
 LM_STATUS LM_MulticastDel (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress);
 LM_STATUS LM_MulticastClear (PLM_DEVICE_BLOCK pDevice);
-LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress);
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice);
 LM_STATUS LM_LoopbackAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pAddress);
 
 LM_UINT32 LM_GetCrcCounter (PLM_DEVICE_BLOCK pDevice);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 23f934a..12d98c2 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -315,7 +315,7 @@
 		return -1;
 
 	/* Initialize EMAC address */
-	bfin_EMAC_setup_addr(bd);
+	bfin_EMAC_setup_addr(dev->enetaddr);
 
 	/* Initialize TX and RX buffer */
 	for (i = 0; i < PKTBUFSRX; i++) {
@@ -373,16 +373,16 @@
 
 }
 
-void bfin_EMAC_setup_addr(bd_t *bd)
+void bfin_EMAC_setup_addr(uchar *enetaddr)
 {
 	*pEMAC_ADDRLO =
-		bd->bi_enetaddr[0] |
-		bd->bi_enetaddr[1] << 8 |
-		bd->bi_enetaddr[2] << 16 |
-		bd->bi_enetaddr[3] << 24;
+		enetaddr[0] |
+		enetaddr[1] << 8 |
+		enetaddr[2] << 16 |
+		enetaddr[3] << 24;
 	*pEMAC_ADDRHI =
-		bd->bi_enetaddr[4] |
-		bd->bi_enetaddr[5] << 8;
+		enetaddr[4] |
+		enetaddr[5] << 8;
 }
 
 ADI_ETHER_BUFFER *SetupRxBuffer(int no)
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index 084f533..8f467a3 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -61,6 +61,6 @@
 static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length);
 static int bfin_EMAC_recv(struct eth_device *dev);
 
-static void bfin_EMAC_setup_addr(bd_t *bd);
+void bfin_EMAC_setup_addr(uchar *enetaddr);
 
 #endif
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index 35a9baf..0557fcd 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -110,18 +110,14 @@
 	put_reg (PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
 }
 
-void cs8900_get_enetaddr (uchar * addr)
+void cs8900_get_enetaddr (void)
 {
 	int i;
-	unsigned char env_enetaddr[6];
-	char *tmp = getenv ("ethaddr");
-	char *end;
+	uchar enetaddr[6];
 
-	for (i=0; i<6; i++) {
-		env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
-		if (tmp)
-			tmp = (*end) ? end+1 : end;
-	}
+	/* if the env is setup, then bail */
+	if (eth_getenv_enetaddr("ethaddr", enetaddr))
+		return;
 
 	/* verify chip id */
 	if (get_reg_init_bus (PP_ChipID) != 0x630e)
@@ -135,35 +131,12 @@
 			unsigned int Addr;
 
 			Addr = get_reg (PP_IA + i * 2);
-			addr[i * 2] = Addr & 0xFF;
-			addr[i * 2 + 1] = Addr >> 8;
+			enetaddr[i * 2] = Addr & 0xFF;
+			enetaddr[i * 2 + 1] = Addr >> 8;
 		}
 
-		if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6) != 0 &&
-		    memcmp(env_enetaddr, addr, 6) != 0) {
-			printf ("\nWarning: MAC addresses don't match:\n");
-			printf ("\tHW MAC address:  "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				addr[0], addr[1],
-				addr[2], addr[3],
-				addr[4], addr[5] );
-			printf ("\t\"ethaddr\" value: "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				env_enetaddr[0], env_enetaddr[1],
-				env_enetaddr[2], env_enetaddr[3],
-				env_enetaddr[4], env_enetaddr[5]) ;
-			debug ("### Set MAC addr from environment\n");
-			memcpy (addr, env_enetaddr, 6);
-		}
-		if (!tmp) {
-			char ethaddr[20];
-			sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
-				 addr[0], addr[1],
-				 addr[2], addr[3],
-				 addr[4], addr[5]) ;
-			debug ("### Set environment from HW MAC addr = \"%s\"\n", ethaddr);
-			setenv ("ethaddr", ethaddr);
-		}
+		eth_setenv_enetaddr("ethaddr", enetaddr);
+		debug("### Set environment from HW MAC addr = \"%pM\"\n", enetaddr);
 	}
 }
 
@@ -178,6 +151,8 @@
 
 int eth_init (bd_t * bd)
 {
+	uchar *enetaddr[6];
+
 	/* verify chip id */
 	if (get_reg_init_bus (PP_ChipID) != 0x630e) {
 		printf ("CS8900 Ethernet chip not found?!\n");
@@ -186,9 +161,10 @@
 
 	eth_reset ();
 	/* set the ethernet address */
-	put_reg (PP_IA + 0, bd->bi_enetaddr[0] | (bd->bi_enetaddr[1] << 8));
-	put_reg (PP_IA + 2, bd->bi_enetaddr[2] | (bd->bi_enetaddr[3] << 8));
-	put_reg (PP_IA + 4, bd->bi_enetaddr[4] | (bd->bi_enetaddr[5] << 8));
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	put_reg (PP_IA + 0, enetaddr[0] | (enetaddr[1] << 8));
+	put_reg (PP_IA + 2, enetaddr[2] | (enetaddr[3] << 8));
+	put_reg (PP_IA + 4, enetaddr[4] | (enetaddr[5] << 8));
 
 	eth_reginit ();
 	return 0;
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index c0137a7..5ae53e8 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -752,11 +752,14 @@
 		0x0000, 0x0000, 0x0000, 0x0000,	/* 38 */
 		0x0000, 0x0000, 0x0000, 0x4e07,	/* 3c */
 	};
+	uchar enetaddr[6];
 
 	/* Ethernet Addr... */
-	eeprom[0x0a] = ((bis->bi_enetaddr[1] & 0xff) << 8) | (bis->bi_enetaddr[0] & 0xff);
-	eeprom[0x0b] = ((bis->bi_enetaddr[3] & 0xff) << 8) | (bis->bi_enetaddr[2] & 0xff);
-	eeprom[0x0c] = ((bis->bi_enetaddr[5] & 0xff) << 8) | (bis->bi_enetaddr[4] & 0xff);
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr))
+		return;
+	eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
+	eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
+	eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
 
 	for (i=0; i<0x40; i++) {
 		write_srom(dev, DE4X5_APROM, i, eeprom[i]);
diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c
index ffb739d..c52d307 100644
--- a/drivers/net/dm9000x.c
+++ b/drivers/net/dm9000x.c
@@ -287,6 +287,7 @@
 	int i, oft, lnk;
 	u8 io_mode;
 	struct board_info *db = &dm9000_info;
+	uchar enetaddr[6];
 
 	DM9000_DBG("eth_init()\n");
 
@@ -345,32 +346,19 @@
 	DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
 
 	/* Set Node address */
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
 #if !defined(CONFIG_AT91SAM9261EK)
-	for (i = 0; i < 6; i++)
-		((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
+		for (i = 0; i < 6; i++)
+			enetaddr[i] = read_srom_word(i);
+		eth_setenv_enetaddr("ethaddr", enetaddr);
 #endif
-
-	if (is_zero_ether_addr(bd->bi_enetaddr) ||
-	    is_multicast_ether_addr(bd->bi_enetaddr)) {
-		/* try reading from environment */
-		u8 i;
-		char *s, *e;
-		s = getenv ("ethaddr");
-		for (i = 0; i < 6; ++i) {
-			bd->bi_enetaddr[i] = s ?
-				simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
 	}
 
-	printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
-	       bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
-	       bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
+	printf("MAC: %pM\n", enetaddr);
 
 	/* fill device MAC address registers */
 	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
-		DM9000_iow(oft, bd->bi_enetaddr[i]);
+		DM9000_iow(oft, enetaddr[i]);
 	for (i = 0, oft = 0x16; i < 8; i++, oft++)
 		DM9000_iow(oft, 0xff);
 
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 5c24b0d..3238a50 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -330,6 +330,7 @@
 int eth_init (bd_t * bis)
 {
 	unsigned char estatVal;
+	uchar enetaddr[6];
 
 	/* configure GPIO */
 	(*((volatile unsigned long *) IO1DIR)) |= ENC_SPI_SLAVE_CS;
@@ -351,7 +352,8 @@
 
 	/* initialize controller */
 	encReset ();
-	encInit (bis->bi_enetaddr);
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	encInit (enetaddr);
 
 	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
 
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
index d056010..35a6dfb 100644
--- a/drivers/net/fsl_mcdmafec.c
+++ b/drivers/net/fsl_mcdmafec.c
@@ -369,6 +369,7 @@
 	struct fec_info_dma *info = dev->priv;
 	volatile fecdma_t *fecp = (fecdma_t *) (info->iobase);
 	int i;
+	uchar enetaddr[6];
 
 #ifdef ET_DEBUG
 	printf("fec_init: iobase 0x%08x ...\n", info->iobase);
@@ -397,11 +398,11 @@
 	fecp->eir = 0xffffffff;
 
 	/* Set station address   */
-	if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
-		fec_set_hwaddr(fecp, bd->bi_enetaddr);
-	} else {
-		fec_set_hwaddr(fecp, bd->bi_enet1addr);
-	}
+	if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE)
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+	else
+		eth_getenv_enetaddr("eth1addr", enetaddr);
+	fec_set_hwaddr(fecp, enetaddr);
 
 	/* Set Opcode/Pause Duration Register */
 	fecp->opd = 0x00010020;
diff --git a/drivers/net/ks8695eth.c b/drivers/net/ks8695eth.c
index 7f3e0c2..5ea6e7f 100644
--- a/drivers/net/ks8695eth.c
+++ b/drivers/net/ks8695eth.c
@@ -150,13 +150,7 @@
 	ks8695_write(KS8695_LAN_DMA_RX, 0x71);
 	ks8695_write(KS8695_LAN_DMA_RX_START, 0x1);
 
-	printf("KS8695 ETHERNET: ");
-	for (i = 0; (i < 5); i++) {
-		bd->bi_enetaddr[i] = eth_mac[i];
-		printf("%02x:", eth_mac[i]);
-	}
-	bd->bi_enetaddr[i] = eth_mac[i];
-	printf("%02x\n", eth_mac[i]);
+	printf("KS8695 ETHERNET: %pM\n", eth_mac);
 }
 
 /****************************************************************************/
diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c
index 318bdf4..65565bc 100644
--- a/drivers/net/lan91c96.c
+++ b/drivers/net/lan91c96.c
@@ -606,10 +606,8 @@
 	SMC_SELECT_BANK (1);
 
 	err = smc_get_ethaddr (bd);	/* set smc_mac_addr, and sync it with u-boot globals */
-	if (err < 0) {
-		memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
-		return (-1);	/* upper code ignores this, but NOT bi_enetaddr */
-	}
+	if (err < 0)
+		return -1;
 #ifdef USE_32_BIT
 	for (i = 0; i < 6; i += 2) {
 		word address;
@@ -869,69 +867,20 @@
 
 int smc_get_ethaddr (bd_t * bd)
 {
-	int env_size = 0;
-	int rom_valid = 0;
-	int env_present = 0;
-	int reg = 0;
-	char *s = NULL;
-	char *e = NULL;
-	char *v_mac, es[] = "11:22:33:44:55:66";
-	char s_env_mac[64];
-	uchar v_env_mac[6];
-	uchar v_rom_mac[6];
+	uchar v_mac[6];
 
-	env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
-	if (env_size != sizeof(es)) {	/* Ignore if env is bad or not set */
-		printf ("\n*** Warning: ethaddr is not set properly, ignoring!!\n");
-	} else {
-		env_present = 1;
-		s = s_env_mac;
-
-		for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
-			v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
+	if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
+		/* get ROM mac value if any */
+		if (!get_rom_mac(v_mac)) {
+			printf("\n*** ERROR: ethaddr is NOT set !!\n");
+			return -1;
 		}
+		eth_setenv_enetaddr("ethaddr", v_mac);
 	}
 
-	rom_valid = get_rom_mac (v_rom_mac);	/* get ROM mac value if any */
-
-	if (!env_present) {	/* if NO env */
-		if (rom_valid) {	/* but ROM is valid */
-			v_mac = (char *)v_rom_mac;
-			sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
-				 v_mac[0], v_mac[1], v_mac[2], v_mac[3],
-				 v_mac[4], v_mac[5]);
-			setenv ("ethaddr", s_env_mac);
-		} else {	/* no env, bad ROM */
-			printf ("\n*** ERROR: ethaddr is NOT set !!\n");
-			return (-1);
-		}
-	} else {		/* good env, don't care ROM */
-		v_mac = (char *)v_env_mac;	/* always use a good env over a ROM */
-	}
-
-	if (env_present && rom_valid) { /* if both env and ROM are good */
-		if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
-			printf ("\nWarning: MAC addresses don't match:\n");
-			printf ("\tHW MAC address:  "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				v_rom_mac[0], v_rom_mac[1],
-				v_rom_mac[2], v_rom_mac[3],
-				v_rom_mac[4], v_rom_mac[5] );
-			printf ("\t\"ethaddr\" value: "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				v_env_mac[0], v_env_mac[1],
-				v_env_mac[2], v_env_mac[3],
-				v_env_mac[4], v_env_mac[5]) ;
-			debug ("### Set MAC addr from environment\n");
-		}
-	}
-	memcpy (bd->bi_enetaddr, v_mac, 6);	/* update global address to match env (allows env changing) */
-	smc_set_mac_addr ((unsigned char *)v_mac); /* use old function to update smc default */
-	PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
-		v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
-	return (0);
+	smc_set_mac_addr(v_mac); /* use old function to update smc default */
+	PRINTK("Using MAC Address %pM\n", v_mac);
+	return 0;
 }
 
 /*
diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c
index 18240a8..64be5de 100644
--- a/drivers/net/mcffec.c
+++ b/drivers/net/mcffec.c
@@ -416,7 +416,7 @@
 	struct fec_info_s *info = dev->priv;
 	volatile fec_t *fecp = (fec_t *) (info->iobase);
 	int i;
-	u8 *ea = NULL;
+	uchar ea[6];
 
 	fecpin_setclear(dev, 1);
 
@@ -444,25 +444,25 @@
 	if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
 #ifdef CONFIG_SYS_FEC1_IOBASE
 		volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE);
-		ea = &bd->bi_enet1addr[0];
+		eth_getenv_enetaddr("eth1addr", ea);
 		fecp1->palr =
 		    (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
 		fecp1->paur = (ea[4] << 24) | (ea[5] << 16);
 #endif
-		ea = &bd->bi_enetaddr[0];
+		eth_getenv_enetaddr("ethaddr", ea);
 		fecp->palr =
 		    (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
 		fecp->paur = (ea[4] << 24) | (ea[5] << 16);
 	} else {
 #ifdef CONFIG_SYS_FEC0_IOBASE
 		volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE);
-		ea = &bd->bi_enetaddr[0];
+		eth_getenv_enetaddr("ethaddr", ea);
 		fecp0->palr =
 		    (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
 		fecp0->paur = (ea[4] << 24) | (ea[5] << 16);
 #endif
 #ifdef CONFIG_SYS_FEC1_IOBASE
-		ea = &bd->bi_enet1addr[0];
+		eth_getenv_enetaddr("eth1addr", ea);
 		fecp->palr =
 		    (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
 		fecp->paur = (ea[4] << 24) | (ea[5] << 16);
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index 2bf901e..0f1d1af 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -281,13 +281,6 @@
 	}
 
 	fec->eth->x_cntrl = 0x00000000;	/* half-duplex, heartbeat disabled */
-	if (fec->xcv_type != SEVENWIRE) {
-		/*
-		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
-		 * and do not drop the Preamble.
-		 */
-		fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
-	}
 
 	/*
 	 * Set Opcode/Pause Duration Register
@@ -640,6 +633,15 @@
 	 */
 	udelay(10);
 
+	/* don't leave the MII speed set to zero */
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
+	}
+
 #if (DEBUG & 0x3)
 	printf("Ethernet task stopped\n");
 #endif
@@ -897,6 +899,13 @@
 #else
 #error fec->xcv_type not initialized.
 #endif
+	if (fec->xcv_type != SEVENWIRE) {
+		/*
+		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+		 * and do not drop the Preamble.
+		 */
+		fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
+	}
 
 	dev->priv = (void *)fec;
 	dev->iobase = MPC5XXX_FEC;
diff --git a/drivers/net/rtl8019.c b/drivers/net/rtl8019.c
index 3ddf917..f516afe 100644
--- a/drivers/net/rtl8019.c
+++ b/drivers/net/rtl8019.c
@@ -91,6 +91,7 @@
 
 int eth_init (bd_t * bd)
 {
+	uchar enetaddr[6];
 	eth_reset ();
 	put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);
 	put_reg (RTL8019_DATACONFIGURATION, 0x48);
@@ -105,12 +106,13 @@
 	put_reg (RTL8019_INTERRUPTSTATUS, 0xff);
 	put_reg (RTL8019_INTERRUPTMASK, 0x11);	/*b; */
 	put_reg (RTL8019_COMMAND, RTL8019_PAGE1STOP);
-	put_reg (RTL8019_PHYSICALADDRESS0, bd->bi_enetaddr[0]);
-	put_reg (RTL8019_PHYSICALADDRESS1, bd->bi_enetaddr[1]);
-	put_reg (RTL8019_PHYSICALADDRESS2, bd->bi_enetaddr[2]);
-	put_reg (RTL8019_PHYSICALADDRESS3, bd->bi_enetaddr[3]);
-	put_reg (RTL8019_PHYSICALADDRESS4, bd->bi_enetaddr[4]);
-	put_reg (RTL8019_PHYSICALADDRESS5, bd->bi_enetaddr[5]);
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+	put_reg (RTL8019_PHYSICALADDRESS0, enetaddr[0]);
+	put_reg (RTL8019_PHYSICALADDRESS1, enetaddr[1]);
+	put_reg (RTL8019_PHYSICALADDRESS2, enetaddr[2]);
+	put_reg (RTL8019_PHYSICALADDRESS3, enetaddr[3]);
+	put_reg (RTL8019_PHYSICALADDRESS4, enetaddr[4]);
+	put_reg (RTL8019_PHYSICALADDRESS5, enetaddr[5]);
 	put_reg (RTL8019_MULTIADDRESS0, 0x00);
 	put_reg (RTL8019_MULTIADDRESS1, 0x00);
 	put_reg (RTL8019_MULTIADDRESS2, 0x00);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index e9f6391..f8c14b4 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -750,7 +750,7 @@
 
 	/* Get MAC address.  FIXME: read EEPROM */
 	for (i = 0; i < MAC_ADDR_LEN; i++)
-		bis->bi_enetaddr[i] = dev->enetaddr[i] = RTL_R8(MAC0 + i);
+		dev->enetaddr[i] = RTL_R8(MAC0 + i);
 
 #ifdef DEBUG_RTL8169
 	printf("chipset = %d\n", tpc->chipset);
diff --git a/drivers/net/s3c4510b_eth.c b/drivers/net/s3c4510b_eth.c
index 6dcb244..818ed3d 100644
--- a/drivers/net/s3c4510b_eth.c
+++ b/drivers/net/s3c4510b_eth.c
@@ -100,7 +100,7 @@
 	ETH *eth = &m_eth;
 
 	/* store our MAC address */
-	eth->m_mac = bis->bi_enetaddr;
+	eth_getenv_enetaddr("ethaddr", eth->m_mac);
 
 	/* setup DBMA and MAC */
 	PUT_REG( REG_BDMARXCON, ETH_BRxRS);   /* reset BDMA RX machine */
diff --git a/drivers/net/s3c4510b_eth.h b/drivers/net/s3c4510b_eth.h
index 048307f..18a52a7 100644
--- a/drivers/net/s3c4510b_eth.h
+++ b/drivers/net/s3c4510b_eth.h
@@ -296,7 +296,7 @@
 	TX_FrameDescriptor  *m_baseTX_FD; /*  pointer to base TX frame descriptor    */
 	RX_FrameDescriptor   *m_curRX_FD; /*  pointer to current RX frame descriptor */
 	RX_FrameDescriptor  *m_baseRX_FD; /*  pointer to base RX frame descriptor    */
-	u8                        *m_mac; /*  pointer to our MAC address             */
+	u8                      m_mac[6]; /*  pointer to our MAC address             */
 } ETH;
 
 #endif
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index ebe8588..f24ded2 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -514,6 +514,7 @@
 	int port = eth->port, ret = 0;
 	u32 val,  phy_status;
 	struct sh_eth_info *port_info = &eth->port_info[port];
+	struct eth_device *dev = port_info->dev;
 
 	/* Configure e-dmac registers */
 	outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port));
@@ -529,11 +530,11 @@
 	outl(0, ECSIPR(port));
 
 	/* Set Mac address */
-	val = bd->bi_enetaddr[0] << 24 | bd->bi_enetaddr[1] << 16 |
-	    bd->bi_enetaddr[2] << 8 | bd->bi_enetaddr[3];
+	val = dev->enetaddr[0] << 24 | dev->enetaddr[1] << 16 |
+	    dev->enetaddr[2] << 8 | dev->enetaddr[3];
 	outl(val, MAHR(port));
 
-	val = bd->bi_enetaddr[4] << 8 | bd->bi_enetaddr[5];
+	val = dev->enetaddr[4] << 8 | dev->enetaddr[5];
 	outl(val, MALR(port));
 
 	outl(RFLR_RFL_MIN, RFLR(port));
@@ -589,24 +590,6 @@
 	outl(~EDRRR_R, EDRRR(eth->port));
 }
 
-static int sh_eth_get_mac(bd_t *bd)
-{
-	char *s, *e;
-
-	s = getenv("ethaddr");
-	if (s != NULL) {
-		int i;
-		for (i = 0; i < 6; ++i) {
-			bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
-	} else {
-		puts("Please set MAC address\n");
-	}
-	return 0;
-}
-
 int sh_eth_init(struct eth_device *dev, bd_t *bd)
 {
 	int ret = 0;
@@ -639,8 +622,6 @@
 void sh_eth_halt(struct eth_device *dev)
 {
 	struct sh_eth_dev *eth = dev->priv;
-
-	sh_eth_reset(eth);
 	sh_eth_stop(eth);
 }
 
@@ -682,7 +663,8 @@
     /* Register Device to EtherNet subsystem  */
     eth_register(dev);
 
-	sh_eth_get_mac(bd);
+	if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr))
+		puts("Please set MAC address\n");
 
 	return ret;
 
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 82abb02..b41e4d2 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -834,10 +834,8 @@
 	SMC_SELECT_BANK (1);
 
 	err = smc_get_ethaddr (bd);	/* set smc_mac_addr, and sync it with u-boot globals */
-	if (err < 0) {
-		memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */
-		return (-1);	/* upper code ignores this, but NOT bi_enetaddr */
-	}
+	if (err < 0)
+		return -1;
 #ifdef USE_32_BIT
 	for (i = 0; i < 6; i += 2) {
 		word address;
@@ -1535,66 +1533,20 @@
 
 int smc_get_ethaddr (bd_t * bd)
 {
-	int env_size, rom_valid, env_present = 0, reg;
-	char *s = NULL, *e, es[] = "11:22:33:44:55:66";
-	char s_env_mac[64];
-	uchar v_env_mac[6], v_rom_mac[6], *v_mac;
+	uchar v_mac[6];
 
-	env_size = getenv_r ("ethaddr", s_env_mac, sizeof (s_env_mac));
-	if ((env_size > 0) && (env_size < sizeof (es))) {	/* exit if env is bad */
-		printf ("\n*** ERROR: ethaddr is not set properly!!\n");
-		return (-1);
-	}
-
-	if (env_size > 0) {
-		env_present = 1;
-		s = s_env_mac;
-	}
-
-	for (reg = 0; reg < 6; ++reg) { /* turn string into mac value */
-		v_env_mac[reg] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-
-	rom_valid = get_rom_mac (v_rom_mac);	/* get ROM mac value if any */
-
-	if (!env_present) {	/* if NO env */
-		if (rom_valid) {	/* but ROM is valid */
-			v_mac = v_rom_mac;
-			sprintf (s_env_mac, "%02X:%02X:%02X:%02X:%02X:%02X",
-				 v_mac[0], v_mac[1], v_mac[2], v_mac[3],
-				 v_mac[4], v_mac[5]);
-			setenv ("ethaddr", s_env_mac);
-		} else {	/* no env, bad ROM */
-			printf ("\n*** ERROR: ethaddr is NOT set !!\n");
-			return (-1);
+	if (!eth_getenv_enetaddr("ethaddr", v_mac)) {
+		/* get ROM mac value if any */
+		if (!get_rom_mac(v_mac)) {
+			printf("\n*** ERROR: ethaddr is NOT set !!\n");
+			return -1;
 		}
-	} else {		/* good env, don't care ROM */
-		v_mac = v_env_mac;	/* always use a good env over a ROM */
+		eth_setenv_enetaddr("ethaddr", v_mac);
 	}
 
-	if (env_present && rom_valid) { /* if both env and ROM are good */
-		if (memcmp (v_env_mac, v_rom_mac, 6) != 0) {
-			printf ("\nWarning: MAC addresses don't match:\n");
-			printf ("\tHW MAC address:  "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				v_rom_mac[0], v_rom_mac[1],
-				v_rom_mac[2], v_rom_mac[3],
-				v_rom_mac[4], v_rom_mac[5] );
-			printf ("\t\"ethaddr\" value: "
-				"%02X:%02X:%02X:%02X:%02X:%02X\n",
-				v_env_mac[0], v_env_mac[1],
-				v_env_mac[2], v_env_mac[3],
-				v_env_mac[4], v_env_mac[5]) ;
-			debug ("### Set MAC addr from environment\n");
-		}
-	}
-	memcpy (bd->bi_enetaddr, v_mac, 6);	/* update global address to match env (allows env changing) */
-	smc_set_mac_addr ((uchar *)v_mac);	/* use old function to update smc default */
-	PRINTK("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", v_mac[0], v_mac[1],
-		v_mac[2], v_mac[3], v_mac[4], v_mac[5]);
-	return (0);
+	smc_set_mac_addr(v_mac); /* use old function to update smc default */
+	PRINTK("Using MAC Address %pM\n", v_mac);
+	return 0;
 }
 
 int get_rom_mac (uchar *v_rom_mac)
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 9cc4fce..30f2dc2 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -27,38 +27,7 @@
 #include <net.h>
 #include <miiphy.h>
 
-#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \
-	defined (CONFIG_DRIVER_SMC911X_16_BIT)
-#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \
-	CONFIG_DRIVER_SMC911X_16_BIT shall be set"
-#endif
-
-#if defined (CONFIG_DRIVER_SMC911X_32_BIT)
-static inline u32 __smc911x_reg_read(u32 addr)
-{
-	return *(volatile u32*)addr;
-}
-u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read")));
-
-static inline void __smc911x_reg_write(u32 addr, u32 val)
-{
-	*(volatile u32*)addr = val;
-}
-void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write")));
-#elif defined (CONFIG_DRIVER_SMC911X_16_BIT)
-static inline u32 smc911x_reg_read(u32 addr)
-{
-	volatile u16 *addr_16 = (u16 *)addr;
-	return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
-}
-static inline void smc911x_reg_write(u32 addr, u32 val)
-{
-	*(volatile u16*)addr = (u16)val;
-	*(volatile u16*)(addr + 2) = (u16)(val >> 16);
-}
-#else
-#error "SMC911X: undefined bus width"
-#endif /* CONFIG_DRIVER_SMC911X_16_BIT */
+#include "smc911x.h"
 
 u32 pkt_data_pull(u32 addr) \
 	__attribute__ ((weak, alias ("smc911x_reg_read")));
@@ -67,382 +36,13 @@
 
 #define mdelay(n)       udelay((n)*1000)
 
-/* Below are the register offsets and bit definitions
- * of the Lan911x memory space
- */
-#define RX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x00)
-
-#define TX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x20)
-#define	TX_CMD_A_INT_ON_COMP			0x80000000
-#define	TX_CMD_A_INT_BUF_END_ALGN		0x03000000
-#define	TX_CMD_A_INT_4_BYTE_ALGN		0x00000000
-#define	TX_CMD_A_INT_16_BYTE_ALGN		0x01000000
-#define	TX_CMD_A_INT_32_BYTE_ALGN		0x02000000
-#define	TX_CMD_A_INT_DATA_OFFSET		0x001F0000
-#define	TX_CMD_A_INT_FIRST_SEG			0x00002000
-#define	TX_CMD_A_INT_LAST_SEG			0x00001000
-#define	TX_CMD_A_BUF_SIZE			0x000007FF
-#define	TX_CMD_B_PKT_TAG			0xFFFF0000
-#define	TX_CMD_B_ADD_CRC_DISABLE		0x00002000
-#define	TX_CMD_B_DISABLE_PADDING		0x00001000
-#define	TX_CMD_B_PKT_BYTE_LENGTH		0x000007FF
-
-#define RX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x40)
-#define	RX_STS_PKT_LEN				0x3FFF0000
-#define	RX_STS_ES				0x00008000
-#define	RX_STS_BCST				0x00002000
-#define	RX_STS_LEN_ERR				0x00001000
-#define	RX_STS_RUNT_ERR				0x00000800
-#define	RX_STS_MCAST				0x00000400
-#define	RX_STS_TOO_LONG				0x00000080
-#define	RX_STS_COLL				0x00000040
-#define	RX_STS_ETH_TYPE				0x00000020
-#define	RX_STS_WDOG_TMT				0x00000010
-#define	RX_STS_MII_ERR				0x00000008
-#define	RX_STS_DRIBBLING			0x00000004
-#define	RX_STS_CRC_ERR				0x00000002
-#define RX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x44)
-#define TX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x48)
-#define	TX_STS_TAG				0xFFFF0000
-#define	TX_STS_ES				0x00008000
-#define	TX_STS_LOC				0x00000800
-#define	TX_STS_NO_CARR				0x00000400
-#define	TX_STS_LATE_COLL			0x00000200
-#define	TX_STS_MANY_COLL			0x00000100
-#define	TX_STS_COLL_CNT				0x00000078
-#define	TX_STS_MANY_DEFER			0x00000004
-#define	TX_STS_UNDERRUN				0x00000002
-#define	TX_STS_DEFERRED				0x00000001
-#define TX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x4C)
-#define ID_REV			(CONFIG_DRIVER_SMC911X_BASE + 0x50)
-#define	ID_REV_CHIP_ID				0xFFFF0000  /* RO */
-#define	ID_REV_REV_ID				0x0000FFFF  /* RO */
-
-#define INT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x54)
-#define	INT_CFG_INT_DEAS			0xFF000000  /* R/W */
-#define	INT_CFG_INT_DEAS_CLR			0x00004000
-#define	INT_CFG_INT_DEAS_STS			0x00002000
-#define	INT_CFG_IRQ_INT				0x00001000  /* RO */
-#define	INT_CFG_IRQ_EN				0x00000100  /* R/W */
-#define	INT_CFG_IRQ_POL				0x00000010  /* R/W Not Affected by SW Reset */
-#define	INT_CFG_IRQ_TYPE			0x00000001  /* R/W Not Affected by SW Reset */
-
-#define INT_STS			(CONFIG_DRIVER_SMC911X_BASE + 0x58)
-#define	INT_STS_SW_INT				0x80000000  /* R/WC */
-#define	INT_STS_TXSTOP_INT			0x02000000  /* R/WC */
-#define	INT_STS_RXSTOP_INT			0x01000000  /* R/WC */
-#define	INT_STS_RXDFH_INT			0x00800000  /* R/WC */
-#define	INT_STS_RXDF_INT			0x00400000  /* R/WC */
-#define	INT_STS_TX_IOC				0x00200000  /* R/WC */
-#define	INT_STS_RXD_INT				0x00100000  /* R/WC */
-#define	INT_STS_GPT_INT				0x00080000  /* R/WC */
-#define	INT_STS_PHY_INT				0x00040000  /* RO */
-#define	INT_STS_PME_INT				0x00020000  /* R/WC */
-#define	INT_STS_TXSO				0x00010000  /* R/WC */
-#define	INT_STS_RWT				0x00008000  /* R/WC */
-#define	INT_STS_RXE				0x00004000  /* R/WC */
-#define	INT_STS_TXE				0x00002000  /* R/WC */
-/*#define	INT_STS_ERX		0x00001000*/  /* R/WC */
-#define	INT_STS_TDFU				0x00000800  /* R/WC */
-#define	INT_STS_TDFO				0x00000400  /* R/WC */
-#define	INT_STS_TDFA				0x00000200  /* R/WC */
-#define	INT_STS_TSFF				0x00000100  /* R/WC */
-#define	INT_STS_TSFL				0x00000080  /* R/WC */
-/*#define	INT_STS_RXDF		0x00000040*/  /* R/WC */
-#define	INT_STS_RDFO				0x00000040  /* R/WC */
-#define	INT_STS_RDFL				0x00000020  /* R/WC */
-#define	INT_STS_RSFF				0x00000010  /* R/WC */
-#define	INT_STS_RSFL				0x00000008  /* R/WC */
-#define	INT_STS_GPIO2_INT			0x00000004  /* R/WC */
-#define	INT_STS_GPIO1_INT			0x00000002  /* R/WC */
-#define	INT_STS_GPIO0_INT			0x00000001  /* R/WC */
-#define INT_EN			(CONFIG_DRIVER_SMC911X_BASE + 0x5C)
-#define	INT_EN_SW_INT_EN			0x80000000  /* R/W */
-#define	INT_EN_TXSTOP_INT_EN			0x02000000  /* R/W */
-#define	INT_EN_RXSTOP_INT_EN			0x01000000  /* R/W */
-#define	INT_EN_RXDFH_INT_EN			0x00800000  /* R/W */
-/*#define	INT_EN_RXDF_INT_EN		0x00400000*/  /* R/W */
-#define	INT_EN_TIOC_INT_EN			0x00200000  /* R/W */
-#define	INT_EN_RXD_INT_EN			0x00100000  /* R/W */
-#define	INT_EN_GPT_INT_EN			0x00080000  /* R/W */
-#define	INT_EN_PHY_INT_EN			0x00040000  /* R/W */
-#define	INT_EN_PME_INT_EN			0x00020000  /* R/W */
-#define	INT_EN_TXSO_EN				0x00010000  /* R/W */
-#define	INT_EN_RWT_EN				0x00008000  /* R/W */
-#define	INT_EN_RXE_EN				0x00004000  /* R/W */
-#define	INT_EN_TXE_EN				0x00002000  /* R/W */
-/*#define	INT_EN_ERX_EN			0x00001000*/  /* R/W */
-#define	INT_EN_TDFU_EN				0x00000800  /* R/W */
-#define	INT_EN_TDFO_EN				0x00000400  /* R/W */
-#define	INT_EN_TDFA_EN				0x00000200  /* R/W */
-#define	INT_EN_TSFF_EN				0x00000100  /* R/W */
-#define	INT_EN_TSFL_EN				0x00000080  /* R/W */
-/*#define	INT_EN_RXDF_EN			0x00000040*/  /* R/W */
-#define	INT_EN_RDFO_EN				0x00000040  /* R/W */
-#define	INT_EN_RDFL_EN				0x00000020  /* R/W */
-#define	INT_EN_RSFF_EN				0x00000010  /* R/W */
-#define	INT_EN_RSFL_EN				0x00000008  /* R/W */
-#define	INT_EN_GPIO2_INT			0x00000004  /* R/W */
-#define	INT_EN_GPIO1_INT			0x00000002  /* R/W */
-#define	INT_EN_GPIO0_INT			0x00000001  /* R/W */
-
-#define BYTE_TEST		(CONFIG_DRIVER_SMC911X_BASE + 0x64)
-#define FIFO_INT		(CONFIG_DRIVER_SMC911X_BASE + 0x68)
-#define	FIFO_INT_TX_AVAIL_LEVEL			0xFF000000  /* R/W */
-#define	FIFO_INT_TX_STS_LEVEL			0x00FF0000  /* R/W */
-#define	FIFO_INT_RX_AVAIL_LEVEL			0x0000FF00  /* R/W */
-#define	FIFO_INT_RX_STS_LEVEL			0x000000FF  /* R/W */
-
-#define RX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x6C)
-#define	RX_CFG_RX_END_ALGN			0xC0000000  /* R/W */
-#define		RX_CFG_RX_END_ALGN4		0x00000000  /* R/W */
-#define		RX_CFG_RX_END_ALGN16		0x40000000  /* R/W */
-#define		RX_CFG_RX_END_ALGN32		0x80000000  /* R/W */
-#define	RX_CFG_RX_DMA_CNT			0x0FFF0000  /* R/W */
-#define	RX_CFG_RX_DUMP				0x00008000  /* R/W */
-#define	RX_CFG_RXDOFF				0x00001F00  /* R/W */
-/*#define	RX_CFG_RXBAD			0x00000001*/  /* R/W */
-
-#define TX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x70)
-/*#define	TX_CFG_TX_DMA_LVL		0xE0000000*/	 /* R/W */
-/*#define	TX_CFG_TX_DMA_CNT		0x0FFF0000*/	 /* R/W Self Clearing */
-#define	TX_CFG_TXS_DUMP				0x00008000  /* Self Clearing */
-#define	TX_CFG_TXD_DUMP				0x00004000  /* Self Clearing */
-#define	TX_CFG_TXSAO				0x00000004  /* R/W */
-#define	TX_CFG_TX_ON				0x00000002  /* R/W */
-#define	TX_CFG_STOP_TX				0x00000001  /* Self Clearing */
-
-#define HW_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x74)
-#define	HW_CFG_TTM				0x00200000  /* R/W */
-#define	HW_CFG_SF				0x00100000  /* R/W */
-#define	HW_CFG_TX_FIF_SZ			0x000F0000  /* R/W */
-#define	HW_CFG_TR				0x00003000  /* R/W */
-#define	HW_CFG_PHY_CLK_SEL			0x00000060  /* R/W */
-#define	HW_CFG_PHY_CLK_SEL_INT_PHY		0x00000000 /* R/W */
-#define	HW_CFG_PHY_CLK_SEL_EXT_PHY		0x00000020 /* R/W */
-#define	HW_CFG_PHY_CLK_SEL_CLK_DIS		0x00000040 /* R/W */
-#define	HW_CFG_SMI_SEL				0x00000010  /* R/W */
-#define	HW_CFG_EXT_PHY_DET			0x00000008  /* RO */
-#define	HW_CFG_EXT_PHY_EN			0x00000004  /* R/W */
-#define	HW_CFG_32_16_BIT_MODE			0x00000004  /* RO */
-#define	HW_CFG_SRST_TO				0x00000002  /* RO */
-#define	HW_CFG_SRST				0x00000001  /* Self Clearing */
-
-#define RX_DP_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x78)
-#define	RX_DP_CTRL_RX_FFWD			0x80000000  /* R/W */
-#define	RX_DP_CTRL_FFWD_BUSY			0x80000000  /* RO */
-
-#define RX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x7C)
-#define	 RX_FIFO_INF_RXSUSED			0x00FF0000  /* RO */
-#define	 RX_FIFO_INF_RXDUSED			0x0000FFFF  /* RO */
-
-#define TX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x80)
-#define	TX_FIFO_INF_TSUSED			0x00FF0000  /* RO */
-#define	TX_FIFO_INF_TDFREE			0x0000FFFF  /* RO */
-
-#define PMT_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x84)
-#define	PMT_CTRL_PM_MODE			0x00003000  /* Self Clearing */
-#define	PMT_CTRL_PHY_RST			0x00000400  /* Self Clearing */
-#define	PMT_CTRL_WOL_EN				0x00000200  /* R/W */
-#define	PMT_CTRL_ED_EN				0x00000100  /* R/W */
-#define	PMT_CTRL_PME_TYPE			0x00000040  /* R/W Not Affected by SW Reset */
-#define	PMT_CTRL_WUPS				0x00000030  /* R/WC */
-#define	PMT_CTRL_WUPS_NOWAKE			0x00000000  /* R/WC */
-#define	PMT_CTRL_WUPS_ED			0x00000010  /* R/WC */
-#define	PMT_CTRL_WUPS_WOL			0x00000020  /* R/WC */
-#define	PMT_CTRL_WUPS_MULTI			0x00000030  /* R/WC */
-#define	PMT_CTRL_PME_IND			0x00000008  /* R/W */
-#define	PMT_CTRL_PME_POL			0x00000004  /* R/W */
-#define	PMT_CTRL_PME_EN				0x00000002  /* R/W Not Affected by SW Reset */
-#define	PMT_CTRL_READY				0x00000001  /* RO */
-
-#define GPIO_CFG		(CONFIG_DRIVER_SMC911X_BASE + 0x88)
-#define	GPIO_CFG_LED3_EN			0x40000000  /* R/W */
-#define	GPIO_CFG_LED2_EN			0x20000000  /* R/W */
-#define	GPIO_CFG_LED1_EN			0x10000000  /* R/W */
-#define	GPIO_CFG_GPIO2_INT_POL			0x04000000  /* R/W */
-#define	GPIO_CFG_GPIO1_INT_POL			0x02000000  /* R/W */
-#define	GPIO_CFG_GPIO0_INT_POL			0x01000000  /* R/W */
-#define	GPIO_CFG_EEPR_EN			0x00700000  /* R/W */
-#define	GPIO_CFG_GPIOBUF2			0x00040000  /* R/W */
-#define	GPIO_CFG_GPIOBUF1			0x00020000  /* R/W */
-#define	GPIO_CFG_GPIOBUF0			0x00010000  /* R/W */
-#define	GPIO_CFG_GPIODIR2			0x00000400  /* R/W */
-#define	GPIO_CFG_GPIODIR1			0x00000200  /* R/W */
-#define	GPIO_CFG_GPIODIR0			0x00000100  /* R/W */
-#define	GPIO_CFG_GPIOD4				0x00000010  /* R/W */
-#define	GPIO_CFG_GPIOD3				0x00000008  /* R/W */
-#define	GPIO_CFG_GPIOD2				0x00000004  /* R/W */
-#define	GPIO_CFG_GPIOD1				0x00000002  /* R/W */
-#define	GPIO_CFG_GPIOD0				0x00000001  /* R/W */
-
-#define GPT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x8C)
-#define	GPT_CFG_TIMER_EN			0x20000000  /* R/W */
-#define	GPT_CFG_GPT_LOAD			0x0000FFFF  /* R/W */
-
-#define GPT_CNT			(CONFIG_DRIVER_SMC911X_BASE + 0x90)
-#define	GPT_CNT_GPT_CNT				0x0000FFFF  /* RO */
-
-#define ENDIAN			(CONFIG_DRIVER_SMC911X_BASE + 0x98)
-#define FREE_RUN		(CONFIG_DRIVER_SMC911X_BASE + 0x9C)
-#define RX_DROP			(CONFIG_DRIVER_SMC911X_BASE + 0xA0)
-#define MAC_CSR_CMD		(CONFIG_DRIVER_SMC911X_BASE + 0xA4)
-#define	 MAC_CSR_CMD_CSR_BUSY			0x80000000  /* Self Clearing */
-#define	 MAC_CSR_CMD_R_NOT_W			0x40000000  /* R/W */
-#define	 MAC_CSR_CMD_CSR_ADDR			0x000000FF  /* R/W */
-
-#define MAC_CSR_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xA8)
-#define AFC_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0xAC)
-#define		AFC_CFG_AFC_HI			0x00FF0000  /* R/W */
-#define		AFC_CFG_AFC_LO			0x0000FF00  /* R/W */
-#define		AFC_CFG_BACK_DUR		0x000000F0  /* R/W */
-#define		AFC_CFG_FCMULT			0x00000008  /* R/W */
-#define		AFC_CFG_FCBRD			0x00000004  /* R/W */
-#define		AFC_CFG_FCADD			0x00000002  /* R/W */
-#define		AFC_CFG_FCANY			0x00000001  /* R/W */
-
-#define E2P_CMD			(CONFIG_DRIVER_SMC911X_BASE + 0xB0)
-#define		E2P_CMD_EPC_BUSY		0x80000000  /* Self Clearing */
-#define		E2P_CMD_EPC_CMD			0x70000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_READ		0x00000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_EWDS		0x10000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_EWEN		0x20000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_WRITE		0x30000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_WRAL		0x40000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_ERASE		0x50000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_ERAL		0x60000000  /* R/W */
-#define		E2P_CMD_EPC_CMD_RELOAD		0x70000000  /* R/W */
-#define		E2P_CMD_EPC_TIMEOUT		0x00000200  /* RO */
-#define		E2P_CMD_MAC_ADDR_LOADED		0x00000100  /* RO */
-#define		E2P_CMD_EPC_ADDR		0x000000FF  /* R/W */
-
-#define E2P_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xB4)
-#define	E2P_DATA_EEPROM_DATA			0x000000FF  /* R/W */
-/* end of LAN register offsets and bit definitions */
-
-/* MAC Control and Status registers */
-#define MAC_CR			0x01  /* R/W */
-
-/* MAC_CR - MAC Control Register */
-#define MAC_CR_RXALL			0x80000000
-/* TODO: delete this bit? It is not described in the data sheet. */
-#define MAC_CR_HBDIS			0x10000000
-#define MAC_CR_RCVOWN			0x00800000
-#define MAC_CR_LOOPBK			0x00200000
-#define MAC_CR_FDPX			0x00100000
-#define MAC_CR_MCPAS			0x00080000
-#define MAC_CR_PRMS			0x00040000
-#define MAC_CR_INVFILT			0x00020000
-#define MAC_CR_PASSBAD			0x00010000
-#define MAC_CR_HFILT			0x00008000
-#define MAC_CR_HPFILT			0x00002000
-#define MAC_CR_LCOLL			0x00001000
-#define MAC_CR_BCAST			0x00000800
-#define MAC_CR_DISRTY			0x00000400
-#define MAC_CR_PADSTR			0x00000100
-#define MAC_CR_BOLMT_MASK		0x000000C0
-#define MAC_CR_DFCHK			0x00000020
-#define MAC_CR_TXEN			0x00000008
-#define MAC_CR_RXEN			0x00000004
-
-#define ADDRH			0x02	  /* R/W mask 0x0000FFFFUL */
-#define ADDRL			0x03	  /* R/W mask 0xFFFFFFFFUL */
-#define HASHH			0x04	  /* R/W */
-#define HASHL			0x05	  /* R/W */
-
-#define MII_ACC			0x06	  /* R/W */
-#define MII_ACC_PHY_ADDR		0x0000F800
-#define MII_ACC_MIIRINDA		0x000007C0
-#define MII_ACC_MII_WRITE		0x00000002
-#define MII_ACC_MII_BUSY		0x00000001
-
-#define MII_DATA		0x07	  /* R/W mask 0x0000FFFFUL */
-
-#define FLOW			0x08	  /* R/W */
-#define FLOW_FCPT			0xFFFF0000
-#define FLOW_FCPASS			0x00000004
-#define FLOW_FCEN			0x00000002
-#define FLOW_FCBSY			0x00000001
-
-#define VLAN1			0x09	  /* R/W mask 0x0000FFFFUL */
-#define VLAN1_VTI1			0x0000ffff
-
-#define VLAN2			0x0A	  /* R/W mask 0x0000FFFFUL */
-#define VLAN2_VTI2			0x0000ffff
-
-#define WUFF			0x0B	  /* WO */
-
-#define WUCSR			0x0C	  /* R/W */
-#define WUCSR_GUE			0x00000200
-#define WUCSR_WUFR			0x00000040
-#define WUCSR_MPR			0x00000020
-#define WUCSR_WAKE_EN			0x00000004
-#define WUCSR_MPEN			0x00000002
-
-/* Chip ID values */
-#define CHIP_9115	0x115
-#define CHIP_9116	0x116
-#define CHIP_9117	0x117
-#define CHIP_9118	0x118
-#define CHIP_9211	0x9211
-#define CHIP_9215	0x115a
-#define CHIP_9216	0x116a
-#define CHIP_9217	0x117a
-#define CHIP_9218	0x118a
-
-struct chip_id {
-	u16 id;
-	char *name;
-};
-
-static const struct chip_id chip_ids[] =  {
-	{ CHIP_9115, "LAN9115" },
-	{ CHIP_9116, "LAN9116" },
-	{ CHIP_9117, "LAN9117" },
-	{ CHIP_9118, "LAN9118" },
-	{ CHIP_9211, "LAN9211" },
-	{ CHIP_9215, "LAN9215" },
-	{ CHIP_9216, "LAN9216" },
-	{ CHIP_9217, "LAN9217" },
-	{ CHIP_9218, "LAN9218" },
-	{ 0, NULL },
-};
-
-#define DRIVERNAME "smc911x"
-
-u32 smc911x_get_mac_csr(u8 reg)
-{
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-
-	return smc911x_reg_read(MAC_CSR_DATA);
-}
-
-void smc911x_set_mac_csr(u8 reg, u32 data)
-{
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-	smc911x_reg_write(MAC_CSR_DATA, data);
-	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
-	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-}
-
 static int smx911x_handle_mac_address(bd_t *bd)
 {
 	unsigned long addrh, addrl;
-	unsigned char *m = bd->bi_enetaddr;
+	uchar m[6];
 
 	/* if the environment has a valid mac address then use it */
-	if ((m[0] | m[1] | m[2] | m[3] | m[4] | m[5])) {
-		addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24;
-		addrh = m[4] | m[5] << 8;
-		smc911x_set_mac_csr(ADDRH, addrh);
-		smc911x_set_mac_csr(ADDRL, addrl);
-	} else {
+	if (!eth_getenv_enetaddr("ethaddr", m)) {
 		/* if not, try to get one from the eeprom */
 		addrh = smc911x_get_mac_csr(ADDRH);
 		addrl = smc911x_get_mac_csr(ADDRL);
@@ -460,10 +60,11 @@
 				"and no eeprom found\n");
 			return -1;
 		}
+
+		eth_setenv_enetaddr("ethaddr", m);
 	}
 
-	printf(DRIVERNAME ": MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-		m[0], m[1], m[2], m[3], m[4], m[5]);
+	printf(DRIVERNAME ": MAC %pM\n", m);
 
 	return 0;
 }
@@ -541,48 +142,6 @@
 	printf(DRIVERNAME ": autonegotiation timed out\n");
 }
 
-static void smc911x_reset(void)
-{
-	int timeout;
-
-	/* Take out of PM setting first */
-	if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) {
-		/* Write to the bytetest will take out of powerdown */
-		smc911x_reg_write(BYTE_TEST, 0x0);
-
-		timeout = 10;
-
-		while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY))
-			udelay(10);
-		if (!timeout) {
-			printf(DRIVERNAME
-				": timeout waiting for PM restore\n");
-			return;
-		}
-	}
-
-	/* Disable interrupts */
-	smc911x_reg_write(INT_EN, 0);
-
-	smc911x_reg_write(HW_CFG, HW_CFG_SRST);
-
-	timeout = 1000;
-	while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
-		udelay(10);
-
-	if (!timeout) {
-		printf(DRIVERNAME ": reset timeout\n");
-		return;
-	}
-
-	/* Reset the FIFO level and flow control settings */
-	smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN);
-	smc911x_reg_write(AFC_CFG, 0x0050287F);
-
-	/* Set to LED outputs */
-	smc911x_reg_write(GPIO_CFG, 0x70070000);
-}
-
 static void smc911x_enable(void)
 {
 	/* Enable TX */
@@ -601,26 +160,10 @@
 
 int eth_init(bd_t *bd)
 {
-	unsigned long val, i;
-
 	printf(DRIVERNAME ": initializing\n");
 
-	val = smc911x_reg_read(BYTE_TEST);
-	if (val != 0x87654321) {
-		printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
+	if (smc911x_detect_chip())
 		goto err_out;
-	}
-
-	val = smc911x_reg_read(ID_REV) >> 16;
-	for (i = 0; chip_ids[i].id != 0; i++) {
-		if (chip_ids[i].id == val) break;
-	}
-	if (!chip_ids[i].id) {
-		printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
-		goto err_out;
-	}
-
-	printf(DRIVERNAME ": detected %s controller\n", chip_ids[i].name);
 
 	smc911x_reset();
 
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
new file mode 100644
index 0000000..80d2ce0
--- /dev/null
+++ b/drivers/net/smc911x.h
@@ -0,0 +1,494 @@
+/*
+ * SMSC LAN9[12]1[567] Network driver
+ *
+ * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.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
+ */
+
+#ifndef _SMC911X_H_
+#define _SMC911X_H_
+
+#include <linux/types.h>
+
+#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \
+	defined (CONFIG_DRIVER_SMC911X_16_BIT)
+#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \
+	CONFIG_DRIVER_SMC911X_16_BIT shall be set"
+#endif
+
+#if defined (CONFIG_DRIVER_SMC911X_32_BIT)
+static inline u32 __smc911x_reg_read(u32 addr)
+{
+	return *(volatile u32*)addr;
+}
+u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read")));
+
+static inline void __smc911x_reg_write(u32 addr, u32 val)
+{
+	*(volatile u32*)addr = val;
+}
+void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write")));
+#elif defined (CONFIG_DRIVER_SMC911X_16_BIT)
+static inline u32 smc911x_reg_read(u32 addr)
+{
+	volatile u16 *addr_16 = (u16 *)addr;
+	return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
+}
+static inline void smc911x_reg_write(u32 addr, u32 val)
+{
+	*(volatile u16*)addr = (u16)val;
+	*(volatile u16*)(addr + 2) = (u16)(val >> 16);
+}
+#else
+#error "SMC911X: undefined bus width"
+#endif /* CONFIG_DRIVER_SMC911X_16_BIT */
+
+/* Below are the register offsets and bit definitions
+ * of the Lan911x memory space
+ */
+#define RX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x00)
+
+#define TX_DATA_FIFO		 (CONFIG_DRIVER_SMC911X_BASE + 0x20)
+#define	TX_CMD_A_INT_ON_COMP			0x80000000
+#define	TX_CMD_A_INT_BUF_END_ALGN		0x03000000
+#define	TX_CMD_A_INT_4_BYTE_ALGN		0x00000000
+#define	TX_CMD_A_INT_16_BYTE_ALGN		0x01000000
+#define	TX_CMD_A_INT_32_BYTE_ALGN		0x02000000
+#define	TX_CMD_A_INT_DATA_OFFSET		0x001F0000
+#define	TX_CMD_A_INT_FIRST_SEG			0x00002000
+#define	TX_CMD_A_INT_LAST_SEG			0x00001000
+#define	TX_CMD_A_BUF_SIZE			0x000007FF
+#define	TX_CMD_B_PKT_TAG			0xFFFF0000
+#define	TX_CMD_B_ADD_CRC_DISABLE		0x00002000
+#define	TX_CMD_B_DISABLE_PADDING		0x00001000
+#define	TX_CMD_B_PKT_BYTE_LENGTH		0x000007FF
+
+#define RX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x40)
+#define	RX_STS_PKT_LEN				0x3FFF0000
+#define	RX_STS_ES				0x00008000
+#define	RX_STS_BCST				0x00002000
+#define	RX_STS_LEN_ERR				0x00001000
+#define	RX_STS_RUNT_ERR				0x00000800
+#define	RX_STS_MCAST				0x00000400
+#define	RX_STS_TOO_LONG				0x00000080
+#define	RX_STS_COLL				0x00000040
+#define	RX_STS_ETH_TYPE				0x00000020
+#define	RX_STS_WDOG_TMT				0x00000010
+#define	RX_STS_MII_ERR				0x00000008
+#define	RX_STS_DRIBBLING			0x00000004
+#define	RX_STS_CRC_ERR				0x00000002
+#define RX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x44)
+#define TX_STATUS_FIFO		(CONFIG_DRIVER_SMC911X_BASE + 0x48)
+#define	TX_STS_TAG				0xFFFF0000
+#define	TX_STS_ES				0x00008000
+#define	TX_STS_LOC				0x00000800
+#define	TX_STS_NO_CARR				0x00000400
+#define	TX_STS_LATE_COLL			0x00000200
+#define	TX_STS_MANY_COLL			0x00000100
+#define	TX_STS_COLL_CNT				0x00000078
+#define	TX_STS_MANY_DEFER			0x00000004
+#define	TX_STS_UNDERRUN				0x00000002
+#define	TX_STS_DEFERRED				0x00000001
+#define TX_STATUS_FIFO_PEEK	(CONFIG_DRIVER_SMC911X_BASE + 0x4C)
+#define ID_REV			(CONFIG_DRIVER_SMC911X_BASE + 0x50)
+#define	ID_REV_CHIP_ID				0xFFFF0000  /* RO */
+#define	ID_REV_REV_ID				0x0000FFFF  /* RO */
+
+#define INT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x54)
+#define	INT_CFG_INT_DEAS			0xFF000000  /* R/W */
+#define	INT_CFG_INT_DEAS_CLR			0x00004000
+#define	INT_CFG_INT_DEAS_STS			0x00002000
+#define	INT_CFG_IRQ_INT				0x00001000  /* RO */
+#define	INT_CFG_IRQ_EN				0x00000100  /* R/W */
+#define	INT_CFG_IRQ_POL				0x00000010  /* R/W Not Affected by SW Reset */
+#define	INT_CFG_IRQ_TYPE			0x00000001  /* R/W Not Affected by SW Reset */
+
+#define INT_STS			(CONFIG_DRIVER_SMC911X_BASE + 0x58)
+#define	INT_STS_SW_INT				0x80000000  /* R/WC */
+#define	INT_STS_TXSTOP_INT			0x02000000  /* R/WC */
+#define	INT_STS_RXSTOP_INT			0x01000000  /* R/WC */
+#define	INT_STS_RXDFH_INT			0x00800000  /* R/WC */
+#define	INT_STS_RXDF_INT			0x00400000  /* R/WC */
+#define	INT_STS_TX_IOC				0x00200000  /* R/WC */
+#define	INT_STS_RXD_INT				0x00100000  /* R/WC */
+#define	INT_STS_GPT_INT				0x00080000  /* R/WC */
+#define	INT_STS_PHY_INT				0x00040000  /* RO */
+#define	INT_STS_PME_INT				0x00020000  /* R/WC */
+#define	INT_STS_TXSO				0x00010000  /* R/WC */
+#define	INT_STS_RWT				0x00008000  /* R/WC */
+#define	INT_STS_RXE				0x00004000  /* R/WC */
+#define	INT_STS_TXE				0x00002000  /* R/WC */
+/*#define	INT_STS_ERX		0x00001000*/  /* R/WC */
+#define	INT_STS_TDFU				0x00000800  /* R/WC */
+#define	INT_STS_TDFO				0x00000400  /* R/WC */
+#define	INT_STS_TDFA				0x00000200  /* R/WC */
+#define	INT_STS_TSFF				0x00000100  /* R/WC */
+#define	INT_STS_TSFL				0x00000080  /* R/WC */
+/*#define	INT_STS_RXDF		0x00000040*/  /* R/WC */
+#define	INT_STS_RDFO				0x00000040  /* R/WC */
+#define	INT_STS_RDFL				0x00000020  /* R/WC */
+#define	INT_STS_RSFF				0x00000010  /* R/WC */
+#define	INT_STS_RSFL				0x00000008  /* R/WC */
+#define	INT_STS_GPIO2_INT			0x00000004  /* R/WC */
+#define	INT_STS_GPIO1_INT			0x00000002  /* R/WC */
+#define	INT_STS_GPIO0_INT			0x00000001  /* R/WC */
+#define INT_EN			(CONFIG_DRIVER_SMC911X_BASE + 0x5C)
+#define	INT_EN_SW_INT_EN			0x80000000  /* R/W */
+#define	INT_EN_TXSTOP_INT_EN			0x02000000  /* R/W */
+#define	INT_EN_RXSTOP_INT_EN			0x01000000  /* R/W */
+#define	INT_EN_RXDFH_INT_EN			0x00800000  /* R/W */
+/*#define	INT_EN_RXDF_INT_EN		0x00400000*/  /* R/W */
+#define	INT_EN_TIOC_INT_EN			0x00200000  /* R/W */
+#define	INT_EN_RXD_INT_EN			0x00100000  /* R/W */
+#define	INT_EN_GPT_INT_EN			0x00080000  /* R/W */
+#define	INT_EN_PHY_INT_EN			0x00040000  /* R/W */
+#define	INT_EN_PME_INT_EN			0x00020000  /* R/W */
+#define	INT_EN_TXSO_EN				0x00010000  /* R/W */
+#define	INT_EN_RWT_EN				0x00008000  /* R/W */
+#define	INT_EN_RXE_EN				0x00004000  /* R/W */
+#define	INT_EN_TXE_EN				0x00002000  /* R/W */
+/*#define	INT_EN_ERX_EN			0x00001000*/  /* R/W */
+#define	INT_EN_TDFU_EN				0x00000800  /* R/W */
+#define	INT_EN_TDFO_EN				0x00000400  /* R/W */
+#define	INT_EN_TDFA_EN				0x00000200  /* R/W */
+#define	INT_EN_TSFF_EN				0x00000100  /* R/W */
+#define	INT_EN_TSFL_EN				0x00000080  /* R/W */
+/*#define	INT_EN_RXDF_EN			0x00000040*/  /* R/W */
+#define	INT_EN_RDFO_EN				0x00000040  /* R/W */
+#define	INT_EN_RDFL_EN				0x00000020  /* R/W */
+#define	INT_EN_RSFF_EN				0x00000010  /* R/W */
+#define	INT_EN_RSFL_EN				0x00000008  /* R/W */
+#define	INT_EN_GPIO2_INT			0x00000004  /* R/W */
+#define	INT_EN_GPIO1_INT			0x00000002  /* R/W */
+#define	INT_EN_GPIO0_INT			0x00000001  /* R/W */
+
+#define BYTE_TEST		(CONFIG_DRIVER_SMC911X_BASE + 0x64)
+#define FIFO_INT		(CONFIG_DRIVER_SMC911X_BASE + 0x68)
+#define	FIFO_INT_TX_AVAIL_LEVEL			0xFF000000  /* R/W */
+#define	FIFO_INT_TX_STS_LEVEL			0x00FF0000  /* R/W */
+#define	FIFO_INT_RX_AVAIL_LEVEL			0x0000FF00  /* R/W */
+#define	FIFO_INT_RX_STS_LEVEL			0x000000FF  /* R/W */
+
+#define RX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x6C)
+#define	RX_CFG_RX_END_ALGN			0xC0000000  /* R/W */
+#define		RX_CFG_RX_END_ALGN4		0x00000000  /* R/W */
+#define		RX_CFG_RX_END_ALGN16		0x40000000  /* R/W */
+#define		RX_CFG_RX_END_ALGN32		0x80000000  /* R/W */
+#define	RX_CFG_RX_DMA_CNT			0x0FFF0000  /* R/W */
+#define	RX_CFG_RX_DUMP				0x00008000  /* R/W */
+#define	RX_CFG_RXDOFF				0x00001F00  /* R/W */
+/*#define	RX_CFG_RXBAD			0x00000001*/  /* R/W */
+
+#define TX_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x70)
+/*#define	TX_CFG_TX_DMA_LVL		0xE0000000*/	 /* R/W */
+/*#define	TX_CFG_TX_DMA_CNT		0x0FFF0000*/	 /* R/W Self Clearing */
+#define	TX_CFG_TXS_DUMP				0x00008000  /* Self Clearing */
+#define	TX_CFG_TXD_DUMP				0x00004000  /* Self Clearing */
+#define	TX_CFG_TXSAO				0x00000004  /* R/W */
+#define	TX_CFG_TX_ON				0x00000002  /* R/W */
+#define	TX_CFG_STOP_TX				0x00000001  /* Self Clearing */
+
+#define HW_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x74)
+#define	HW_CFG_TTM				0x00200000  /* R/W */
+#define	HW_CFG_SF				0x00100000  /* R/W */
+#define	HW_CFG_TX_FIF_SZ			0x000F0000  /* R/W */
+#define	HW_CFG_TR				0x00003000  /* R/W */
+#define	HW_CFG_PHY_CLK_SEL			0x00000060  /* R/W */
+#define	HW_CFG_PHY_CLK_SEL_INT_PHY		0x00000000 /* R/W */
+#define	HW_CFG_PHY_CLK_SEL_EXT_PHY		0x00000020 /* R/W */
+#define	HW_CFG_PHY_CLK_SEL_CLK_DIS		0x00000040 /* R/W */
+#define	HW_CFG_SMI_SEL				0x00000010  /* R/W */
+#define	HW_CFG_EXT_PHY_DET			0x00000008  /* RO */
+#define	HW_CFG_EXT_PHY_EN			0x00000004  /* R/W */
+#define	HW_CFG_32_16_BIT_MODE			0x00000004  /* RO */
+#define	HW_CFG_SRST_TO				0x00000002  /* RO */
+#define	HW_CFG_SRST				0x00000001  /* Self Clearing */
+
+#define RX_DP_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x78)
+#define	RX_DP_CTRL_RX_FFWD			0x80000000  /* R/W */
+#define	RX_DP_CTRL_FFWD_BUSY			0x80000000  /* RO */
+
+#define RX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x7C)
+#define	 RX_FIFO_INF_RXSUSED			0x00FF0000  /* RO */
+#define	 RX_FIFO_INF_RXDUSED			0x0000FFFF  /* RO */
+
+#define TX_FIFO_INF		(CONFIG_DRIVER_SMC911X_BASE + 0x80)
+#define	TX_FIFO_INF_TSUSED			0x00FF0000  /* RO */
+#define	TX_FIFO_INF_TDFREE			0x0000FFFF  /* RO */
+
+#define PMT_CTRL		(CONFIG_DRIVER_SMC911X_BASE + 0x84)
+#define	PMT_CTRL_PM_MODE			0x00003000  /* Self Clearing */
+#define	PMT_CTRL_PHY_RST			0x00000400  /* Self Clearing */
+#define	PMT_CTRL_WOL_EN				0x00000200  /* R/W */
+#define	PMT_CTRL_ED_EN				0x00000100  /* R/W */
+#define	PMT_CTRL_PME_TYPE			0x00000040  /* R/W Not Affected by SW Reset */
+#define	PMT_CTRL_WUPS				0x00000030  /* R/WC */
+#define	PMT_CTRL_WUPS_NOWAKE			0x00000000  /* R/WC */
+#define	PMT_CTRL_WUPS_ED			0x00000010  /* R/WC */
+#define	PMT_CTRL_WUPS_WOL			0x00000020  /* R/WC */
+#define	PMT_CTRL_WUPS_MULTI			0x00000030  /* R/WC */
+#define	PMT_CTRL_PME_IND			0x00000008  /* R/W */
+#define	PMT_CTRL_PME_POL			0x00000004  /* R/W */
+#define	PMT_CTRL_PME_EN				0x00000002  /* R/W Not Affected by SW Reset */
+#define	PMT_CTRL_READY				0x00000001  /* RO */
+
+#define GPIO_CFG		(CONFIG_DRIVER_SMC911X_BASE + 0x88)
+#define	GPIO_CFG_LED3_EN			0x40000000  /* R/W */
+#define	GPIO_CFG_LED2_EN			0x20000000  /* R/W */
+#define	GPIO_CFG_LED1_EN			0x10000000  /* R/W */
+#define	GPIO_CFG_GPIO2_INT_POL			0x04000000  /* R/W */
+#define	GPIO_CFG_GPIO1_INT_POL			0x02000000  /* R/W */
+#define	GPIO_CFG_GPIO0_INT_POL			0x01000000  /* R/W */
+#define	GPIO_CFG_EEPR_EN			0x00700000  /* R/W */
+#define	GPIO_CFG_GPIOBUF2			0x00040000  /* R/W */
+#define	GPIO_CFG_GPIOBUF1			0x00020000  /* R/W */
+#define	GPIO_CFG_GPIOBUF0			0x00010000  /* R/W */
+#define	GPIO_CFG_GPIODIR2			0x00000400  /* R/W */
+#define	GPIO_CFG_GPIODIR1			0x00000200  /* R/W */
+#define	GPIO_CFG_GPIODIR0			0x00000100  /* R/W */
+#define	GPIO_CFG_GPIOD4				0x00000010  /* R/W */
+#define	GPIO_CFG_GPIOD3				0x00000008  /* R/W */
+#define	GPIO_CFG_GPIOD2				0x00000004  /* R/W */
+#define	GPIO_CFG_GPIOD1				0x00000002  /* R/W */
+#define	GPIO_CFG_GPIOD0				0x00000001  /* R/W */
+
+#define GPT_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0x8C)
+#define	GPT_CFG_TIMER_EN			0x20000000  /* R/W */
+#define	GPT_CFG_GPT_LOAD			0x0000FFFF  /* R/W */
+
+#define GPT_CNT			(CONFIG_DRIVER_SMC911X_BASE + 0x90)
+#define	GPT_CNT_GPT_CNT				0x0000FFFF  /* RO */
+
+#define ENDIAN			(CONFIG_DRIVER_SMC911X_BASE + 0x98)
+#define FREE_RUN		(CONFIG_DRIVER_SMC911X_BASE + 0x9C)
+#define RX_DROP			(CONFIG_DRIVER_SMC911X_BASE + 0xA0)
+#define MAC_CSR_CMD		(CONFIG_DRIVER_SMC911X_BASE + 0xA4)
+#define	 MAC_CSR_CMD_CSR_BUSY			0x80000000  /* Self Clearing */
+#define	 MAC_CSR_CMD_R_NOT_W			0x40000000  /* R/W */
+#define	 MAC_CSR_CMD_CSR_ADDR			0x000000FF  /* R/W */
+
+#define MAC_CSR_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xA8)
+#define AFC_CFG			(CONFIG_DRIVER_SMC911X_BASE + 0xAC)
+#define		AFC_CFG_AFC_HI			0x00FF0000  /* R/W */
+#define		AFC_CFG_AFC_LO			0x0000FF00  /* R/W */
+#define		AFC_CFG_BACK_DUR		0x000000F0  /* R/W */
+#define		AFC_CFG_FCMULT			0x00000008  /* R/W */
+#define		AFC_CFG_FCBRD			0x00000004  /* R/W */
+#define		AFC_CFG_FCADD			0x00000002  /* R/W */
+#define		AFC_CFG_FCANY			0x00000001  /* R/W */
+
+#define E2P_CMD			(CONFIG_DRIVER_SMC911X_BASE + 0xB0)
+#define		E2P_CMD_EPC_BUSY		0x80000000  /* Self Clearing */
+#define		E2P_CMD_EPC_CMD			0x70000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_READ		0x00000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_EWDS		0x10000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_EWEN		0x20000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_WRITE		0x30000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_WRAL		0x40000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_ERASE		0x50000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_ERAL		0x60000000  /* R/W */
+#define		E2P_CMD_EPC_CMD_RELOAD		0x70000000  /* R/W */
+#define		E2P_CMD_EPC_TIMEOUT		0x00000200  /* RO */
+#define		E2P_CMD_MAC_ADDR_LOADED		0x00000100  /* RO */
+#define		E2P_CMD_EPC_ADDR		0x000000FF  /* R/W */
+
+#define E2P_DATA		(CONFIG_DRIVER_SMC911X_BASE + 0xB4)
+#define	E2P_DATA_EEPROM_DATA			0x000000FF  /* R/W */
+/* end of LAN register offsets and bit definitions */
+
+/* MAC Control and Status registers */
+#define MAC_CR			0x01  /* R/W */
+
+/* MAC_CR - MAC Control Register */
+#define MAC_CR_RXALL			0x80000000
+/* TODO: delete this bit? It is not described in the data sheet. */
+#define MAC_CR_HBDIS			0x10000000
+#define MAC_CR_RCVOWN			0x00800000
+#define MAC_CR_LOOPBK			0x00200000
+#define MAC_CR_FDPX			0x00100000
+#define MAC_CR_MCPAS			0x00080000
+#define MAC_CR_PRMS			0x00040000
+#define MAC_CR_INVFILT			0x00020000
+#define MAC_CR_PASSBAD			0x00010000
+#define MAC_CR_HFILT			0x00008000
+#define MAC_CR_HPFILT			0x00002000
+#define MAC_CR_LCOLL			0x00001000
+#define MAC_CR_BCAST			0x00000800
+#define MAC_CR_DISRTY			0x00000400
+#define MAC_CR_PADSTR			0x00000100
+#define MAC_CR_BOLMT_MASK		0x000000C0
+#define MAC_CR_DFCHK			0x00000020
+#define MAC_CR_TXEN			0x00000008
+#define MAC_CR_RXEN			0x00000004
+
+#define ADDRH			0x02	  /* R/W mask 0x0000FFFFUL */
+#define ADDRL			0x03	  /* R/W mask 0xFFFFFFFFUL */
+#define HASHH			0x04	  /* R/W */
+#define HASHL			0x05	  /* R/W */
+
+#define MII_ACC			0x06	  /* R/W */
+#define MII_ACC_PHY_ADDR		0x0000F800
+#define MII_ACC_MIIRINDA		0x000007C0
+#define MII_ACC_MII_WRITE		0x00000002
+#define MII_ACC_MII_BUSY		0x00000001
+
+#define MII_DATA		0x07	  /* R/W mask 0x0000FFFFUL */
+
+#define FLOW			0x08	  /* R/W */
+#define FLOW_FCPT			0xFFFF0000
+#define FLOW_FCPASS			0x00000004
+#define FLOW_FCEN			0x00000002
+#define FLOW_FCBSY			0x00000001
+
+#define VLAN1			0x09	  /* R/W mask 0x0000FFFFUL */
+#define VLAN1_VTI1			0x0000ffff
+
+#define VLAN2			0x0A	  /* R/W mask 0x0000FFFFUL */
+#define VLAN2_VTI2			0x0000ffff
+
+#define WUFF			0x0B	  /* WO */
+
+#define WUCSR			0x0C	  /* R/W */
+#define WUCSR_GUE			0x00000200
+#define WUCSR_WUFR			0x00000040
+#define WUCSR_MPR			0x00000020
+#define WUCSR_WAKE_EN			0x00000004
+#define WUCSR_MPEN			0x00000002
+
+/* Chip ID values */
+#define CHIP_9115	0x115
+#define CHIP_9116	0x116
+#define CHIP_9117	0x117
+#define CHIP_9118	0x118
+#define CHIP_9211	0x9211
+#define CHIP_9215	0x115a
+#define CHIP_9216	0x116a
+#define CHIP_9217	0x117a
+#define CHIP_9218	0x118a
+
+struct chip_id {
+	u16 id;
+	char *name;
+};
+
+static const struct chip_id chip_ids[] =  {
+	{ CHIP_9115, "LAN9115" },
+	{ CHIP_9116, "LAN9116" },
+	{ CHIP_9117, "LAN9117" },
+	{ CHIP_9118, "LAN9118" },
+	{ CHIP_9211, "LAN9211" },
+	{ CHIP_9215, "LAN9215" },
+	{ CHIP_9216, "LAN9216" },
+	{ CHIP_9217, "LAN9217" },
+	{ CHIP_9218, "LAN9218" },
+	{ 0, NULL },
+};
+
+
+#define DRIVERNAME "smc911x"
+
+static u32 smc911x_get_mac_csr(u8 reg)
+{
+	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+		;
+	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
+	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+		;
+
+	return smc911x_reg_read(MAC_CSR_DATA);
+}
+
+static void smc911x_set_mac_csr(u8 reg, u32 data)
+{
+	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+		;
+	smc911x_reg_write(MAC_CSR_DATA, data);
+	smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
+	while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+		;
+}
+
+static int smc911x_detect_chip(void)
+{
+	unsigned long val, i;
+
+	val = smc911x_reg_read(BYTE_TEST);
+	if (val != 0x87654321) {
+		printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
+		return -1;
+	}
+
+	val = smc911x_reg_read(ID_REV) >> 16;
+	for (i = 0; chip_ids[i].id != 0; i++) {
+		if (chip_ids[i].id == val) break;
+	}
+	if (!chip_ids[i].id) {
+		printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
+		return -1;
+	}
+
+	printf(DRIVERNAME ": detected %s controller\n", chip_ids[i].name);
+
+	return 0;
+}
+
+static void smc911x_reset(void)
+{
+	int timeout;
+
+	/* Take out of PM setting first */
+	if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) {
+		/* Write to the bytetest will take out of powerdown */
+		smc911x_reg_write(BYTE_TEST, 0x0);
+
+		timeout = 10;
+
+		while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY))
+			udelay(10);
+		if (!timeout) {
+			printf(DRIVERNAME
+				": timeout waiting for PM restore\n");
+			return;
+		}
+	}
+
+	/* Disable interrupts */
+	smc911x_reg_write(INT_EN, 0);
+
+	smc911x_reg_write(HW_CFG, HW_CFG_SRST);
+
+	timeout = 1000;
+	while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+		udelay(10);
+
+	if (!timeout) {
+		printf(DRIVERNAME ": reset timeout\n");
+		return;
+	}
+
+	/* Reset the FIFO level and flow control settings */
+	smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN);
+	smc911x_reg_write(AFC_CFG, 0x0050287F);
+
+	/* Set to LED outputs */
+	smc911x_reg_write(GPIO_CFG, 0x70070000);
+}
+
+#endif
diff --git a/drivers/net/tigon3.c b/drivers/net/tigon3.c
index e4e004e..33cb447 100644
--- a/drivers/net/tigon3.c
+++ b/drivers/net/tigon3.c
@@ -2463,7 +2463,7 @@
 #endif				/* T3_JUMBO_RCV_ENTRY_COUNT */
 
 	/* Configure the MAC address. */
-	LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+	LM_SetMacAddress (pDevice);
 
 	/* Initialize the transmit random backoff seed. */
 	Value32 = (pDevice->NodeAddress[0] + pDevice->NodeAddress[1] +
@@ -3428,7 +3428,7 @@
 		     (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId);
 
 	/* Reprogram the MAC address. */
-	LM_SetMacAddress (pDevice, pDevice->NodeAddress);
+	LM_SetMacAddress (pDevice);
 
 	return LM_STATUS_SUCCESS;
 }				/* LM_Halt */
@@ -3833,9 +3833,10 @@
 /*                                                                            */
 /* Return:                                                                    */
 /******************************************************************************/
-LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress)
+LM_STATUS LM_SetMacAddress (PLM_DEVICE_BLOCK pDevice)
 {
 	LM_UINT32 j;
+	PLM_UINT8 pMacAddress = pDevice->NodeAddress;
 
 	for (j = 0; j < 4; j++) {
 		REG_WR (pDevice, MacCtrl.MacAddr[j].High,
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 9edba6a..399116f 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -1332,6 +1332,35 @@
 			   {miim_end,}
 			   },
 };
+struct phy_info phy_info_VSC8211 = {
+	0xfc4b,
+	"Vitesse VSC8211",
+	4,
+	(struct phy_cmd[]) { /* config */
+			   /* Override PHY config settings */
+			   {MIIM_CIS8201_AUX_CONSTAT,
+			    MIIM_CIS8201_AUXCONSTAT_INIT, NULL},
+			   /* Set up the interface mode */
+			   {MIIM_CIS8201_EXT_CON1,
+			    MIIM_CIS8201_EXTCON1_INIT, NULL},
+			   /* Configure some basic stuff */
+			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]) { /* startup */
+			   /* Read the Status (2x to make sure link is right) */
+			   {MIIM_STATUS, miim_read, NULL},
+			   /* Auto-negotiate */
+			   {MIIM_STATUS, miim_read, &mii_parse_sr},
+			   /* Read the status */
+			   {MIIM_CIS8201_AUX_CONSTAT, miim_read,
+			    &mii_parse_cis8201},
+			   {miim_end,}
+			   },
+	(struct phy_cmd[]) { /* shutdown */
+			   {miim_end,}
+	},
+};
 struct phy_info phy_info_VSC8244 = {
 	0x3f1b,
 	"Vitesse VSC8244",
@@ -1590,11 +1619,12 @@
 	&phy_info_M88E1149S,
 	&phy_info_dm9161,
 	&phy_info_lxt971,
+	&phy_info_VSC8211,
 	&phy_info_VSC8244,
 	&phy_info_VSC8601,
 	&phy_info_dp83865,
 	&phy_info_rtl8211b,
-	&phy_info_generic,
+	&phy_info_generic,	/* must be last; has ID 0 and 32 bit mask */
 	NULL
 };
 
@@ -1626,9 +1656,8 @@
 		}
 	}
 
-	if (theInfo == NULL) {
-		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
-		return NULL;
+	if (theInfo == &phy_info_generic) {
+		printf("%s: No support for PHY id %x; assuming generic\n", dev->name, phy_ID);
 	} else {
 		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
 	}
diff --git a/drivers/net/xilinx_emac.c b/drivers/net/xilinx_emac.c
index c7f1a2a..a489aa9 100644
--- a/drivers/net/xilinx_emac.c
+++ b/drivers/net/xilinx_emac.c
@@ -166,6 +166,7 @@
 
 int eth_init(bd_t * bis)
 {
+	uchar enetaddr[6];
 	u32 helpreg;
 	debug ("EMAC Initialization Started\n\r");
 
@@ -200,15 +201,16 @@
 	helpreg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
 	out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
 
-	if (!getenv("ethaddr")) {
-		memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH);
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
+		eth_setenv_enetaddr("ethaddr", enetaddr);
 	}
 
 	/* Set the device station address high and low registers */
-	helpreg = (bis->bi_enetaddr[0] << 8) | bis->bi_enetaddr[1];
+	helpreg = (enetaddr[0] << 8) | enetaddr[1];
 	out_be32 (emac.baseaddress + XEM_SAH_OFFSET, helpreg);
-	helpreg = (bis->bi_enetaddr[2] << 24) | (bis->bi_enetaddr[3] << 16) |
-			(bis->bi_enetaddr[4] << 8) | bis->bi_enetaddr[5];
+	helpreg = (enetaddr[2] << 24) | (enetaddr[3] << 16) |
+			(enetaddr[4] << 8) | enetaddr[5];
 	out_be32 (emac.baseaddress + XEM_SAL_OFFSET, helpreg);
 
 	helpreg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK |
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 0e96ef1..cf39573 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -140,12 +140,15 @@
 
 int eth_init (bd_t * bis)
 {
+	uchar enetaddr[6];
+
 	debug ("EmacLite Initialization Started\n");
 	memset (&emaclite, 0, sizeof (xemaclite));
 	emaclite.baseaddress = XILINX_EMACLITE_BASEADDR;
 
-	if (!getenv("ethaddr")) {
-		memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH);
+	if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
+		memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
+		eth_setenv_enetaddr("ethaddr", enetaddr);
 	}
 
 /*
@@ -154,7 +157,7 @@
 	/* Restart PING TX */
 	out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
 	/* Copy MAC address */
-	xemaclite_alignedwrite (bis->bi_enetaddr,
+	xemaclite_alignedwrite (enetaddr,
 		emaclite.baseaddress, ENET_ADDR_LENGTH);
 	/* Set the length */
 	out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
@@ -167,7 +170,7 @@
 #ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
 	/* The same operation with PONG TX */
 	out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
-	xemaclite_alignedwrite (bis->bi_enetaddr, emaclite.baseaddress +
+	xemaclite_alignedwrite (enetaddr, emaclite.baseaddress +
 		XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
 	out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
 	out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index fffca49..d6d2d6e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -165,6 +165,19 @@
 	return NULL;
 }
 
+int pci_last_busno(void)
+{
+	struct pci_controller *hose = hose_head;
+
+	if (!hose)
+		return -1;
+
+	while (hose->next)
+		hose = hose->next;
+
+	return hose->last_busno;
+}
+
 #ifndef CONFIG_IXP425
 pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 {
diff --git a/drivers/pci/pci_sh4.c b/drivers/pci/pci_sh4.c
index 057b6dd..c7963ed 100644
--- a/drivers/pci/pci_sh4.c
+++ b/drivers/pci/pci_sh4.c
@@ -54,6 +54,16 @@
 		PCI_REGION_IO);
 	hose->region_count++;
 
+#if defined(CONFIG_PCI_SYS_BUS)
+	/* PCI System Memory space */
+	pci_set_region(hose->regions + 2,
+		CONFIG_PCI_SYS_BUS,
+		CONFIG_PCI_SYS_PHYS,
+		CONFIG_PCI_SYS_SIZE,
+		PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+	hose->region_count++;
+#endif
+
 	udelay(1000);
 
 	pci_set_ops(hose,
diff --git a/drivers/pci/pci_sh7780.c b/drivers/pci/pci_sh7780.c
index 7555d96..bc06f49 100644
--- a/drivers/pci/pci_sh7780.c
+++ b/drivers/pci/pci_sh7780.c
@@ -85,11 +85,11 @@
 	p4_out(SH7780_PCICR_PREFIX, SH7780_PCICR);
 	p4_outw(0x0047, SH7780_PCICMD);
 
-	p4_out(0x07F00001, SH7780_PCILSR0);
-	p4_out(0x08000000, SH7780_PCILAR0);
+	p4_out(CONFIG_SH7780_PCI_LSR, SH7780_PCILSR0);
+	p4_out(CONFIG_SH7780_PCI_LAR, SH7780_PCILAR0);
 	p4_out(0x00000000, SH7780_PCILSR1);
 	p4_out(0, SH7780_PCILAR1);
-	p4_out(0x08000000, SH7780_PCIMBAR0);
+	p4_out(CONFIG_SH7780_PCI_BAR, SH7780_PCIMBAR0);
 	p4_out(0x00000000, SH7780_PCIMBAR1);
 
 	p4_out(0xFD000000, SH7780_PCIMBR0);
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index 2624e6f..d8b1387 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -215,7 +215,7 @@
 			.bLength =
 				sizeof(struct usb_endpoint_descriptor),
 			.bDescriptorType	= USB_DT_ENDPOINT,
-			.bEndpointAddress	= 0x01 | USB_DIR_IN,
+			.bEndpointAddress	= UDC_INT_ENDPOINT | USB_DIR_IN,
 			.bmAttributes		= USB_ENDPOINT_XFER_INT,
 			.wMaxPacketSize
 				= cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
@@ -241,7 +241,7 @@
 				.bLength		=
 					sizeof(struct usb_endpoint_descriptor),
 				.bDescriptorType	= USB_DT_ENDPOINT,
-				.bEndpointAddress	= 0x02 | USB_DIR_OUT,
+				.bEndpointAddress	= UDC_OUT_ENDPOINT | USB_DIR_OUT,
 				.bmAttributes		=
 					USB_ENDPOINT_XFER_BULK,
 				.wMaxPacketSize		=
@@ -252,7 +252,7 @@
 				.bLength		=
 					sizeof(struct usb_endpoint_descriptor),
 				.bDescriptorType	= USB_DT_ENDPOINT,
-				.bEndpointAddress	= 0x03 | USB_DIR_IN,
+				.bEndpointAddress	= UDC_IN_ENDPOINT | USB_DIR_IN,
 				.bmAttributes		=
 					USB_ENDPOINT_XFER_BULK,
 				.wMaxPacketSize		=
@@ -321,7 +321,7 @@
 				.bLength =
 					sizeof(struct usb_endpoint_descriptor),
 				.bDescriptorType =	USB_DT_ENDPOINT,
-				.bEndpointAddress =	0x01 | USB_DIR_OUT,
+				.bEndpointAddress =	UDC_OUT_ENDPOINT | USB_DIR_OUT,
 				.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 				.wMaxPacketSize =
 					cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE),
@@ -331,7 +331,7 @@
 				.bLength =
 					sizeof(struct usb_endpoint_descriptor),
 				.bDescriptorType =	USB_DT_ENDPOINT,
-				.bEndpointAddress =	0x02 | USB_DIR_IN,
+				.bEndpointAddress =	UDC_IN_ENDPOINT | USB_DIR_IN,
 				.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 				.wMaxPacketSize =
 					cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE),
@@ -341,7 +341,7 @@
 				.bLength =
 					sizeof(struct usb_endpoint_descriptor),
 				.bDescriptorType =	USB_DT_ENDPOINT,
-				.bEndpointAddress =	0x03 | USB_DIR_IN,
+				.bEndpointAddress =	UDC_INT_ENDPOINT | USB_DIR_IN,
 				.bmAttributes =		USB_ENDPOINT_XFER_INT,
 				.wMaxPacketSize =
 					cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index 5957ada..fad9840 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -21,6 +21,7 @@
 #include <common.h>
 #include <malloc.h>
 #include <spi.h>
+#include <asm/errno.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_MX27
@@ -32,6 +33,8 @@
 
 #else
 
+#include <asm/arch/mx31.h>
+
 #define MXC_CSPIRXDATA		0x00
 #define MXC_CSPITXDATA		0x04
 #define MXC_CSPICTRL		0x08
@@ -68,6 +71,7 @@
 	struct spi_slave slave;
 	unsigned long	base;
 	u32		ctrl_reg;
+	int		gpio;
 };
 
 static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)
@@ -85,26 +89,33 @@
 	*(volatile unsigned long*)addr = val;
 }
 
-static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)
+static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen,
+			   unsigned long flags)
 {
 	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
 	unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL);
 
-	if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {
-		cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
-			MXC_CSPICTRL_BITCOUNT(bitlen - 1);
-		reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);
-	}
+	mxcs->ctrl_reg = (mxcs->ctrl_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
+		MXC_CSPICTRL_BITCOUNT(bitlen - 1);
+
+	if (cfg_reg != mxcs->ctrl_reg)
+		reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg);
+
+	if (mxcs->gpio > 0 && (flags & SPI_XFER_BEGIN))
+		mx31_gpio_set(mxcs->gpio, mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL);
 
 	reg_write(mxcs->base + MXC_CSPITXDATA, data);
 
-	cfg_reg |= MXC_CSPICTRL_XCH;
-
-	reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);
+	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg | MXC_CSPICTRL_XCH);
 
 	while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)
 		;
 
+	if (mxcs->gpio > 0 && (flags & SPI_XFER_END)) {
+		mx31_gpio_set(mxcs->gpio,
+			      !(mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL));
+	}
+
 	return reg_read(mxcs->base + MXC_CSPIRXDATA);
 }
 
@@ -122,8 +133,17 @@
 
 	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;
 	     i < n_blks;
-	     i++, in_l++, out_l++, bitlen -= 32)
-		*in_l = spi_xchg_single(slave, *out_l, bitlen);
+	     i++, in_l++, out_l++, bitlen -= 32) {
+		u32 data = spi_xchg_single(slave, *out_l, bitlen, flags);
+
+		/* Check if we're only transfering 8 or 16 bits */
+		if (!i) {
+			if (bitlen < 9)
+				*(u8 *)din = data;
+			else if (bitlen < 17)
+				*(u16 *)din = data;
+		}
+	}
 
 	return 0;
 }
@@ -132,16 +152,55 @@
 {
 }
 
+static int decode_cs(struct mxc_spi_slave *mxcs, unsigned int cs)
+{
+	int ret;
+
+	/*
+	 * Some SPI devices require active chip-select over multiple
+	 * transactions, we achieve this using a GPIO. Still, the SPI
+	 * controller has to be configured to use one of its own chipselects.
+	 * To use this feature you have to call spi_setup_slave() with
+	 * cs = internal_cs | (gpio << 8), and you have to use some unused
+	 * on this SPI controller cs between 0 and 3.
+	 */
+	if (cs > 3) {
+		mxcs->gpio = cs >> 8;
+		cs &= 3;
+		ret = mx31_gpio_direction(mxcs->gpio, MX31_GPIO_DIRECTION_OUT);
+		if (ret) {
+			printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
+			return -EINVAL;
+		}
+	} else {
+		mxcs->gpio = -1;
+	}
+
+	return cs;
+}
+
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 			unsigned int max_hz, unsigned int mode)
 {
 	unsigned int ctrl_reg;
 	struct mxc_spi_slave *mxcs;
+	int ret;
 
-	if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) ||
-	    cs > 3)
+	if (bus >= ARRAY_SIZE(spi_bases))
 		return NULL;
 
+	mxcs = malloc(sizeof(struct mxc_spi_slave));
+	if (!mxcs)
+		return NULL;
+
+	ret = decode_cs(mxcs, cs);
+	if (ret < 0) {
+		free(mxcs);
+		return NULL;
+	}
+
+	cs = ret;
+
 	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) |
 		MXC_CSPICTRL_BITCOUNT(31) |
 		MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */
@@ -155,10 +214,6 @@
 	if (mode & SPI_CS_HIGH)
 		ctrl_reg |= MXC_CSPICTRL_SSPOL;
 
-	mxcs = malloc(sizeof(struct mxc_spi_slave));
-	if (!mxcs)
-		return NULL;
-
 	mxcs->slave.bus = bus;
 	mxcs->slave.cs = cs;
 	mxcs->base = spi_bases[bus];
@@ -169,7 +224,9 @@
 
 void spi_free_slave(struct spi_slave *slave)
 {
-	free(slave);
+	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+
+	free(mxcs);
 }
 
 int spi_claim_bus(struct spi_slave *slave)
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 7fba29f..bc00852 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -28,8 +28,10 @@
 COBJS-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o
 COBJS-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
 COBJS-$(CONFIG_CFB_CONSOLE) += cfb_console.o
+COBJS-$(CONFIG_S6E63D6) += s6e63d6.o
 COBJS-$(CONFIG_VIDEO_CT69000) += ct69000.o
 COBJS-$(CONFIG_VIDEO_MB862xx) += mb862xx.o
+COBJS-$(CONFIG_VIDEO_MX3) += mx3fb.o
 COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o
 COBJS-$(CONFIG_SED156X) += sed156x.o
 COBJS-$(CONFIG_VIDEO_SM501) += sm501.o
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
new file mode 100644
index 0000000..1e1d507
--- /dev/null
+++ b/drivers/video/mx3fb.c
@@ -0,0 +1,856 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@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
+ */
+#include <common.h>
+#include <lcd.h>
+#include <asm/arch/mx31.h>
+#include <asm/arch/mx31-regs.h>
+#include <asm/errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void *lcd_base;			/* Start of framebuffer memory	*/
+void *lcd_console_address;	/* Start of console buffer	*/
+
+int lcd_line_length;
+int lcd_color_fg;
+int lcd_color_bg;
+
+short console_col;
+short console_row;
+
+void lcd_initcolregs(void)
+{
+}
+
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+}
+
+void lcd_disable(void)
+{
+}
+
+void lcd_panel_disable(void)
+{
+}
+
+#define msleep(a) udelay(a * 1000)
+
+#define XRES		240
+#define YRES		320
+#define PANEL_TYPE	IPU_PANEL_TFT
+#define PIXEL_CLK	185925
+#define PIXEL_FMT	IPU_PIX_FMT_RGB666
+#define H_START_WIDTH	9		/* left_margin */
+#define H_SYNC_WIDTH	1		/* hsync_len */
+#define H_END_WIDTH	(16 + 1)	/* right_margin + hsync_len */
+#define V_START_WIDTH	7		/* upper_margin */
+#define V_SYNC_WIDTH	1		/* vsync_len */
+#define V_END_WIDTH	(9 + 1)		/* lower_margin + vsync_len */
+#define SIG_POL		(DI_D3_DRDY_SHARP_POL | DI_D3_CLK_POL)
+#define IF_CONF		0
+#define IF_CLK_DIV	0x175
+
+#define LCD_COLOR_IPU	LCD_COLOR16
+
+static ushort colormap[256];
+
+vidinfo_t panel_info = {
+	.vl_col		= XRES,
+	.vl_row		= YRES,
+	.vl_bpix	= LCD_COLOR_IPU,
+	.cmap		= colormap,
+};
+
+#define BIT_PER_PIXEL	NBITS(LCD_COLOR_IPU)
+
+/* IPU DMA Controller channel definitions. */
+enum ipu_channel {
+	IDMAC_IC_0 = 0,		/* IC (encoding task) to memory */
+	IDMAC_IC_1 = 1,		/* IC (viewfinder task) to memory */
+	IDMAC_ADC_0 = 1,
+	IDMAC_IC_2 = 2,
+	IDMAC_ADC_1 = 2,
+	IDMAC_IC_3 = 3,
+	IDMAC_IC_4 = 4,
+	IDMAC_IC_5 = 5,
+	IDMAC_IC_6 = 6,
+	IDMAC_IC_7 = 7,		/* IC (sensor data) to memory */
+	IDMAC_IC_8 = 8,
+	IDMAC_IC_9 = 9,
+	IDMAC_IC_10 = 10,
+	IDMAC_IC_11 = 11,
+	IDMAC_IC_12 = 12,
+	IDMAC_IC_13 = 13,
+	IDMAC_SDC_0 = 14,	/* Background synchronous display data */
+	IDMAC_SDC_1 = 15,	/* Foreground data (overlay) */
+	IDMAC_SDC_2 = 16,
+	IDMAC_SDC_3 = 17,
+	IDMAC_ADC_2 = 18,
+	IDMAC_ADC_3 = 19,
+	IDMAC_ADC_4 = 20,
+	IDMAC_ADC_5 = 21,
+	IDMAC_ADC_6 = 22,
+	IDMAC_ADC_7 = 23,
+	IDMAC_PF_0 = 24,
+	IDMAC_PF_1 = 25,
+	IDMAC_PF_2 = 26,
+	IDMAC_PF_3 = 27,
+	IDMAC_PF_4 = 28,
+	IDMAC_PF_5 = 29,
+	IDMAC_PF_6 = 30,
+	IDMAC_PF_7 = 31,
+};
+
+/* More formats can be copied from the Linux driver if needed */
+enum pixel_fmt {
+	/* 2 bytes */
+	IPU_PIX_FMT_RGB565,
+	IPU_PIX_FMT_RGB666,
+	IPU_PIX_FMT_BGR666,
+	/* 3 bytes */
+	IPU_PIX_FMT_RGB24,
+};
+
+struct pixel_fmt_cfg {
+	u32	b0;
+	u32	b1;
+	u32	b2;
+	u32	acc;
+};
+
+static struct pixel_fmt_cfg fmt_cfg[] = {
+	[IPU_PIX_FMT_RGB24] = {
+		0x1600AAAA, 0x00E05555, 0x00070000, 3,
+	},
+	[IPU_PIX_FMT_RGB666] = {
+		0x0005000F, 0x000B000F, 0x0011000F, 1,
+	},
+	[IPU_PIX_FMT_BGR666] = {
+		0x0011000F, 0x000B000F, 0x0005000F, 1,
+	},
+	[IPU_PIX_FMT_RGB565] = {
+		0x0004003F, 0x000A000F, 0x000F003F, 1,
+	}
+};
+
+enum ipu_panel {
+	IPU_PANEL_SHARP_TFT,
+	IPU_PANEL_TFT,
+};
+
+/* IPU Common registers */
+/* IPU_CONF and its bits already defined in mx31-regs.h */
+#define IPU_CHA_BUF0_RDY	(0x04 + IPU_BASE)
+#define IPU_CHA_BUF1_RDY	(0x08 + IPU_BASE)
+#define IPU_CHA_DB_MODE_SEL	(0x0C + IPU_BASE)
+#define IPU_CHA_CUR_BUF		(0x10 + IPU_BASE)
+#define IPU_FS_PROC_FLOW	(0x14 + IPU_BASE)
+#define IPU_FS_DISP_FLOW	(0x18 + IPU_BASE)
+#define IPU_TASKS_STAT		(0x1C + IPU_BASE)
+#define IPU_IMA_ADDR		(0x20 + IPU_BASE)
+#define IPU_IMA_DATA		(0x24 + IPU_BASE)
+#define IPU_INT_CTRL_1		(0x28 + IPU_BASE)
+#define IPU_INT_CTRL_2		(0x2C + IPU_BASE)
+#define IPU_INT_CTRL_3		(0x30 + IPU_BASE)
+#define IPU_INT_CTRL_4		(0x34 + IPU_BASE)
+#define IPU_INT_CTRL_5		(0x38 + IPU_BASE)
+#define IPU_INT_STAT_1		(0x3C + IPU_BASE)
+#define IPU_INT_STAT_2		(0x40 + IPU_BASE)
+#define IPU_INT_STAT_3		(0x44 + IPU_BASE)
+#define IPU_INT_STAT_4		(0x48 + IPU_BASE)
+#define IPU_INT_STAT_5		(0x4C + IPU_BASE)
+#define IPU_BRK_CTRL_1		(0x50 + IPU_BASE)
+#define IPU_BRK_CTRL_2		(0x54 + IPU_BASE)
+#define IPU_BRK_STAT		(0x58 + IPU_BASE)
+#define IPU_DIAGB_CTRL		(0x5C + IPU_BASE)
+
+/* Image Converter Registers */
+#define IC_CONF			(0x88 + IPU_BASE)
+#define IC_PRP_ENC_RSC		(0x8C + IPU_BASE)
+#define IC_PRP_VF_RSC		(0x90 + IPU_BASE)
+#define IC_PP_RSC		(0x94 + IPU_BASE)
+#define IC_CMBP_1		(0x98 + IPU_BASE)
+#define IC_CMBP_2		(0x9C + IPU_BASE)
+#define PF_CONF			(0xA0 + IPU_BASE)
+#define IDMAC_CONF		(0xA4 + IPU_BASE)
+#define IDMAC_CHA_EN		(0xA8 + IPU_BASE)
+#define IDMAC_CHA_PRI		(0xAC + IPU_BASE)
+#define IDMAC_CHA_BUSY		(0xB0 + IPU_BASE)
+
+/* Image Converter Register bits */
+#define IC_CONF_PRPENC_EN	0x00000001
+#define IC_CONF_PRPENC_CSC1	0x00000002
+#define IC_CONF_PRPENC_ROT_EN	0x00000004
+#define IC_CONF_PRPVF_EN	0x00000100
+#define IC_CONF_PRPVF_CSC1	0x00000200
+#define IC_CONF_PRPVF_CSC2	0x00000400
+#define IC_CONF_PRPVF_CMB	0x00000800
+#define IC_CONF_PRPVF_ROT_EN	0x00001000
+#define IC_CONF_PP_EN		0x00010000
+#define IC_CONF_PP_CSC1		0x00020000
+#define IC_CONF_PP_CSC2		0x00040000
+#define IC_CONF_PP_CMB		0x00080000
+#define IC_CONF_PP_ROT_EN	0x00100000
+#define IC_CONF_IC_GLB_LOC_A	0x10000000
+#define IC_CONF_KEY_COLOR_EN	0x20000000
+#define IC_CONF_RWS_EN		0x40000000
+#define IC_CONF_CSI_MEM_WR_EN	0x80000000
+
+/* SDC Registers */
+#define SDC_COM_CONF		(0xB4 + IPU_BASE)
+#define SDC_GW_CTRL		(0xB8 + IPU_BASE)
+#define SDC_FG_POS		(0xBC + IPU_BASE)
+#define SDC_BG_POS		(0xC0 + IPU_BASE)
+#define SDC_CUR_POS		(0xC4 + IPU_BASE)
+#define SDC_PWM_CTRL		(0xC8 + IPU_BASE)
+#define SDC_CUR_MAP		(0xCC + IPU_BASE)
+#define SDC_HOR_CONF		(0xD0 + IPU_BASE)
+#define SDC_VER_CONF		(0xD4 + IPU_BASE)
+#define SDC_SHARP_CONF_1	(0xD8 + IPU_BASE)
+#define SDC_SHARP_CONF_2	(0xDC + IPU_BASE)
+
+/* Register bits */
+#define SDC_COM_TFT_COLOR	0x00000001UL
+#define SDC_COM_FG_EN		0x00000010UL
+#define SDC_COM_GWSEL		0x00000020UL
+#define SDC_COM_GLB_A		0x00000040UL
+#define SDC_COM_KEY_COLOR_G	0x00000080UL
+#define SDC_COM_BG_EN		0x00000200UL
+#define SDC_COM_SHARP		0x00001000UL
+
+#define SDC_V_SYNC_WIDTH_L	0x00000001UL
+
+/* Display Interface registers */
+#define DI_DISP_IF_CONF		(0x0124 + IPU_BASE)
+#define DI_DISP_SIG_POL		(0x0128 + IPU_BASE)
+#define DI_SER_DISP1_CONF	(0x012C + IPU_BASE)
+#define DI_SER_DISP2_CONF	(0x0130 + IPU_BASE)
+#define DI_HSP_CLK_PER		(0x0134 + IPU_BASE)
+#define DI_DISP0_TIME_CONF_1	(0x0138 + IPU_BASE)
+#define DI_DISP0_TIME_CONF_2	(0x013C + IPU_BASE)
+#define DI_DISP0_TIME_CONF_3	(0x0140 + IPU_BASE)
+#define DI_DISP1_TIME_CONF_1	(0x0144 + IPU_BASE)
+#define DI_DISP1_TIME_CONF_2	(0x0148 + IPU_BASE)
+#define DI_DISP1_TIME_CONF_3	(0x014C + IPU_BASE)
+#define DI_DISP2_TIME_CONF_1	(0x0150 + IPU_BASE)
+#define DI_DISP2_TIME_CONF_2	(0x0154 + IPU_BASE)
+#define DI_DISP2_TIME_CONF_3	(0x0158 + IPU_BASE)
+#define DI_DISP3_TIME_CONF	(0x015C + IPU_BASE)
+#define DI_DISP0_DB0_MAP	(0x0160 + IPU_BASE)
+#define DI_DISP0_DB1_MAP	(0x0164 + IPU_BASE)
+#define DI_DISP0_DB2_MAP	(0x0168 + IPU_BASE)
+#define DI_DISP0_CB0_MAP	(0x016C + IPU_BASE)
+#define DI_DISP0_CB1_MAP	(0x0170 + IPU_BASE)
+#define DI_DISP0_CB2_MAP	(0x0174 + IPU_BASE)
+#define DI_DISP1_DB0_MAP	(0x0178 + IPU_BASE)
+#define DI_DISP1_DB1_MAP	(0x017C + IPU_BASE)
+#define DI_DISP1_DB2_MAP	(0x0180 + IPU_BASE)
+#define DI_DISP1_CB0_MAP	(0x0184 + IPU_BASE)
+#define DI_DISP1_CB1_MAP	(0x0188 + IPU_BASE)
+#define DI_DISP1_CB2_MAP	(0x018C + IPU_BASE)
+#define DI_DISP2_DB0_MAP	(0x0190 + IPU_BASE)
+#define DI_DISP2_DB1_MAP	(0x0194 + IPU_BASE)
+#define DI_DISP2_DB2_MAP	(0x0198 + IPU_BASE)
+#define DI_DISP2_CB0_MAP	(0x019C + IPU_BASE)
+#define DI_DISP2_CB1_MAP	(0x01A0 + IPU_BASE)
+#define DI_DISP2_CB2_MAP	(0x01A4 + IPU_BASE)
+#define DI_DISP3_B0_MAP		(0x01A8 + IPU_BASE)
+#define DI_DISP3_B1_MAP		(0x01AC + IPU_BASE)
+#define DI_DISP3_B2_MAP		(0x01B0 + IPU_BASE)
+#define DI_DISP_ACC_CC		(0x01B4 + IPU_BASE)
+#define DI_DISP_LLA_CONF	(0x01B8 + IPU_BASE)
+#define DI_DISP_LLA_DATA	(0x01BC + IPU_BASE)
+
+/* DI_DISP_SIG_POL bits */
+#define DI_D3_VSYNC_POL		(1 << 28)
+#define DI_D3_HSYNC_POL		(1 << 27)
+#define DI_D3_DRDY_SHARP_POL	(1 << 26)
+#define DI_D3_CLK_POL		(1 << 25)
+#define DI_D3_DATA_POL		(1 << 24)
+
+/* DI_DISP_IF_CONF bits */
+#define DI_D3_CLK_IDLE		(1 << 26)
+#define DI_D3_CLK_SEL		(1 << 25)
+#define DI_D3_DATAMSK		(1 << 24)
+
+#define IOMUX_PADNUM_MASK	0x1ff
+#define IOMUX_GPIONUM_SHIFT	9
+#define IOMUX_GPIONUM_MASK	(0xff << IOMUX_GPIONUM_SHIFT)
+
+#define IOMUX_PIN(gpionum, padnum) ((padnum) & IOMUX_PADNUM_MASK)
+
+#define IOMUX_MODE_L(pin, mode) IOMUX_MODE(((pin) + 0xc) ^ 3, mode)
+
+enum lcd_pin {
+	MX31_PIN_D3_SPL		= IOMUX_PIN(0xff,  19),
+	MX31_PIN_D3_CLS		= IOMUX_PIN(0xff,  20),
+	MX31_PIN_D3_REV		= IOMUX_PIN(0xff,  21),
+	MX31_PIN_CONTRAST	= IOMUX_PIN(0xff,  22),
+	MX31_PIN_VSYNC3		= IOMUX_PIN(0xff,  23),
+
+	MX31_PIN_DRDY0		= IOMUX_PIN(0xff,  33),
+	MX31_PIN_FPSHIFT	= IOMUX_PIN(0xff,  34),
+	MX31_PIN_HSYNC		= IOMUX_PIN(0xff,  35),
+
+	MX31_PIN_LD17		= IOMUX_PIN(0xff,  37),
+	MX31_PIN_LD16		= IOMUX_PIN(0xff,  38),
+	MX31_PIN_LD15		= IOMUX_PIN(0xff,  39),
+	MX31_PIN_LD14		= IOMUX_PIN(0xff,  40),
+	MX31_PIN_LD13		= IOMUX_PIN(0xff,  41),
+	MX31_PIN_LD12		= IOMUX_PIN(0xff,  42),
+	MX31_PIN_LD11		= IOMUX_PIN(0xff,  43),
+	MX31_PIN_LD10		= IOMUX_PIN(0xff,  44),
+	MX31_PIN_LD9		= IOMUX_PIN(0xff,  45),
+	MX31_PIN_LD8		= IOMUX_PIN(0xff,  46),
+	MX31_PIN_LD7		= IOMUX_PIN(0xff,  47),
+	MX31_PIN_LD6		= IOMUX_PIN(0xff,  48),
+	MX31_PIN_LD5		= IOMUX_PIN(0xff,  49),
+	MX31_PIN_LD4		= IOMUX_PIN(0xff,  50),
+	MX31_PIN_LD3		= IOMUX_PIN(0xff,  51),
+	MX31_PIN_LD2		= IOMUX_PIN(0xff,  52),
+	MX31_PIN_LD1		= IOMUX_PIN(0xff,  53),
+	MX31_PIN_LD0		= IOMUX_PIN(0xff,  54),
+};
+
+struct chan_param_mem_planar {
+	/* Word 0 */
+	u32	xv:10;
+	u32	yv:10;
+	u32	xb:12;
+
+	u32	yb:12;
+	u32	res1:2;
+	u32	nsb:1;
+	u32	lnpb:6;
+	u32	ubo_l:11;
+
+	u32	ubo_h:15;
+	u32	vbo_l:17;
+
+	u32	vbo_h:9;
+	u32	res2:3;
+	u32	fw:12;
+	u32	fh_l:8;
+
+	u32	fh_h:4;
+	u32	res3:28;
+
+	/* Word 1 */
+	u32	eba0;
+
+	u32	eba1;
+
+	u32	bpp:3;
+	u32	sl:14;
+	u32	pfs:3;
+	u32	bam:3;
+	u32	res4:2;
+	u32	npb:6;
+	u32	res5:1;
+
+	u32	sat:2;
+	u32	res6:30;
+} __attribute__ ((packed));
+
+struct chan_param_mem_interleaved {
+	/* Word 0 */
+	u32	xv:10;
+	u32	yv:10;
+	u32	xb:12;
+
+	u32	yb:12;
+	u32	sce:1;
+	u32	res1:1;
+	u32	nsb:1;
+	u32	lnpb:6;
+	u32	sx:10;
+	u32	sy_l:1;
+
+	u32	sy_h:9;
+	u32	ns:10;
+	u32	sm:10;
+	u32	sdx_l:3;
+
+	u32	sdx_h:2;
+	u32	sdy:5;
+	u32	sdrx:1;
+	u32	sdry:1;
+	u32	sdr1:1;
+	u32	res2:2;
+	u32	fw:12;
+	u32	fh_l:8;
+
+	u32	fh_h:4;
+	u32	res3:28;
+
+	/* Word 1 */
+	u32	eba0;
+
+	u32	eba1;
+
+	u32	bpp:3;
+	u32	sl:14;
+	u32	pfs:3;
+	u32	bam:3;
+	u32	res4:2;
+	u32	npb:6;
+	u32	res5:1;
+
+	u32	sat:2;
+	u32	scc:1;
+	u32	ofs0:5;
+	u32	ofs1:5;
+	u32	ofs2:5;
+	u32	ofs3:5;
+	u32	wid0:3;
+	u32	wid1:3;
+	u32	wid2:3;
+
+	u32	wid3:3;
+	u32	dec_sel:1;
+	u32	res6:28;
+} __attribute__ ((packed));
+
+union chan_param_mem {
+	struct chan_param_mem_planar		pp;
+	struct chan_param_mem_interleaved	ip;
+};
+
+static inline u32 reg_read(unsigned long reg)
+{
+	return __REG(reg);
+}
+
+static inline void reg_write(u32 value, unsigned long reg)
+{
+	__REG(reg) = value;
+}
+
+/*
+ * sdc_init_panel() - initialize a synchronous LCD panel.
+ * @width:		width of panel in pixels.
+ * @height:		height of panel in pixels.
+ * @pixel_fmt:		pixel format of buffer as FOURCC ASCII code.
+ * @return:		0 on success or negative error code on failure.
+ */
+static int sdc_init_panel(u16 width, u16 height, enum pixel_fmt pixel_fmt)
+{
+	u32 reg;
+	uint32_t old_conf;
+
+	/* Init panel size and blanking periods */
+	reg = ((H_SYNC_WIDTH - 1) << 26) |
+		((u32)(width + H_START_WIDTH + H_END_WIDTH - 1) << 16);
+	reg_write(reg, SDC_HOR_CONF);
+
+	reg = ((V_SYNC_WIDTH - 1) << 26) | SDC_V_SYNC_WIDTH_L |
+		((u32)(height + V_START_WIDTH + V_END_WIDTH - 1) << 16);
+	reg_write(reg, SDC_VER_CONF);
+
+	switch (PANEL_TYPE) {
+	case IPU_PANEL_SHARP_TFT:
+		reg_write(0x00FD0102L, SDC_SHARP_CONF_1);
+		reg_write(0x00F500F4L, SDC_SHARP_CONF_2);
+		reg_write(SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
+		break;
+	case IPU_PANEL_TFT:
+		reg_write(SDC_COM_TFT_COLOR, SDC_COM_CONF);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Init clocking */
+
+	/*
+	 * Calculate divider: fractional part is 4 bits so simply multiple by
+	 * 2^4 to get fractional part, as long as we stay under ~250MHz and on
+	 * i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz
+	 */
+
+	reg_write((((IF_CLK_DIV / 8) - 1) << 22) |
+			IF_CLK_DIV, DI_DISP3_TIME_CONF);
+
+	/* DI settings */
+	old_conf = reg_read(DI_DISP_IF_CONF) & 0x78FFFFFF;
+	reg_write(old_conf | IF_CONF, DI_DISP_IF_CONF);
+
+	old_conf = reg_read(DI_DISP_SIG_POL) & 0xE0FFFFFF;
+	reg_write(old_conf | SIG_POL, DI_DISP_SIG_POL);
+
+	reg_write(fmt_cfg[pixel_fmt].b0, DI_DISP3_B0_MAP);
+	reg_write(fmt_cfg[pixel_fmt].b1, DI_DISP3_B1_MAP);
+	reg_write(fmt_cfg[pixel_fmt].b2, DI_DISP3_B2_MAP);
+	reg_write(reg_read(DI_DISP_ACC_CC) |
+		  ((fmt_cfg[pixel_fmt].acc - 1) << 12), DI_DISP_ACC_CC);
+
+	return 0;
+}
+
+static void ipu_ch_param_set_size(union chan_param_mem *params,
+				  uint32_t pixel_fmt, uint16_t width,
+				  uint16_t height, uint16_t stride)
+{
+	params->pp.fw		= width - 1;
+	params->pp.fh_l		= height - 1;
+	params->pp.fh_h		= (height - 1) >> 8;
+	params->pp.sl		= stride - 1;
+
+	/* See above, for further formats see the Linux driver */
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_RGB565:
+		params->ip.bpp	= 2;
+		params->ip.pfs	= 4;
+		params->ip.npb	= 7;
+		params->ip.sat	= 2;		/* SAT = 32-bit access */
+		params->ip.ofs0	= 0;		/* Red bit offset */
+		params->ip.ofs1	= 5;		/* Green bit offset */
+		params->ip.ofs2	= 11;		/* Blue bit offset */
+		params->ip.ofs3	= 16;		/* Alpha bit offset */
+		params->ip.wid0	= 4;		/* Red bit width - 1 */
+		params->ip.wid1	= 5;		/* Green bit width - 1 */
+		params->ip.wid2	= 4;		/* Blue bit width - 1 */
+		break;
+	case IPU_PIX_FMT_RGB24:
+		params->ip.bpp	= 1;		/* 24 BPP & RGB PFS */
+		params->ip.pfs	= 4;
+		params->ip.npb	= 7;
+		params->ip.sat	= 2;		/* SAT = 32-bit access */
+		params->ip.ofs0	= 16;		/* Red bit offset */
+		params->ip.ofs1	= 8;		/* Green bit offset */
+		params->ip.ofs2	= 0;		/* Blue bit offset */
+		params->ip.ofs3	= 24;		/* Alpha bit offset */
+		params->ip.wid0	= 7;		/* Red bit width - 1 */
+		params->ip.wid1	= 7;		/* Green bit width - 1 */
+		params->ip.wid2	= 7;		/* Blue bit width - 1 */
+		break;
+	default:
+		break;
+	}
+
+	params->pp.nsb = 1;
+}
+
+static void ipu_ch_param_set_buffer(union chan_param_mem *params,
+				    void *buf0, void *buf1)
+{
+	params->pp.eba0 = (u32)buf0;
+	params->pp.eba1 = (u32)buf1;
+}
+
+static void ipu_write_param_mem(uint32_t addr, uint32_t *data,
+				uint32_t num_words)
+{
+	for (; num_words > 0; num_words--) {
+		reg_write(addr, IPU_IMA_ADDR);
+		reg_write(*data++, IPU_IMA_DATA);
+		addr++;
+		if ((addr & 0x7) == 5) {
+			addr &= ~0x7;	/* set to word 0 */
+			addr += 8;	/* increment to next row */
+		}
+	}
+}
+
+static uint32_t bpp_to_pixfmt(int bpp)
+{
+	switch (bpp) {
+	case 16:
+		return IPU_PIX_FMT_RGB565;
+	default:
+		return 0;
+	}
+}
+
+static uint32_t dma_param_addr(enum ipu_channel channel)
+{
+	/* Channel Parameter Memory */
+	return 0x10000 | (channel << 4);
+}
+
+static void ipu_init_channel_buffer(enum ipu_channel channel, void *fbmem)
+{
+	union chan_param_mem params = {};
+	uint32_t reg;
+	uint32_t stride_bytes;
+
+	stride_bytes = (XRES * ((BIT_PER_PIXEL + 7) / 8) + 3) & ~3;
+
+	/* Build parameter memory data for DMA channel */
+	ipu_ch_param_set_size(&params, bpp_to_pixfmt(BIT_PER_PIXEL),
+			      XRES, YRES, stride_bytes);
+	ipu_ch_param_set_buffer(&params, fbmem, NULL);
+	params.pp.bam = 0;
+	/* Some channels (rotation) have restriction on burst length */
+
+	switch (channel) {
+	case IDMAC_SDC_0:
+		/* In original code only IPU_PIX_FMT_RGB565 was setting burst */
+		params.pp.npb = 16 - 1;
+		break;
+	default:
+		break;
+	}
+
+	ipu_write_param_mem(dma_param_addr(channel), (uint32_t *)&params, 10);
+
+	/* Disable double-buffering */
+	reg = reg_read(IPU_CHA_DB_MODE_SEL);
+	reg &= ~(1UL << channel);
+	reg_write(reg, IPU_CHA_DB_MODE_SEL);
+}
+
+static void ipu_channel_set_priority(enum ipu_channel channel,
+				     int prio)
+{
+	u32 reg = reg_read(IDMAC_CHA_PRI);
+
+	if (prio)
+		reg |= 1UL << channel;
+	else
+		reg &= ~(1UL << channel);
+
+	reg_write(reg, IDMAC_CHA_PRI);
+}
+
+/*
+ * ipu_enable_channel() - enable an IPU channel.
+ * @channel:	channel ID.
+ * @return:	0 on success or negative error code on failure.
+ */
+static int ipu_enable_channel(enum ipu_channel channel)
+{
+	uint32_t reg;
+
+	/* Reset to buffer 0 */
+	reg_write(1UL << channel, IPU_CHA_CUR_BUF);
+
+	switch (channel) {
+	case IDMAC_SDC_0:
+		ipu_channel_set_priority(channel, 1);
+		break;
+	default:
+		break;
+	}
+
+	reg = reg_read(IDMAC_CHA_EN);
+	reg_write(reg | (1UL << channel), IDMAC_CHA_EN);
+
+	return 0;
+}
+
+static int ipu_update_channel_buffer(enum ipu_channel channel, void *buf)
+{
+	uint32_t reg;
+
+	reg = reg_read(IPU_CHA_BUF0_RDY);
+	if (reg & (1UL << channel))
+		return -EACCES;
+
+	/* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */
+	reg_write(dma_param_addr(channel) + 0x0008UL, IPU_IMA_ADDR);
+	reg_write((u32)buf, IPU_IMA_DATA);
+
+	return 0;
+}
+
+static int idmac_tx_submit(enum ipu_channel channel, void *buf)
+{
+	int ret;
+
+	ipu_init_channel_buffer(channel, buf);
+
+
+	/* ipu_idmac.c::ipu_submit_channel_buffers() */
+	ret = ipu_update_channel_buffer(channel, buf);
+	if (ret < 0)
+		return ret;
+
+	/* ipu_idmac.c::ipu_select_buffer() */
+	/* Mark buffer 0 as ready. */
+	reg_write(1UL << channel, IPU_CHA_BUF0_RDY);
+
+
+	ret = ipu_enable_channel(channel);
+	return ret;
+}
+
+static void sdc_enable_channel(void *fbmem)
+{
+	int ret;
+	u32 reg;
+
+	ret = idmac_tx_submit(IDMAC_SDC_0, fbmem);
+
+	/* mx3fb.c::sdc_fb_init() */
+	if (ret >= 0) {
+		reg = reg_read(SDC_COM_CONF);
+		reg_write(reg | SDC_COM_BG_EN, SDC_COM_CONF);
+	}
+
+	/*
+	 * Attention! Without this msleep the channel keeps generating
+	 * interrupts. Next sdc_set_brightness() is going to be called
+	 * from mx3fb_blank().
+	 */
+	msleep(2);
+}
+
+/*
+ * mx3fb_set_par() - set framebuffer parameters and change the operating mode.
+ * @return:	0 on success or negative error code on failure.
+ */
+static int mx3fb_set_par(void)
+{
+	int ret;
+
+	ret = sdc_init_panel(XRES, YRES, PIXEL_FMT);
+	if (ret < 0)
+		return ret;
+
+	reg_write((H_START_WIDTH << 16) | V_START_WIDTH, SDC_BG_POS);
+
+	return 0;
+}
+
+/* References in this function refer to respective Linux kernel sources */
+void lcd_enable(void)
+{
+	u32 reg;
+
+	/* pcm037.c::mxc_board_init() */
+
+	/* Display Interface #3 */
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD0, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD1, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD2, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD3, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD4, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD5, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD6, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD7, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD8, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD9, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD10, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD11, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD12, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD13, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD14, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD15, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD16, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD17, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_VSYNC3, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_HSYNC, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_FPSHIFT, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_DRDY0, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_REV, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_CONTRAST, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_SPL, MUX_CTL_FUNC));
+	mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_CLS, MUX_CTL_FUNC));
+
+
+	/* ipu_idmac.c::ipu_probe() */
+
+	/* Start the clock */
+	__REG(CCM_CGR1) = __REG(CCM_CGR1) | (3 << 22);
+
+
+	/* ipu_idmac.c::ipu_idmac_init() */
+
+	/* Service request counter to maximum - shouldn't be needed */
+	reg_write(0x00000070, IDMAC_CONF);
+
+
+	/* ipu_idmac.c::ipu_init_channel() */
+
+	/* Enable IPU sub modules */
+	reg = reg_read(IPU_CONF) | IPU_CONF_SDC_EN | IPU_CONF_DI_EN;
+	reg_write(reg, IPU_CONF);
+
+
+	/* mx3fb.c::init_fb_chan() */
+
+	/* set Display Interface clock period */
+	reg_write(0x00100010L, DI_HSP_CLK_PER);
+	/* Might need to trigger HSP clock change - see 44.3.3.8.5 */
+
+
+	/* mx3fb.c::sdc_set_brightness() */
+
+	/* This might be board-specific */
+	reg_write(0x03000000UL | 255 << 16, SDC_PWM_CTRL);
+
+
+	/* mx3fb.c::sdc_set_global_alpha() */
+
+	/* Use global - not per-pixel - Alpha-blending */
+	reg = reg_read(SDC_GW_CTRL) & 0x00FFFFFFL;
+	reg_write(reg | ((uint32_t) 0xff << 24), SDC_GW_CTRL);
+
+	reg = reg_read(SDC_COM_CONF);
+	reg_write(reg | SDC_COM_GLB_A, SDC_COM_CONF);
+
+
+	/* mx3fb.c::sdc_set_color_key() */
+
+	/* Disable colour-keying for background */
+	reg = reg_read(SDC_COM_CONF) &
+		~(SDC_COM_GWSEL | SDC_COM_KEY_COLOR_G);
+	reg_write(reg, SDC_COM_CONF);
+
+
+	mx3fb_set_par();
+
+	sdc_enable_channel(lcd_base);
+
+	/*
+	 * Linux driver calls sdc_set_brightness() here again,
+	 * once is enough for us
+	 */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	u32 mem_len = XRES * YRES * BIT_PER_PIXEL / 8;
+	/*
+	 * We rely on lcdbase being a physical address, i.e., either MMU off,
+	 * or 1-to-1 mapping. Might want to add some virt2phys here.
+	 */
+	if (!lcdbase)
+		return;
+
+	memset(lcdbase, 0, mem_len);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+		NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
+
+int overwrite_console(void)
+{
+	/* Keep stdout / stderr on serial, our LCD is for splashscreen only */
+	return 1;
+}
diff --git a/drivers/video/s6e63d6.c b/drivers/video/s6e63d6.c
new file mode 100644
index 0000000..d163506
--- /dev/null
+++ b/drivers/video/s6e63d6.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@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
+ */
+#include <common.h>
+#include <spi.h>
+#include <s6e63d6.h>
+
+/*
+ * Each transfer is performed as:
+ * 1. chip-select active
+ * 2. send 8-bit start code
+ * 3. send 16-bit data
+ * 4. chip-select inactive
+ */
+static int send_word(struct s6e63d6 *data, u8 rs, u16 word)
+{
+	/*
+	 * The start byte looks like (binary):
+	 * 01110<ID><RS><R/W>
+	 * RS is 0 for index or 1 for data, and R/W is 0 for write.
+	 */
+	u32 buf8 = 0x70 | data->id | (rs & 2);
+	u32 buf16 = cpu_to_le16(word);
+	u32 buf_in;
+	int err;
+
+	err = spi_xfer(data->slave, 8, &buf8, &buf_in, SPI_XFER_BEGIN);
+	if (err)
+		return err;
+
+	return spi_xfer(data->slave, 16, &buf16, &buf_in, SPI_XFER_END);
+}
+
+/* Index and param differ in Register Select bit */
+int s6e63d6_index(struct s6e63d6 *data, u8 idx)
+{
+	return send_word(data, 0, idx);
+}
+
+int s6e63d6_param(struct s6e63d6 *data, u16 param)
+{
+	return send_word(data, 2, param);
+}
+
+int s6e63d6_init(struct s6e63d6 *data)
+{
+	if (data->id != 0 && data->id != 4) {
+		printf("s6e63d6: invalid ID %u\n", data->id);
+		return 1;
+	}
+
+	data->slave = spi_setup_slave(data->bus, data->cs, 100000, SPI_MODE_3);
+	if (!data->slave)
+		return 1;
+
+	return 0;
+}
diff --git a/examples/.gitignore b/examples/.gitignore
index 806425f..0d1864c 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -6,5 +6,6 @@
 /timer
 /sched
 /smc91111_eeprom
+/smc911x_eeprom
 *.bin
 *.srec
diff --git a/examples/Makefile b/examples/Makefile
index 927010d..dbcfa92 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -105,9 +105,10 @@
 endif
 
 ifeq ($(ARCH),blackfin)
-ELF	+= smc91111_eeprom
-SREC	+= smc91111_eeprom.srec
-BIN	+= smc91111_eeprom.bin
+BFIN_BIN = smc91111_eeprom smc911x_eeprom
+ELF	+= $(BFIN_BIN)
+SREC	+= $(addsuffix .srec,$(BFIN_BIN))
+BIN	+= $(addsuffix .bin,$(BFIN_BIN))
 endif
 
 # The following example is pretty 8xx specific...
diff --git a/examples/mips.lds b/examples/mips.lds
index 939e0e6..717b201 100644
--- a/examples/mips.lds
+++ b/examples/mips.lds
@@ -34,7 +34,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata  : { *(.rodata) }
+	.rodata  : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data  : { *(.data) }
diff --git a/examples/nios.lds b/examples/nios.lds
index 18072f7..4c1080b 100644
--- a/examples/nios.lds
+++ b/examples/nios.lds
@@ -37,7 +37,7 @@
 	. = ALIGN(4);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	__rodata_end = .;
 
diff --git a/examples/nios2.lds b/examples/nios2.lds
index 6a100dc..a3e5ea8 100644
--- a/examples/nios2.lds
+++ b/examples/nios2.lds
@@ -33,8 +33,7 @@
 	  *(.text)
 	  *(.text.*)
 	  *(.gnu.linkonce.t*)
-	  *(.rodata)
-	  *(.rodata.*)
+	  *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	  *(.gnu.linkonce.r*)
 	}
 	. = ALIGN (4);
diff --git a/examples/smc911x_eeprom.c b/examples/smc911x_eeprom.c
new file mode 100644
index 0000000..bf22f0a
--- /dev/null
+++ b/examples/smc911x_eeprom.c
@@ -0,0 +1,383 @@
+/*
+ * smc911x_eeprom.c - EEPROM interface to SMC911x parts.
+ * Only tested on SMSC9118 though ...
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * Based on smc91111_eeprom.c which:
+ * Heavily borrowed from the following peoples GPL'ed software:
+ *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ *       Das U-boot
+ *  - Ladislav Michl ladis@linux-mips.org
+ *       A rejected patch on the U-Boot mailing list
+ */
+
+#include <common.h>
+#include <exports.h>
+
+#ifdef CONFIG_DRIVER_SMC911X
+
+#include "../drivers/net/smc911x.h"
+
+/**
+ *	smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?)
+ */
+static int smsc_ctrlc(void)
+{
+	return (tstc() && getc() == 0x03);
+}
+
+/**
+ *	usage - dump usage information
+ */
+static void usage(void)
+{
+	puts(
+		"MAC/EEPROM Commands:\n"
+		" P : Print the MAC addresses\n"
+		" D : Dump the EEPROM contents\n"
+		" M : Dump the MAC contents\n"
+		" C : Copy the MAC address from the EEPROM to the MAC\n"
+		" W : Write a register in the EEPROM or in the MAC\n"
+		" Q : Quit\n"
+		"\n"
+		"Some commands take arguments:\n"
+		" W <E|M> <register> <value>\n"
+		"    E: EEPROM   M: MAC\n"
+	);
+}
+
+/**
+ *	dump_regs - dump the MAC registers
+ *
+ * Registers 0x00 - 0x50 are FIFOs.  The 0x50+ are the control registers
+ * and they're all 32bits long.  0xB8+ are reserved, so don't bother.
+ */
+static void dump_regs(void)
+{
+	u8 i, j = 0;
+	for (i = 0x50; i < 0xB8; i += sizeof(u32))
+		printf("%02x: 0x%08x %c", i,
+			smc911x_reg_read(CONFIG_DRIVER_SMC911X_BASE + i),
+			(j++ % 2 ? '\n' : ' '));
+}
+
+/**
+ *	do_eeprom_cmd - handle eeprom communication
+ */
+static int do_eeprom_cmd(int cmd, u8 reg)
+{
+	if (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) {
+		printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
+			smc911x_reg_read(E2P_CMD));
+		return -1;
+	}
+
+	smc911x_reg_write(E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
+
+	while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+		if (smsc_ctrlc()) {
+			printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
+				smc911x_reg_read(E2P_CMD));
+			return -1;
+		}
+
+	return 0;
+}
+
+/**
+ *	read_eeprom_reg - read specified register in EEPROM
+ */
+static u8 read_eeprom_reg(u8 reg)
+{
+	int ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_READ, reg);
+	return (ret ? : smc911x_reg_read(E2P_DATA));
+}
+
+/**
+ *	write_eeprom_reg - write specified value into specified register in EEPROM
+ */
+static int write_eeprom_reg(u8 value, u8 reg)
+{
+	int ret;
+
+	/* enable erasing/writing */
+	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWEN, reg);
+	if (ret)
+		goto done;
+
+	/* erase the eeprom reg */
+	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_ERASE, reg);
+	if (ret)
+		goto done;
+
+	/* write the eeprom reg */
+	smc911x_reg_write(E2P_DATA, value);
+	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_WRITE, reg);
+	if (ret)
+		goto done;
+
+	/* disable erasing/writing */
+	ret = do_eeprom_cmd(E2P_CMD_EPC_CMD_EWDS, reg);
+
+ done:
+	return ret;
+}
+
+/**
+ *	skip_space - find first non-whitespace in given pointer
+ */
+static char *skip_space(char *buf)
+{
+	while (buf[0] == ' ' || buf[0] == '\t')
+		++buf;
+	return buf;
+}
+
+/**
+ *	write_stuff - handle writing of MAC registers / eeprom
+ */
+static void write_stuff(char *line)
+{
+	char dest;
+	char *endp;
+	u8 reg;
+	u32 value;
+
+	/* Skip over the "W " part of the command */
+	line = skip_space(line + 1);
+
+	/* Figure out destination */
+	switch (line[0]) {
+	case 'E':
+	case 'M':
+		dest = line[0];
+		break;
+	default:
+	invalid_usage:
+		printf("ERROR: Invalid write usage\n");
+		usage();
+		return;
+	}
+
+	/* Get the register to write */
+	line = skip_space(line + 1);
+	reg = simple_strtoul(line, &endp, 16);
+	if (line == endp)
+		goto invalid_usage;
+
+	/* Get the value to write */
+	line = skip_space(endp);
+	value = simple_strtoul(line, &endp, 16);
+	if (line == endp)
+		goto invalid_usage;
+
+	/* Check for trailing cruft */
+	line = skip_space(endp);
+	if (line[0])
+		goto invalid_usage;
+
+	/* Finally, execute the command */
+	if (dest == 'E') {
+		printf("Writing EEPROM register %02x with %02x\n", reg, value);
+		write_eeprom_reg(value, reg);
+	} else {
+		printf("Writing MAC register %02x with %08x\n", reg, value);
+		smc911x_reg_write(CONFIG_DRIVER_SMC911X_BASE + reg, value);
+	}
+}
+
+/**
+ *	copy_from_eeprom - copy MAC address in eeprom to address registers
+ */
+static void copy_from_eeprom(void)
+{
+	ulong addrl =
+		read_eeprom_reg(0x01) |
+		read_eeprom_reg(0x02) << 8 |
+		read_eeprom_reg(0x03) << 16 |
+		read_eeprom_reg(0x04) << 24;
+	ulong addrh =
+		read_eeprom_reg(0x05) |
+		read_eeprom_reg(0x06) << 8;
+	smc911x_set_mac_csr(ADDRL, addrl);
+	smc911x_set_mac_csr(ADDRH, addrh);
+	puts("EEPROM contents copied to MAC\n");
+}
+
+/**
+ *	print_macaddr - print MAC address registers and MAC address in eeprom
+ */
+static void print_macaddr(void)
+{
+	puts("Current MAC Address in MAC:     ");
+	ulong addrl = smc911x_get_mac_csr(ADDRL);
+	ulong addrh = smc911x_get_mac_csr(ADDRH);
+	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+		(u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16),
+		(u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8));
+
+	puts("Current MAC Address in EEPROM:  ");
+	int i;
+	for (i = 1; i < 6; ++i)
+		printf("%02x:", read_eeprom_reg(i));
+	printf("%02x\n", read_eeprom_reg(i));
+}
+
+/**
+ *	dump_eeprom - dump the whole content of the EEPROM
+ */
+static void dump_eeprom(void)
+{
+	int i;
+	puts("EEPROM:\n");
+	for (i = 0; i < 7; ++i)
+		printf("%02x: 0x%02x\n", i, read_eeprom_reg(i));
+}
+
+/**
+ *	smc911x_init - get the MAC/EEPROM up and ready for use
+ */
+static int smc911x_init(void)
+{
+	/* See if there is anything there */
+	if (!smc911x_detect_chip())
+		return 1;
+
+	smc911x_reset();
+
+	/* Make sure we set EEDIO/EECLK to the EEPROM */
+	if (smc911x_reg_read(GPIO_CFG) & GPIO_CFG_EEPR_EN) {
+		while (smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
+			if (smsc_ctrlc()) {
+				printf("init: timeout (E2P_CMD = 0x%08x)\n",
+					smc911x_reg_read(E2P_CMD));
+				return 1;
+			}
+		smc911x_reg_write(GPIO_CFG, smc911x_reg_read(GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
+	}
+
+	return 0;
+}
+
+/**
+ *	getline - consume a line of input and handle some escape sequences
+ */
+static char *getline(void)
+{
+	static char buffer[100];
+	char c;
+	size_t i;
+
+	i = 0;
+	while (1) {
+		buffer[i] = '\0';
+		while (!tstc())
+			continue;
+
+		c = getc();
+		/* Convert to uppercase */
+		if (c >= 'a' && c <= 'z')
+			c -= ('a' - 'A');
+
+		switch (c) {
+		case '\r':	/* Enter/Return key */
+		case '\n':
+			puts("\n");
+			return buffer;
+
+		case 0x03:	/* ^C - break */
+			return NULL;
+
+		case 0x5F:
+		case 0x08:	/* ^H  - backspace */
+		case 0x7F:	/* DEL - backspace */
+			if (i) {
+				puts("\b \b");
+				i--;
+			}
+			break;
+
+		default:
+			/* Ignore control characters */
+			if (c < 0x20)
+				break;
+			/* Queue up all other characters */
+			buffer[i++] = c;
+			printf("%c", c);
+			break;
+		}
+	}
+}
+
+/**
+ *	smc911x_eeprom - our application's main() function
+ */
+int smc911x_eeprom(int argc, char *argv[])
+{
+	/* Print the ABI version */
+	app_startup(argv);
+	if (XF_VERSION != get_version()) {
+		printf("Expects ABI version %d\n", XF_VERSION);
+		printf("Actual U-Boot ABI version %lu\n", get_version());
+		printf("Can't run\n\n");
+		return 1;
+	}
+
+	/* Initialize the MAC/EEPROM somewhat */
+	puts("\n");
+	if (smc911x_init())
+		return 1;
+
+	/* Dump helpful usage information */
+	puts("\n");
+	usage();
+	puts("\n");
+
+	while (1) {
+		char *line;
+
+		/* Send the prompt and wait for a line */
+		puts("eeprom> ");
+		line = getline();
+
+		/* Got a ctrl+c */
+		if (!line)
+			return 0;
+
+		/* Eat leading space */
+		line = skip_space(line);
+
+		/* Empty line, try again */
+		if (!line[0])
+			continue;
+
+		/* Only accept 1 letter commands */
+		if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
+			goto unknown_cmd;
+
+		/* Now parse the command */
+		switch (line[0]) {
+		case 'W': write_stuff(line);  break;
+		case 'D': dump_eeprom();      break;
+		case 'M': dump_regs();        break;
+		case 'C': copy_from_eeprom(); break;
+		case 'P': print_macaddr();    break;
+		unknown_cmd:
+		default:  puts("ERROR: Unknown command!\n\n");
+		case '?':
+		case 'H': usage();            break;
+		case 'Q': return 0;
+		}
+	}
+}
+
+#else
+int smc911x_eeprom(int argc, char *argv[])
+{
+	puts("Not supported for this board\n");
+	return 1;
+}
+#endif
diff --git a/examples/sparc.lds b/examples/sparc.lds
index 7592544..9733daa 100644
--- a/examples/sparc.lds
+++ b/examples/sparc.lds
@@ -37,7 +37,7 @@
 	. = ALIGN(4);
 	.rodata :
 	{
-		*(.rodata)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 	__rodata_end = .;
 
diff --git a/fs/Makefile b/fs/Makefile
index 8bbd563..22aad12 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -29,6 +29,7 @@
 subdirs-$(CONFIG_CMD_JFFS2) += jffs2
 subdirs-$(CONFIG_CMD_REISER) += reiserfs
 subdirs-$(CONFIG_YAFFS2) += yaffs2
+subdirs-$(CONFIG_CMD_UBIFS) += ubifs
 
 SUBDIRS	:= $(subdirs-y)
 
diff --git a/board/keymile/mgsuvd/Makefile b/fs/ubifs/Makefile
similarity index 66%
copy from board/keymile/mgsuvd/Makefile
copy to fs/ubifs/Makefile
index 2c5732d..8328843 100644
--- a/board/keymile/mgsuvd/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,6 +1,10 @@
 #
-# (C) Copyright 2007
-# Heiko Schocher, DENX Software Engineering, hs@denx.de.
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2003
+# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
+#
 #
 # See file CREDITS for list of people who contributed to this
 # project.
@@ -22,18 +26,18 @@
 #
 
 include $(TOPDIR)/config.mk
-ifneq ($(OBJTREE),$(SRCTREE))
-$(shell mkdir -p $(obj)../common)
-endif
 
-LIB	= $(obj)lib$(BOARD).a
+LIB	= $(obj)libubifs.a
 
-COBJS	= $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
-		mgsuvd_hdlc_enet.o
+COBJS-$(CONFIG_CMD_UBIFS) := ubifs.o io.o super.o sb.o master.o lpt.o
+COBJS-$(CONFIG_CMD_UBIFS) += lpt_commit.o scan.o lprops.o
+COBJS-$(CONFIG_CMD_UBIFS) += tnc.o tnc_misc.o debug.o crc16.o budget.o
+COBJS-$(CONFIG_CMD_UBIFS) += log.o orphan.o recovery.o replay.o
 
-SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
-OBJS	:= $(addprefix $(obj),$(COBJS))
-SOBJS	:= $(addprefix $(obj),$(SOBJS))
+SRCS	:= $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(AOBJS) $(COBJS-y))
+
+all:	$(LIB) $(AOBJS)
 
 $(LIB):	$(obj).depend $(OBJS)
 	$(AR) $(ARFLAGS) $@ $(OBJS)
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
new file mode 100644
index 0000000..85377ea
--- /dev/null
+++ b/fs/ubifs/budget.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements the budgeting sub-system which is responsible for UBIFS
+ * space management.
+ *
+ * Factors such as compression, wasted space at the ends of LEBs, space in other
+ * journal heads, the effect of updates on the index, and so on, make it
+ * impossible to accurately predict the amount of space needed. Consequently
+ * approximations are used.
+ */
+
+#include "ubifs.h"
+#include <linux/math64.h>
+
+/**
+ * ubifs_calc_min_idx_lebs - calculate amount of eraseblocks for the index.
+ * @c: UBIFS file-system description object
+ *
+ * This function calculates and returns the number of eraseblocks which should
+ * be kept for index usage.
+ */
+int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
+{
+	int idx_lebs, eff_leb_size = c->leb_size - c->max_idx_node_sz;
+	long long idx_size;
+
+	idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
+
+	/* And make sure we have thrice the index size of space reserved */
+	idx_size = idx_size + (idx_size << 1);
+
+	/*
+	 * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes'
+	 * pair, nor similarly the two variables for the new index size, so we
+	 * have to do this costly 64-bit division on fast-path.
+	 */
+	idx_size += eff_leb_size - 1;
+	idx_lebs = div_u64(idx_size, eff_leb_size);
+	/*
+	 * The index head is not available for the in-the-gaps method, so add an
+	 * extra LEB to compensate.
+	 */
+	idx_lebs += 1;
+	if (idx_lebs < MIN_INDEX_LEBS)
+		idx_lebs = MIN_INDEX_LEBS;
+	return idx_lebs;
+}
+
+/**
+ * ubifs_reported_space - calculate reported free space.
+ * @c: the UBIFS file-system description object
+ * @free: amount of free space
+ *
+ * This function calculates amount of free space which will be reported to
+ * user-space. User-space application tend to expect that if the file-system
+ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
+ * are able to write a file of size N. UBIFS attaches node headers to each data
+ * node and it has to write indexing nodes as well. This introduces additional
+ * overhead, and UBIFS has to report slightly less free space to meet the above
+ * expectations.
+ *
+ * This function assumes free space is made up of uncompressed data nodes and
+ * full index nodes (one per data node, tripled because we always allow enough
+ * space to write the index thrice).
+ *
+ * Note, the calculation is pessimistic, which means that most of the time
+ * UBIFS reports less space than it actually has.
+ */
+long long ubifs_reported_space(const struct ubifs_info *c, long long free)
+{
+	int divisor, factor, f;
+
+	/*
+	 * Reported space size is @free * X, where X is UBIFS block size
+	 * divided by UBIFS block size + all overhead one data block
+	 * introduces. The overhead is the node header + indexing overhead.
+	 *
+	 * Indexing overhead calculations are based on the following formula:
+	 * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number
+	 * of data nodes, f - fanout. Because effective UBIFS fanout is twice
+	 * as less than maximum fanout, we assume that each data node
+	 * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
+	 * Note, the multiplier 3 is because UBIFS reserves thrice as more space
+	 * for the index.
+	 */
+	f = c->fanout > 3 ? c->fanout >> 1 : 2;
+	factor = UBIFS_BLOCK_SIZE;
+	divisor = UBIFS_MAX_DATA_NODE_SZ;
+	divisor += (c->max_idx_node_sz * 3) / (f - 1);
+	free *= factor;
+	return div_u64(free, divisor);
+}
diff --git a/fs/ubifs/crc16.c b/fs/ubifs/crc16.c
new file mode 100644
index 0000000..443ccf8
--- /dev/null
+++ b/fs/ubifs/crc16.c
@@ -0,0 +1,60 @@
+/*
+ *      crc16.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include "crc16.h"
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+u16 const crc16_table[256] = {
+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+/**
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc:	previous CRC value
+ * @buffer:	data pointer
+ * @len:	number of bytes in the buffer
+ *
+ * Returns the updated CRC value.
+ */
+u16 crc16(u16 crc, u8 const *buffer, size_t len)
+{
+	while (len--)
+		crc = crc16_byte(crc, *buffer++);
+	return crc;
+}
diff --git a/fs/ubifs/crc16.h b/fs/ubifs/crc16.h
new file mode 100644
index 0000000..9443c08
--- /dev/null
+++ b/fs/ubifs/crc16.h
@@ -0,0 +1,30 @@
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <linux/types.h>
+
+extern u16 const crc16_table[256];
+
+extern u16 crc16(u16 crc, const u8 *buffer, size_t len);
+
+static inline u16 crc16_byte(u16 crc, const u8 data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
+
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
new file mode 100644
index 0000000..6afb883
--- /dev/null
+++ b/fs/ubifs/debug.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file implements most of the debugging stuff which is compiled in only
+ * when it is enabled. But some debugging check functions are implemented in
+ * corresponding subsystem, just because they are closely related and utilize
+ * various local functions of those subsystems.
+ */
+
+#define UBIFS_DBG_PRESERVE_UBI
+
+#include "ubifs.h"
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+
+DEFINE_SPINLOCK(dbg_lock);
+
+static char dbg_key_buf0[128];
+static char dbg_key_buf1[128];
+
+unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
+unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+unsigned int ubifs_tst_flags;
+
+module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+MODULE_PARM_DESC(debug_chks, "Debug check flags");
+MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
+
+static const char *get_key_type(int type)
+{
+	switch (type) {
+	case UBIFS_INO_KEY:
+		return "inode";
+	case UBIFS_DENT_KEY:
+		return "direntry";
+	case UBIFS_XENT_KEY:
+		return "xentry";
+	case UBIFS_DATA_KEY:
+		return "data";
+	case UBIFS_TRUN_KEY:
+		return "truncate";
+	default:
+		return "unknown/invalid key";
+	}
+}
+
+static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+			char *buffer)
+{
+	char *p = buffer;
+	int type = key_type(c, key);
+
+	if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+		switch (type) {
+		case UBIFS_INO_KEY:
+			sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
+			       get_key_type(type));
+			break;
+		case UBIFS_DENT_KEY:
+		case UBIFS_XENT_KEY:
+			sprintf(p, "(%lu, %s, %#08x)",
+				(unsigned long)key_inum(c, key),
+				get_key_type(type), key_hash(c, key));
+			break;
+		case UBIFS_DATA_KEY:
+			sprintf(p, "(%lu, %s, %u)",
+				(unsigned long)key_inum(c, key),
+				get_key_type(type), key_block(c, key));
+			break;
+		case UBIFS_TRUN_KEY:
+			sprintf(p, "(%lu, %s)",
+				(unsigned long)key_inum(c, key),
+				get_key_type(type));
+			break;
+		default:
+			sprintf(p, "(bad key type: %#08x, %#08x)",
+				key->u32[0], key->u32[1]);
+		}
+	} else
+		sprintf(p, "bad key format %d", c->key_fmt);
+}
+
+const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
+{
+	/* dbg_lock must be held */
+	sprintf_key(c, key, dbg_key_buf0);
+	return dbg_key_buf0;
+}
+
+const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
+{
+	/* dbg_lock must be held */
+	sprintf_key(c, key, dbg_key_buf1);
+	return dbg_key_buf1;
+}
+
+/**
+ * ubifs_debugging_init - initialize UBIFS debugging.
+ * @c: UBIFS file-system description object
+ *
+ * This function initializes debugging-related data for the file system.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int ubifs_debugging_init(struct ubifs_info *c)
+{
+	c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+	if (!c->dbg)
+		return -ENOMEM;
+
+	c->dbg->buf = vmalloc(c->leb_size);
+	if (!c->dbg->buf)
+		goto out;
+
+	return 0;
+
+out:
+	kfree(c->dbg);
+	return -ENOMEM;
+}
+
+/**
+ * ubifs_debugging_exit - free debugging data.
+ * @c: UBIFS file-system description object
+ */
+void ubifs_debugging_exit(struct ubifs_info *c)
+{
+	vfree(c->dbg->buf);
+	kfree(c->dbg);
+}
+
+#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
new file mode 100644
index 0000000..62617b6
--- /dev/null
+++ b/fs/ubifs/debug.h
@@ -0,0 +1,392 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+#ifndef __UBIFS_DEBUG_H__
+#define __UBIFS_DEBUG_H__
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+
+/**
+ * ubifs_debug_info - per-FS debugging information.
+ * @buf: a buffer of LEB size, used for various purposes
+ * @old_zroot: old index root - used by 'dbg_check_old_index()'
+ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+ * @failure_mode: failure mode for recovery testing
+ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+ * @fail_timeout: time in jiffies when delay of failure mode expires
+ * @fail_cnt: current number of calls to failure mode I/O functions
+ * @fail_cnt_max: number of calls by which to delay failure mode
+ * @chk_lpt_sz: used by LPT tree size checker
+ * @chk_lpt_sz2: used by LPT tree size checker
+ * @chk_lpt_wastage: used by LPT tree size checker
+ * @chk_lpt_lebs: used by LPT tree size checker
+ * @new_nhead_offs: used by LPT tree size checker
+ * @new_ihead_lnum: used by debugging to check @c->ihead_lnum
+ * @new_ihead_offs: used by debugging to check @c->ihead_offs
+ *
+ * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
+ * @saved_free: saved free space (used by 'dbg_save_space_info()')
+ *
+ * dfs_dir_name: name of debugfs directory containing this file-system's files
+ * dfs_dir: direntry object of the file-system debugfs directory
+ * dfs_dump_lprops: "dump lprops" debugfs knob
+ * dfs_dump_budg: "dump budgeting information" debugfs knob
+ * dfs_dump_tnc: "dump TNC" debugfs knob
+ */
+struct ubifs_debug_info {
+	void *buf;
+	struct ubifs_zbranch old_zroot;
+	int old_zroot_level;
+	unsigned long long old_zroot_sqnum;
+	int failure_mode;
+	int fail_delay;
+	unsigned long fail_timeout;
+	unsigned int fail_cnt;
+	unsigned int fail_cnt_max;
+	long long chk_lpt_sz;
+	long long chk_lpt_sz2;
+	long long chk_lpt_wastage;
+	int chk_lpt_lebs;
+	int new_nhead_offs;
+	int new_ihead_lnum;
+	int new_ihead_offs;
+
+	struct ubifs_lp_stats saved_lst;
+	long long saved_free;
+
+	char dfs_dir_name[100];
+	struct dentry *dfs_dir;
+	struct dentry *dfs_dump_lprops;
+	struct dentry *dfs_dump_budg;
+	struct dentry *dfs_dump_tnc;
+};
+
+#define UBIFS_DBG(op) op
+
+#define ubifs_assert(expr) do {                                                \
+	if (unlikely(!(expr))) {                                               \
+		printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+		       __func__, __LINE__, 0);                      \
+		dbg_dump_stack();                                              \
+	}                                                                      \
+} while (0)
+
+#define ubifs_assert_cmt_locked(c) do {                                        \
+	if (unlikely(down_write_trylock(&(c)->commit_sem))) {                  \
+		up_write(&(c)->commit_sem);                                    \
+		printk(KERN_CRIT "commit lock is not locked!\n");              \
+		ubifs_assert(0);                                               \
+	}                                                                      \
+} while (0)
+
+#define dbg_dump_stack() do {                                                  \
+	if (!dbg_failure_mode)                                                 \
+		dump_stack();                                                  \
+} while (0)
+
+/* Generic debugging messages */
+#define dbg_msg(fmt, ...) do {                                                 \
+	spin_lock(&dbg_lock);                                                  \
+	printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", 0,   \
+	       __func__, ##__VA_ARGS__);                                       \
+	spin_unlock(&dbg_lock);                                                \
+} while (0)
+
+#define dbg_do_msg(typ, fmt, ...) do {                                         \
+	if (ubifs_msg_flags & typ)                                             \
+		dbg_msg(fmt, ##__VA_ARGS__);                                   \
+} while (0)
+
+#define dbg_err(fmt, ...) do {                                                 \
+	spin_lock(&dbg_lock);                                                  \
+	ubifs_err(fmt, ##__VA_ARGS__);                                         \
+	spin_unlock(&dbg_lock);                                                \
+} while (0)
+
+const char *dbg_key_str0(const struct ubifs_info *c,
+			 const union ubifs_key *key);
+const char *dbg_key_str1(const struct ubifs_info *c,
+			 const union ubifs_key *key);
+
+/*
+ * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
+ * macros.
+ */
+#define DBGKEY(key)	dbg_key_str0(c, (key))
+#define DBGKEY1(key)	dbg_key_str1(c, (key))
+
+/* General messages */
+#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
+
+/* Additional journal messages */
+#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+
+/* Additional TNC messages */
+#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+
+/* Additional lprops messages */
+#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+
+/* Additional LEB find messages */
+#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+
+/* Additional mount messages */
+#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+
+/* Additional I/O messages */
+#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+
+/* Additional commit messages */
+#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+
+/* Additional budgeting messages */
+#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+
+/* Additional log messages */
+#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+
+/* Additional gc messages */
+#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+
+/* Additional scan messages */
+#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+
+/* Additional recovery messages */
+#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
+
+/*
+ * Debugging message type flags (must match msg_type_names in debug.c).
+ *
+ * UBIFS_MSG_GEN: general messages
+ * UBIFS_MSG_JNL: journal messages
+ * UBIFS_MSG_MNT: mount messages
+ * UBIFS_MSG_CMT: commit messages
+ * UBIFS_MSG_FIND: LEB find messages
+ * UBIFS_MSG_BUDG: budgeting messages
+ * UBIFS_MSG_GC: garbage collection messages
+ * UBIFS_MSG_TNC: TNC messages
+ * UBIFS_MSG_LP: lprops messages
+ * UBIFS_MSG_IO: I/O messages
+ * UBIFS_MSG_LOG: log messages
+ * UBIFS_MSG_SCAN: scan messages
+ * UBIFS_MSG_RCVRY: recovery messages
+ */
+enum {
+	UBIFS_MSG_GEN   = 0x1,
+	UBIFS_MSG_JNL   = 0x2,
+	UBIFS_MSG_MNT   = 0x4,
+	UBIFS_MSG_CMT   = 0x8,
+	UBIFS_MSG_FIND  = 0x10,
+	UBIFS_MSG_BUDG  = 0x20,
+	UBIFS_MSG_GC    = 0x40,
+	UBIFS_MSG_TNC   = 0x80,
+	UBIFS_MSG_LP    = 0x100,
+	UBIFS_MSG_IO    = 0x200,
+	UBIFS_MSG_LOG   = 0x400,
+	UBIFS_MSG_SCAN  = 0x800,
+	UBIFS_MSG_RCVRY = 0x1000,
+};
+
+/* Debugging message type flags for each default debug message level */
+#define UBIFS_MSG_LVL_0 0
+#define UBIFS_MSG_LVL_1 0x1
+#define UBIFS_MSG_LVL_2 0x7f
+#define UBIFS_MSG_LVL_3 0xffff
+
+/*
+ * Debugging check flags (must match chk_names in debug.c).
+ *
+ * UBIFS_CHK_GEN: general checks
+ * UBIFS_CHK_TNC: check TNC
+ * UBIFS_CHK_IDX_SZ: check index size
+ * UBIFS_CHK_ORPH: check orphans
+ * UBIFS_CHK_OLD_IDX: check the old index
+ * UBIFS_CHK_LPROPS: check lprops
+ * UBIFS_CHK_FS: check the file-system
+ */
+enum {
+	UBIFS_CHK_GEN     = 0x1,
+	UBIFS_CHK_TNC     = 0x2,
+	UBIFS_CHK_IDX_SZ  = 0x4,
+	UBIFS_CHK_ORPH    = 0x8,
+	UBIFS_CHK_OLD_IDX = 0x10,
+	UBIFS_CHK_LPROPS  = 0x20,
+	UBIFS_CHK_FS      = 0x40,
+};
+
+/*
+ * Special testing flags (must match tst_names in debug.c).
+ *
+ * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
+ * UBIFS_TST_RCVRY: failure mode for recovery testing
+ */
+enum {
+	UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
+	UBIFS_TST_RCVRY             = 0x4,
+};
+
+#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
+#else
+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
+#endif
+
+#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
+#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
+#else
+#define UBIFS_CHK_FLAGS_DEFAULT 0
+#endif
+
+#define dbg_ntype(type)                       ""
+#define dbg_cstate(cmt_state)                 ""
+#define dbg_get_key_dump(c, key)              ({})
+#define dbg_dump_inode(c, inode)              ({})
+#define dbg_dump_node(c, node)                ({})
+#define dbg_dump_budget_req(req)              ({})
+#define dbg_dump_lstats(lst)                  ({})
+#define dbg_dump_budg(c)                      ({})
+#define dbg_dump_lprop(c, lp)                 ({})
+#define dbg_dump_lprops(c)                    ({})
+#define dbg_dump_lpt_info(c)                  ({})
+#define dbg_dump_leb(c, lnum)                 ({})
+#define dbg_dump_znode(c, znode)              ({})
+#define dbg_dump_heap(c, heap, cat)           ({})
+#define dbg_dump_pnode(c, pnode, parent, iip) ({})
+#define dbg_dump_tnc(c)                       ({})
+#define dbg_dump_index(c)                     ({})
+
+#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
+#define dbg_old_index_check_init(c, zroot)         0
+#define dbg_check_old_index(c, zroot)              0
+#define dbg_check_cats(c)                          0
+#define dbg_check_ltab(c)                          0
+#define dbg_chk_lpt_free_spc(c)                    0
+#define dbg_chk_lpt_sz(c, action, len)             0
+#define dbg_check_synced_i_size(inode)             0
+#define dbg_check_dir_size(c, dir)                 0
+#define dbg_check_tnc(c, x)                        0
+#define dbg_check_idx_size(c, idx_size)            0
+#define dbg_check_filesystem(c)                    0
+#define dbg_check_heap(c, heap, cat, add_pos)      ({})
+#define dbg_check_lprops(c)                        0
+#define dbg_check_lpt_nodes(c, cnode, row, col)    0
+#define dbg_force_in_the_gaps_enabled              0
+#define dbg_force_in_the_gaps()                    0
+#define dbg_failure_mode                           0
+#define dbg_failure_mode_registration(c)           ({})
+#define dbg_failure_mode_deregistration(c)         ({})
+
+int ubifs_debugging_init(struct ubifs_info *c);
+void ubifs_debugging_exit(struct ubifs_info *c);
+
+#else /* !CONFIG_UBIFS_FS_DEBUG */
+
+#define UBIFS_DBG(op)
+
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubifs_assert(expr)  do {                                               \
+	if (0 && (expr))                                                       \
+		printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+		       __func__, __LINE__, 0);                      \
+} while (0)
+
+#define dbg_err(fmt, ...)   do {                                               \
+	if (0)                                                                 \
+		ubifs_err(fmt, ##__VA_ARGS__);                                 \
+} while (0)
+
+#define dbg_msg(fmt, ...) do {                                                 \
+	if (0)                                                                 \
+		printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
+		       0, __func__, ##__VA_ARGS__);                 \
+} while (0)
+
+#define dbg_dump_stack()
+#define ubifs_assert_cmt_locked(c)
+
+#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+
+#define DBGKEY(key)  ((char *)(key))
+#define DBGKEY1(key) ((char *)(key))
+
+#define ubifs_debugging_init(c)                0
+#define ubifs_debugging_exit(c)                ({})
+
+#define dbg_ntype(type)                       ""
+#define dbg_cstate(cmt_state)                 ""
+#define dbg_get_key_dump(c, key)              ({})
+#define dbg_dump_inode(c, inode)              ({})
+#define dbg_dump_node(c, node)                ({})
+#define dbg_dump_budget_req(req)              ({})
+#define dbg_dump_lstats(lst)                  ({})
+#define dbg_dump_budg(c)                      ({})
+#define dbg_dump_lprop(c, lp)                 ({})
+#define dbg_dump_lprops(c)                    ({})
+#define dbg_dump_lpt_info(c)                  ({})
+#define dbg_dump_leb(c, lnum)                 ({})
+#define dbg_dump_znode(c, znode)              ({})
+#define dbg_dump_heap(c, heap, cat)           ({})
+#define dbg_dump_pnode(c, pnode, parent, iip) ({})
+#define dbg_dump_tnc(c)                       ({})
+#define dbg_dump_index(c)                     ({})
+
+#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
+#define dbg_old_index_check_init(c, zroot)         0
+#define dbg_check_old_index(c, zroot)              0
+#define dbg_check_cats(c)                          0
+#define dbg_check_ltab(c)                          0
+#define dbg_chk_lpt_free_spc(c)                    0
+#define dbg_chk_lpt_sz(c, action, len)             0
+#define dbg_check_synced_i_size(inode)             0
+#define dbg_check_dir_size(c, dir)                 0
+#define dbg_check_tnc(c, x)                        0
+#define dbg_check_idx_size(c, idx_size)            0
+#define dbg_check_filesystem(c)                    0
+#define dbg_check_heap(c, heap, cat, add_pos)      ({})
+#define dbg_check_lprops(c)                        0
+#define dbg_check_lpt_nodes(c, cnode, row, col)    0
+#define dbg_force_in_the_gaps_enabled              0
+#define dbg_force_in_the_gaps()                    0
+#define dbg_failure_mode                           0
+#define dbg_failure_mode_registration(c)           ({})
+#define dbg_failure_mode_deregistration(c)         ({})
+
+#endif /* !CONFIG_UBIFS_FS_DEBUG */
+
+#endif /* !__UBIFS_DEBUG_H__ */
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
new file mode 100644
index 0000000..aae5c65
--- /dev/null
+++ b/fs/ubifs/io.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ * Copyright (C) 2006, 2007 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+/*
+ * This file implements UBIFS I/O subsystem which provides various I/O-related
+ * helper functions (reading/writing/checking/validating nodes) and implements
+ * write-buffering support. Write buffers help to save space which otherwise
+ * would have been wasted for padding to the nearest minimal I/O unit boundary.
+ * Instead, data first goes to the write-buffer and is flushed when the
+ * buffer is full or when it is not used for some time (by timer). This is
+ * similar to the mechanism is used by JFFS2.
+ *
+ * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
+ * mutexes defined inside these objects. Since sometimes upper-level code
+ * has to lock the write-buffer (e.g. journal space reservation code), many
+ * functions related to write-buffers have "nolock" suffix which means that the
+ * caller has to lock the write-buffer before calling this function.
+ *
+ * UBIFS stores nodes at 64 bit-aligned addresses. If the node length is not
+ * aligned, UBIFS starts the next node from the aligned address, and the padded
+ * bytes may contain any rubbish. In other words, UBIFS does not put padding
+ * bytes in those small gaps. Common headers of nodes store real node lengths,
+ * not aligned lengths. Indexing nodes also store real lengths in branches.
+ *
+ * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
+ * uses padding nodes or padding bytes, if the padding node does not fit.
+ *
+ * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
+ * every time they are read from the flash media.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_ro_mode - switch UBIFS to read read-only mode.
+ * @c: UBIFS file-system description object
+ * @err: error code which is the reason of switching to R/O mode
+ */
+void ubifs_ro_mode(struct ubifs_info *c, int err)
+{
+	if (!c->ro_media) {
+		c->ro_media = 1;
+		c->no_chk_data_crc = 0;
+		ubifs_warn("switched to read-only mode, error %d", err);
+		dbg_dump_stack();
+	}
+}
+
+/**
+ * ubifs_check_node - check node.
+ * @c: UBIFS file-system description object
+ * @buf: node to check
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ * @quiet: print no messages
+ * @must_chk_crc: indicates whether to always check the CRC
+ *
+ * This function checks node magic number and CRC checksum. This function also
+ * validates node length to prevent UBIFS from becoming crazy when an attacker
+ * feeds it a file-system image with incorrect nodes. For example, too large
+ * node length in the common header could cause UBIFS to read memory outside of
+ * allocated buffer when checking the CRC checksum.
+ *
+ * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
+ * true, which is controlled by corresponding UBIFS mount option. However, if
+ * @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
+ * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
+ * ignored and CRC is checked.
+ *
+ * This function returns zero in case of success and %-EUCLEAN in case of bad
+ * CRC or magic.
+ */
+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+		     int offs, int quiet, int must_chk_crc)
+{
+	int err = -EINVAL, type, node_len;
+	uint32_t crc, node_crc, magic;
+	const struct ubifs_ch *ch = buf;
+
+	ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+	ubifs_assert(!(offs & 7) && offs < c->leb_size);
+
+	magic = le32_to_cpu(ch->magic);
+	if (magic != UBIFS_NODE_MAGIC) {
+		if (!quiet)
+			ubifs_err("bad magic %#08x, expected %#08x",
+				  magic, UBIFS_NODE_MAGIC);
+		err = -EUCLEAN;
+		goto out;
+	}
+
+	type = ch->node_type;
+	if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {
+		if (!quiet)
+			ubifs_err("bad node type %d", type);
+		goto out;
+	}
+
+	node_len = le32_to_cpu(ch->len);
+	if (node_len + offs > c->leb_size)
+		goto out_len;
+
+	if (c->ranges[type].max_len == 0) {
+		if (node_len != c->ranges[type].len)
+			goto out_len;
+	} else if (node_len < c->ranges[type].min_len ||
+		   node_len > c->ranges[type].max_len)
+		goto out_len;
+
+	if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
+	     c->no_chk_data_crc)
+		return 0;
+
+	crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+	node_crc = le32_to_cpu(ch->crc);
+	if (crc != node_crc) {
+		if (!quiet)
+			ubifs_err("bad CRC: calculated %#08x, read %#08x",
+				  crc, node_crc);
+		err = -EUCLEAN;
+		goto out;
+	}
+
+	return 0;
+
+out_len:
+	if (!quiet)
+		ubifs_err("bad node length %d", node_len);
+out:
+	if (!quiet) {
+		ubifs_err("bad node at LEB %d:%d", lnum, offs);
+		dbg_dump_node(c, buf);
+		dbg_dump_stack();
+	}
+	return err;
+}
+
+/**
+ * ubifs_pad - pad flash space.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to put padding to
+ * @pad: how many bytes to pad
+ *
+ * The flash media obliges us to write only in chunks of %c->min_io_size and
+ * when we have to write less data we add padding node to the write-buffer and
+ * pad it to the next minimal I/O unit's boundary. Padding nodes help when the
+ * media is being scanned. If the amount of wasted space is not enough to fit a
+ * padding node which takes %UBIFS_PAD_NODE_SZ bytes, we write padding bytes
+ * pattern (%UBIFS_PADDING_BYTE).
+ *
+ * Padding nodes are also used to fill gaps when the "commit-in-gaps" method is
+ * used.
+ */
+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
+{
+	uint32_t crc;
+
+	ubifs_assert(pad >= 0 && !(pad & 7));
+
+	if (pad >= UBIFS_PAD_NODE_SZ) {
+		struct ubifs_ch *ch = buf;
+		struct ubifs_pad_node *pad_node = buf;
+
+		ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+		ch->node_type = UBIFS_PAD_NODE;
+		ch->group_type = UBIFS_NO_NODE_GROUP;
+		ch->padding[0] = ch->padding[1] = 0;
+		ch->sqnum = 0;
+		ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ);
+		pad -= UBIFS_PAD_NODE_SZ;
+		pad_node->pad_len = cpu_to_le32(pad);
+		crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8);
+		ch->crc = cpu_to_le32(crc);
+		memset(buf + UBIFS_PAD_NODE_SZ, 0, pad);
+	} else if (pad > 0)
+		/* Too little space, padding node won't fit */
+		memset(buf, UBIFS_PADDING_BYTE, pad);
+}
+
+/**
+ * next_sqnum - get next sequence number.
+ * @c: UBIFS file-system description object
+ */
+static unsigned long long next_sqnum(struct ubifs_info *c)
+{
+	unsigned long long sqnum;
+
+	spin_lock(&c->cnt_lock);
+	sqnum = ++c->max_sqnum;
+	spin_unlock(&c->cnt_lock);
+
+	if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) {
+		if (sqnum >= SQNUM_WATERMARK) {
+			ubifs_err("sequence number overflow %llu, end of life",
+				  sqnum);
+			ubifs_ro_mode(c, -EINVAL);
+		}
+		ubifs_warn("running out of sequence numbers, end of life soon");
+	}
+
+	return sqnum;
+}
+
+/**
+ * ubifs_prepare_node - prepare node to be written to flash.
+ * @c: UBIFS file-system description object
+ * @node: the node to pad
+ * @len: node length
+ * @pad: if the buffer has to be padded
+ *
+ * This function prepares node at @node to be written to the media - it
+ * calculates node CRC, fills the common header, and adds proper padding up to
+ * the next minimum I/O unit if @pad is not zero.
+ */
+void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
+{
+	uint32_t crc;
+	struct ubifs_ch *ch = node;
+	unsigned long long sqnum = next_sqnum(c);
+
+	ubifs_assert(len >= UBIFS_CH_SZ);
+
+	ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+	ch->len = cpu_to_le32(len);
+	ch->group_type = UBIFS_NO_NODE_GROUP;
+	ch->sqnum = cpu_to_le64(sqnum);
+	ch->padding[0] = ch->padding[1] = 0;
+	crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+	ch->crc = cpu_to_le32(crc);
+
+	if (pad) {
+		len = ALIGN(len, 8);
+		pad = ALIGN(len, c->min_io_size) - len;
+		ubifs_pad(c, node + len, pad);
+	}
+}
+
+/**
+ * ubifs_read_node - read node.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to read to
+ * @type: node type
+ * @len: node length (not aligned)
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ *
+ * This function reads a node of known type and and length, checks it and
+ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched
+ * and a negative error code in case of failure.
+ */
+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+		    int lnum, int offs)
+{
+	int err, l;
+	struct ubifs_ch *ch = buf;
+
+	dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+	ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+	ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
+	ubifs_assert(!(offs & 7) && offs < c->leb_size);
+	ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+
+	err = ubi_read(c->ubi, lnum, buf, offs, len);
+	if (err && err != -EBADMSG) {
+		ubifs_err("cannot read node %d from LEB %d:%d, error %d",
+			  type, lnum, offs, err);
+		return err;
+	}
+
+	if (type != ch->node_type) {
+		ubifs_err("bad node type (%d but expected %d)",
+			  ch->node_type, type);
+		goto out;
+	}
+
+	err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
+	if (err) {
+		ubifs_err("expected node type %d", type);
+		return err;
+	}
+
+	l = le32_to_cpu(ch->len);
+	if (l != len) {
+		ubifs_err("bad node length %d, expected %d", l, len);
+		goto out;
+	}
+
+	return 0;
+
+out:
+	ubifs_err("bad node at LEB %d:%d", lnum, offs);
+	dbg_dump_node(c, buf);
+	dbg_dump_stack();
+	return -EINVAL;
+}
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
new file mode 100644
index 0000000..efb3430
--- /dev/null
+++ b/fs/ubifs/key.h
@@ -0,0 +1,557 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This header contains various key-related definitions and helper function.
+ * UBIFS allows several key schemes, so we access key fields only via these
+ * helpers. At the moment only one key scheme is supported.
+ *
+ * Simple key scheme
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number
+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are
+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry
+ * node. We use "r5" hash borrowed from reiserfs.
+ */
+
+#ifndef __UBIFS_KEY_H__
+#define __UBIFS_KEY_H__
+
+/**
+ * key_mask_hash - mask a valid hash value.
+ * @val: value to be masked
+ *
+ * We use hash values as offset in directories, so values %0 and %1 are
+ * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
+ * function makes sure the reserved values are not used.
+ */
+static inline uint32_t key_mask_hash(uint32_t hash)
+{
+	hash &= UBIFS_S_KEY_HASH_MASK;
+	if (unlikely(hash <= 2))
+		hash += 3;
+	return hash;
+}
+
+/**
+ * key_r5_hash - R5 hash function (borrowed from reiserfs).
+ * @s: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_r5_hash(const char *s, int len)
+{
+	uint32_t a = 0;
+	const signed char *str = (const signed char *)s;
+
+	while (*str) {
+		a += *str << 4;
+		a += *str >> 4;
+		a *= 11;
+		str++;
+	}
+
+	return key_mask_hash(a);
+}
+
+/**
+ * key_test_hash - testing hash function.
+ * @str: direntry name
+ * @len: name length
+ */
+static inline uint32_t key_test_hash(const char *str, int len)
+{
+	uint32_t a = 0;
+
+	len = min_t(uint32_t, len, 4);
+	memcpy(&a, str, len);
+	return key_mask_hash(a);
+}
+
+/**
+ * ino_key_init - initialize inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init(const struct ubifs_info *c,
+				union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * ino_key_init_flash - initialize on-flash inode key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: inode number
+ */
+static inline void ino_key_init_flash(const struct ubifs_info *c, void *k,
+				      ino_t inum)
+{
+	union ubifs_key *key = k;
+
+	key->j32[0] = cpu_to_le32(inum);
+	key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS);
+	memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_ino_key - get the lowest possible inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void lowest_ino_key(const struct ubifs_info *c,
+				union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = 0;
+}
+
+/**
+ * highest_ino_key - get the highest possible inode key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ */
+static inline void highest_ino_key(const struct ubifs_info *c,
+				union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = 0xffffffff;
+}
+
+/**
+ * dent_key_init - initialize directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum,
+				 const struct qstr *nm)
+{
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * dent_key_init_hash - initialize directory entry key without re-calculating
+ *                      hash function.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: parent inode number
+ * @hash: direntry name hash
+ */
+static inline void dent_key_init_hash(const struct ubifs_info *c,
+				      union ubifs_key *key, ino_t inum,
+				      uint32_t hash)
+{
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * dent_key_init_flash - initialize on-flash directory entry key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: parent inode number
+ * @nm: direntry name and length
+ */
+static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
+				       ino_t inum, const struct qstr *nm)
+{
+	union ubifs_key *key = k;
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->j32[0] = cpu_to_le32(inum);
+	key->j32[1] = cpu_to_le32(hash |
+				  (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS));
+	memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_dent_key - get the lowest possible directory entry key.
+ * @c: UBIFS file-system description object
+ * @key: where to store the lowest key
+ * @inum: parent inode number
+ */
+static inline void lowest_dent_key(const struct ubifs_info *c,
+				   union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS;
+}
+
+/**
+ * xent_key_init - initialize extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: host inode number
+ * @nm: extended attribute entry name and length
+ */
+static inline void xent_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum,
+				 const struct qstr *nm)
+{
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * xent_key_init_hash - initialize extended attribute entry key without
+ *                      re-calculating hash function.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: host inode number
+ * @hash: extended attribute entry name hash
+ */
+static inline void xent_key_init_hash(const struct ubifs_info *c,
+				      union ubifs_key *key, ino_t inum,
+				      uint32_t hash)
+{
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
+ * xent_key_init_flash - initialize on-flash extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: host inode number
+ * @nm: extended attribute entry name and length
+ */
+static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
+				       ino_t inum, const struct qstr *nm)
+{
+	union ubifs_key *key = k;
+	uint32_t hash = c->key_hash(nm->name, nm->len);
+
+	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+	key->j32[0] = cpu_to_le32(inum);
+	key->j32[1] = cpu_to_le32(hash |
+				  (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS));
+	memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * lowest_xent_key - get the lowest possible extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @key: where to store the lowest key
+ * @inum: host inode number
+ */
+static inline void lowest_xent_key(const struct ubifs_info *c,
+				   union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS;
+}
+
+/**
+ * data_key_init - initialize data key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum,
+				 unsigned int block)
+{
+	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+	key->u32[0] = inum;
+	key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
+}
+
+/**
+ * data_key_init_flash - initialize on-flash data key.
+ * @c: UBIFS file-system description object
+ * @k: key to initialize
+ * @inum: inode number
+ * @block: block number
+ */
+static inline void data_key_init_flash(const struct ubifs_info *c, void *k,
+				       ino_t inum, unsigned int block)
+{
+	union ubifs_key *key = k;
+
+	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+	key->j32[0] = cpu_to_le32(inum);
+	key->j32[1] = cpu_to_le32(block |
+				  (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS));
+	memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * trun_key_init - initialize truncation node key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ *
+ * Note, UBIFS does not have truncation keys on the media and this function is
+ * only used for purposes of replay.
+ */
+static inline void trun_key_init(const struct ubifs_info *c,
+				 union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_type - get key type.
+ * @c: UBIFS file-system description object
+ * @key: key to get type of
+ */
+static inline int key_type(const struct ubifs_info *c,
+			   const union ubifs_key *key)
+{
+	return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_type_flash - get type of a on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: key to get type of
+ */
+static inline int key_type_flash(const struct ubifs_info *c, const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return le32_to_cpu(key->j32[1]) >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
+ * key_inum - fetch inode number from key.
+ * @c: UBIFS file-system description object
+ * @k: key to fetch inode number from
+ */
+static inline ino_t key_inum(const struct ubifs_info *c, const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return key->u32[0];
+}
+
+/**
+ * key_inum_flash - fetch inode number from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: key to fetch inode number from
+ */
+static inline ino_t key_inum_flash(const struct ubifs_info *c, const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return le32_to_cpu(key->j32[0]);
+}
+
+/**
+ * key_hash - get directory entry hash.
+ * @c: UBIFS file-system description object
+ * @key: the key to get hash from
+ */
+static inline int key_hash(const struct ubifs_info *c,
+			   const union ubifs_key *key)
+{
+	return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
+}
+
+/**
+ * key_hash_flash - get directory entry hash from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: the key to get hash from
+ */
+static inline int key_hash_flash(const struct ubifs_info *c, const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK;
+}
+
+/**
+ * key_block - get data block number.
+ * @c: UBIFS file-system description object
+ * @key: the key to get the block number from
+ */
+static inline unsigned int key_block(const struct ubifs_info *c,
+				     const union ubifs_key *key)
+{
+	return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
+}
+
+/**
+ * key_block_flash - get data block number from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: the key to get the block number from
+ */
+static inline unsigned int key_block_flash(const struct ubifs_info *c,
+					   const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_BLOCK_MASK;
+}
+
+/**
+ * key_read - transform a key to in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_read(const struct ubifs_info *c, const void *from,
+			    union ubifs_key *to)
+{
+	const union ubifs_key *f = from;
+
+	to->u32[0] = le32_to_cpu(f->j32[0]);
+	to->u32[1] = le32_to_cpu(f->j32[1]);
+}
+
+/**
+ * key_write - transform a key from in-memory format.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write(const struct ubifs_info *c,
+			     const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+	memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
+}
+
+/**
+ * key_write_idx - transform a key from in-memory format for the index.
+ * @c: UBIFS file-system description object
+ * @from: the key to transform
+ * @to: the key to store the result
+ */
+static inline void key_write_idx(const struct ubifs_info *c,
+				 const union ubifs_key *from, void *to)
+{
+	union ubifs_key *t = to;
+
+	t->j32[0] = cpu_to_le32(from->u32[0]);
+	t->j32[1] = cpu_to_le32(from->u32[1]);
+}
+
+/**
+ * key_copy - copy a key.
+ * @c: UBIFS file-system description object
+ * @from: the key to copy from
+ * @to: the key to copy to
+ */
+static inline void key_copy(const struct ubifs_info *c,
+			    const union ubifs_key *from, union ubifs_key *to)
+{
+	to->u64[0] = from->u64[0];
+}
+
+/**
+ * keys_cmp - compare keys.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %-1 if @key1 is less than
+ * @key2, %0 if the keys are equivalent and %1 if @key1 is greater than @key2.
+ */
+static inline int keys_cmp(const struct ubifs_info *c,
+			   const union ubifs_key *key1,
+			   const union ubifs_key *key2)
+{
+	if (key1->u32[0] < key2->u32[0])
+		return -1;
+	if (key1->u32[0] > key2->u32[0])
+		return 1;
+	if (key1->u32[1] < key2->u32[1])
+		return -1;
+	if (key1->u32[1] > key2->u32[1])
+		return 1;
+
+	return 0;
+}
+
+/**
+ * keys_eq - determine if keys are equivalent.
+ * @c: UBIFS file-system description object
+ * @key1: the first key to compare
+ * @key2: the second key to compare
+ *
+ * This function compares 2 keys and returns %1 if @key1 is equal to @key2 and
+ * %0 if not.
+ */
+static inline int keys_eq(const struct ubifs_info *c,
+			  const union ubifs_key *key1,
+			  const union ubifs_key *key2)
+{
+	if (key1->u32[0] != key2->u32[0])
+		return 0;
+	if (key1->u32[1] != key2->u32[1])
+		return 0;
+	return 1;
+}
+
+/**
+ * is_hash_key - is a key vulnerable to hash collisions.
+ * @c: UBIFS file-system description object
+ * @key: key
+ *
+ * This function returns %1 if @key is a hashed key or %0 otherwise.
+ */
+static inline int is_hash_key(const struct ubifs_info *c,
+			      const union ubifs_key *key)
+{
+	int type = key_type(c, key);
+
+	return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY;
+}
+
+/**
+ * key_max_inode_size - get maximum file size allowed by current key format.
+ * @c: UBIFS file-system description object
+ */
+static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
+{
+	switch (c->key_fmt) {
+	case UBIFS_SIMPLE_KEY_FMT:
+		return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE;
+	default:
+		return 0;
+	}
+}
+#endif /* !__UBIFS_KEY_H__ */
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
new file mode 100644
index 0000000..68a9bd9
--- /dev/null
+++ b/fs/ubifs/log.c
@@ -0,0 +1,104 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file is a part of UBIFS journal implementation and contains various
+ * functions which manipulate the log. The log is a fixed area on the flash
+ * which does not contain any data but refers to buds. The log is a part of the
+ * journal.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_search_bud - search bud LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number to search
+ *
+ * This function searches bud LEB @lnum. Returns bud description object in case
+ * of success and %NULL if there is no bud with this LEB number.
+ */
+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
+{
+	struct rb_node *p;
+	struct ubifs_bud *bud;
+
+	spin_lock(&c->buds_lock);
+	p = c->buds.rb_node;
+	while (p) {
+		bud = rb_entry(p, struct ubifs_bud, rb);
+		if (lnum < bud->lnum)
+			p = p->rb_left;
+		else if (lnum > bud->lnum)
+			p = p->rb_right;
+		else {
+			spin_unlock(&c->buds_lock);
+			return bud;
+		}
+	}
+	spin_unlock(&c->buds_lock);
+	return NULL;
+}
+
+/**
+ * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list.
+ * @c: UBIFS file-system description object
+ * @bud: the bud to add
+ */
+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+{
+	struct rb_node **p, *parent = NULL;
+	struct ubifs_bud *b;
+	struct ubifs_jhead *jhead;
+
+	spin_lock(&c->buds_lock);
+	p = &c->buds.rb_node;
+	while (*p) {
+		parent = *p;
+		b = rb_entry(parent, struct ubifs_bud, rb);
+		ubifs_assert(bud->lnum != b->lnum);
+		if (bud->lnum < b->lnum)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	rb_link_node(&bud->rb, parent, p);
+	rb_insert_color(&bud->rb, &c->buds);
+	if (c->jheads) {
+		jhead = &c->jheads[bud->jhead];
+		list_add_tail(&bud->list, &jhead->buds_list);
+	} else
+		ubifs_assert(c->replaying && (c->vfs_sb->s_flags & MS_RDONLY));
+
+	/*
+	 * Note, although this is a new bud, we anyway account this space now,
+	 * before any data has been written to it, because this is about to
+	 * guarantee fixed mount time, and this bud will anyway be read and
+	 * scanned.
+	 */
+	c->bud_bytes += c->leb_size - bud->start;
+
+	dbg_log("LEB %d:%d, jhead %d, bud_bytes %lld", bud->lnum,
+		bud->start, bud->jhead, c->bud_bytes);
+	spin_unlock(&c->buds_lock);
+}
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
new file mode 100644
index 0000000..8ce4949
--- /dev/null
+++ b/fs/ubifs/lprops.c
@@ -0,0 +1,842 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements the functions that access LEB properties and their
+ * categories. LEBs are categorized based on the needs of UBIFS, and the
+ * categories are stored as either heaps or lists to provide a fast way of
+ * finding a LEB in a particular category. For example, UBIFS may need to find
+ * an empty LEB for the journal, or a very dirty LEB for garbage collection.
+ */
+
+#include "ubifs.h"
+
+/**
+ * get_heap_comp_val - get the LEB properties value for heap comparisons.
+ * @lprops: LEB properties
+ * @cat: LEB category
+ */
+static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
+{
+	switch (cat) {
+	case LPROPS_FREE:
+		return lprops->free;
+	case LPROPS_DIRTY_IDX:
+		return lprops->free + lprops->dirty;
+	default:
+		return lprops->dirty;
+	}
+}
+
+/**
+ * move_up_lpt_heap - move a new heap entry up as far as possible.
+ * @c: UBIFS file-system description object
+ * @heap: LEB category heap
+ * @lprops: LEB properties to move
+ * @cat: LEB category
+ *
+ * New entries to a heap are added at the bottom and then moved up until the
+ * parent's value is greater.  In the case of LPT's category heaps, the value
+ * is either the amount of free space or the amount of dirty space, depending
+ * on the category.
+ */
+static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+			     struct ubifs_lprops *lprops, int cat)
+{
+	int val1, val2, hpos;
+
+	hpos = lprops->hpos;
+	if (!hpos)
+		return; /* Already top of the heap */
+	val1 = get_heap_comp_val(lprops, cat);
+	/* Compare to parent and, if greater, move up the heap */
+	do {
+		int ppos = (hpos - 1) / 2;
+
+		val2 = get_heap_comp_val(heap->arr[ppos], cat);
+		if (val2 >= val1)
+			return;
+		/* Greater than parent so move up */
+		heap->arr[ppos]->hpos = hpos;
+		heap->arr[hpos] = heap->arr[ppos];
+		heap->arr[ppos] = lprops;
+		lprops->hpos = ppos;
+		hpos = ppos;
+	} while (hpos);
+}
+
+/**
+ * adjust_lpt_heap - move a changed heap entry up or down the heap.
+ * @c: UBIFS file-system description object
+ * @heap: LEB category heap
+ * @lprops: LEB properties to move
+ * @hpos: heap position of @lprops
+ * @cat: LEB category
+ *
+ * Changed entries in a heap are moved up or down until the parent's value is
+ * greater.  In the case of LPT's category heaps, the value is either the amount
+ * of free space or the amount of dirty space, depending on the category.
+ */
+static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+			    struct ubifs_lprops *lprops, int hpos, int cat)
+{
+	int val1, val2, val3, cpos;
+
+	val1 = get_heap_comp_val(lprops, cat);
+	/* Compare to parent and, if greater than parent, move up the heap */
+	if (hpos) {
+		int ppos = (hpos - 1) / 2;
+
+		val2 = get_heap_comp_val(heap->arr[ppos], cat);
+		if (val1 > val2) {
+			/* Greater than parent so move up */
+			while (1) {
+				heap->arr[ppos]->hpos = hpos;
+				heap->arr[hpos] = heap->arr[ppos];
+				heap->arr[ppos] = lprops;
+				lprops->hpos = ppos;
+				hpos = ppos;
+				if (!hpos)
+					return;
+				ppos = (hpos - 1) / 2;
+				val2 = get_heap_comp_val(heap->arr[ppos], cat);
+				if (val1 <= val2)
+					return;
+				/* Still greater than parent so keep going */
+			}
+		}
+	}
+
+	/* Not greater than parent, so compare to children */
+	while (1) {
+		/* Compare to left child */
+		cpos = hpos * 2 + 1;
+		if (cpos >= heap->cnt)
+			return;
+		val2 = get_heap_comp_val(heap->arr[cpos], cat);
+		if (val1 < val2) {
+			/* Less than left child, so promote biggest child */
+			if (cpos + 1 < heap->cnt) {
+				val3 = get_heap_comp_val(heap->arr[cpos + 1],
+							 cat);
+				if (val3 > val2)
+					cpos += 1; /* Right child is bigger */
+			}
+			heap->arr[cpos]->hpos = hpos;
+			heap->arr[hpos] = heap->arr[cpos];
+			heap->arr[cpos] = lprops;
+			lprops->hpos = cpos;
+			hpos = cpos;
+			continue;
+		}
+		/* Compare to right child */
+		cpos += 1;
+		if (cpos >= heap->cnt)
+			return;
+		val3 = get_heap_comp_val(heap->arr[cpos], cat);
+		if (val1 < val3) {
+			/* Less than right child, so promote right child */
+			heap->arr[cpos]->hpos = hpos;
+			heap->arr[hpos] = heap->arr[cpos];
+			heap->arr[cpos] = lprops;
+			lprops->hpos = cpos;
+			hpos = cpos;
+			continue;
+		}
+		return;
+	}
+}
+
+/**
+ * add_to_lpt_heap - add LEB properties to a LEB category heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to add
+ * @cat: LEB category
+ *
+ * This function returns %1 if @lprops is added to the heap for LEB category
+ * @cat, otherwise %0 is returned because the heap is full.
+ */
+static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
+			   int cat)
+{
+	struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
+
+	if (heap->cnt >= heap->max_cnt) {
+		const int b = LPT_HEAP_SZ / 2 - 1;
+		int cpos, val1, val2;
+
+		/* Compare to some other LEB on the bottom of heap */
+		/* Pick a position kind of randomly */
+		cpos = (((size_t)lprops >> 4) & b) + b;
+		ubifs_assert(cpos >= b);
+		ubifs_assert(cpos < LPT_HEAP_SZ);
+		ubifs_assert(cpos < heap->cnt);
+
+		val1 = get_heap_comp_val(lprops, cat);
+		val2 = get_heap_comp_val(heap->arr[cpos], cat);
+		if (val1 > val2) {
+			struct ubifs_lprops *lp;
+
+			lp = heap->arr[cpos];
+			lp->flags &= ~LPROPS_CAT_MASK;
+			lp->flags |= LPROPS_UNCAT;
+			list_add(&lp->list, &c->uncat_list);
+			lprops->hpos = cpos;
+			heap->arr[cpos] = lprops;
+			move_up_lpt_heap(c, heap, lprops, cat);
+			dbg_check_heap(c, heap, cat, lprops->hpos);
+			return 1; /* Added to heap */
+		}
+		dbg_check_heap(c, heap, cat, -1);
+		return 0; /* Not added to heap */
+	} else {
+		lprops->hpos = heap->cnt++;
+		heap->arr[lprops->hpos] = lprops;
+		move_up_lpt_heap(c, heap, lprops, cat);
+		dbg_check_heap(c, heap, cat, lprops->hpos);
+		return 1; /* Added to heap */
+	}
+}
+
+/**
+ * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to remove
+ * @cat: LEB category
+ */
+static void remove_from_lpt_heap(struct ubifs_info *c,
+				 struct ubifs_lprops *lprops, int cat)
+{
+	struct ubifs_lpt_heap *heap;
+	int hpos = lprops->hpos;
+
+	heap = &c->lpt_heap[cat - 1];
+	ubifs_assert(hpos >= 0 && hpos < heap->cnt);
+	ubifs_assert(heap->arr[hpos] == lprops);
+	heap->cnt -= 1;
+	if (hpos < heap->cnt) {
+		heap->arr[hpos] = heap->arr[heap->cnt];
+		heap->arr[hpos]->hpos = hpos;
+		adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
+	}
+	dbg_check_heap(c, heap, cat, -1);
+}
+
+/**
+ * lpt_heap_replace - replace lprops in a category heap.
+ * @c: UBIFS file-system description object
+ * @old_lprops: LEB properties to replace
+ * @new_lprops: LEB properties with which to replace
+ * @cat: LEB category
+ *
+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
+ * and the lprops that the pnode contains.  When that happens, references in
+ * the category heaps to those lprops must be updated to point to the new
+ * lprops.  This function does that.
+ */
+static void lpt_heap_replace(struct ubifs_info *c,
+			     struct ubifs_lprops *old_lprops,
+			     struct ubifs_lprops *new_lprops, int cat)
+{
+	struct ubifs_lpt_heap *heap;
+	int hpos = new_lprops->hpos;
+
+	heap = &c->lpt_heap[cat - 1];
+	heap->arr[hpos] = new_lprops;
+}
+
+/**
+ * ubifs_add_to_cat - add LEB properties to a category list or heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to add
+ * @cat: LEB category to which to add
+ *
+ * LEB properties are categorized to enable fast find operations.
+ */
+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
+		      int cat)
+{
+	switch (cat) {
+	case LPROPS_DIRTY:
+	case LPROPS_DIRTY_IDX:
+	case LPROPS_FREE:
+		if (add_to_lpt_heap(c, lprops, cat))
+			break;
+		/* No more room on heap so make it uncategorized */
+		cat = LPROPS_UNCAT;
+		/* Fall through */
+	case LPROPS_UNCAT:
+		list_add(&lprops->list, &c->uncat_list);
+		break;
+	case LPROPS_EMPTY:
+		list_add(&lprops->list, &c->empty_list);
+		break;
+	case LPROPS_FREEABLE:
+		list_add(&lprops->list, &c->freeable_list);
+		c->freeable_cnt += 1;
+		break;
+	case LPROPS_FRDI_IDX:
+		list_add(&lprops->list, &c->frdi_idx_list);
+		break;
+	default:
+		ubifs_assert(0);
+	}
+	lprops->flags &= ~LPROPS_CAT_MASK;
+	lprops->flags |= cat;
+}
+
+/**
+ * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to remove
+ * @cat: LEB category from which to remove
+ *
+ * LEB properties are categorized to enable fast find operations.
+ */
+static void ubifs_remove_from_cat(struct ubifs_info *c,
+				  struct ubifs_lprops *lprops, int cat)
+{
+	switch (cat) {
+	case LPROPS_DIRTY:
+	case LPROPS_DIRTY_IDX:
+	case LPROPS_FREE:
+		remove_from_lpt_heap(c, lprops, cat);
+		break;
+	case LPROPS_FREEABLE:
+		c->freeable_cnt -= 1;
+		ubifs_assert(c->freeable_cnt >= 0);
+		/* Fall through */
+	case LPROPS_UNCAT:
+	case LPROPS_EMPTY:
+	case LPROPS_FRDI_IDX:
+		ubifs_assert(!list_empty(&lprops->list));
+		list_del(&lprops->list);
+		break;
+	default:
+		ubifs_assert(0);
+	}
+}
+
+/**
+ * ubifs_replace_cat - replace lprops in a category list or heap.
+ * @c: UBIFS file-system description object
+ * @old_lprops: LEB properties to replace
+ * @new_lprops: LEB properties with which to replace
+ *
+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
+ * and the lprops that the pnode contains. When that happens, references in
+ * category lists and heaps must be replaced. This function does that.
+ */
+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
+		       struct ubifs_lprops *new_lprops)
+{
+	int cat;
+
+	cat = new_lprops->flags & LPROPS_CAT_MASK;
+	switch (cat) {
+	case LPROPS_DIRTY:
+	case LPROPS_DIRTY_IDX:
+	case LPROPS_FREE:
+		lpt_heap_replace(c, old_lprops, new_lprops, cat);
+		break;
+	case LPROPS_UNCAT:
+	case LPROPS_EMPTY:
+	case LPROPS_FREEABLE:
+	case LPROPS_FRDI_IDX:
+		list_replace(&old_lprops->list, &new_lprops->list);
+		break;
+	default:
+		ubifs_assert(0);
+	}
+}
+
+/**
+ * ubifs_ensure_cat - ensure LEB properties are categorized.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties
+ *
+ * A LEB may have fallen off of the bottom of a heap, and ended up as
+ * uncategorized even though it has enough space for us now. If that is the case
+ * this function will put the LEB back onto a heap.
+ */
+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+	int cat = lprops->flags & LPROPS_CAT_MASK;
+
+	if (cat != LPROPS_UNCAT)
+		return;
+	cat = ubifs_categorize_lprops(c, lprops);
+	if (cat == LPROPS_UNCAT)
+		return;
+	ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
+	ubifs_add_to_cat(c, lprops, cat);
+}
+
+/**
+ * ubifs_categorize_lprops - categorize LEB properties.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to categorize
+ *
+ * LEB properties are categorized to enable fast find operations. This function
+ * returns the LEB category to which the LEB properties belong. Note however
+ * that if the LEB category is stored as a heap and the heap is full, the
+ * LEB properties may have their category changed to %LPROPS_UNCAT.
+ */
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+			    const struct ubifs_lprops *lprops)
+{
+	if (lprops->flags & LPROPS_TAKEN)
+		return LPROPS_UNCAT;
+
+	if (lprops->free == c->leb_size) {
+		ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+		return LPROPS_EMPTY;
+	}
+
+	if (lprops->free + lprops->dirty == c->leb_size) {
+		if (lprops->flags & LPROPS_INDEX)
+			return LPROPS_FRDI_IDX;
+		else
+			return LPROPS_FREEABLE;
+	}
+
+	if (lprops->flags & LPROPS_INDEX) {
+		if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
+			return LPROPS_DIRTY_IDX;
+	} else {
+		if (lprops->dirty >= c->dead_wm &&
+		    lprops->dirty > lprops->free)
+			return LPROPS_DIRTY;
+		if (lprops->free > 0)
+			return LPROPS_FREE;
+	}
+
+	return LPROPS_UNCAT;
+}
+
+/**
+ * change_category - change LEB properties category.
+ * @c: UBIFS file-system description object
+ * @lprops: LEB properties to recategorize
+ *
+ * LEB properties are categorized to enable fast find operations. When the LEB
+ * properties change they must be recategorized.
+ */
+static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+	int old_cat = lprops->flags & LPROPS_CAT_MASK;
+	int new_cat = ubifs_categorize_lprops(c, lprops);
+
+	if (old_cat == new_cat) {
+		struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
+
+		/* lprops on a heap now must be moved up or down */
+		if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
+			return; /* Not on a heap */
+		heap = &c->lpt_heap[new_cat - 1];
+		adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
+	} else {
+		ubifs_remove_from_cat(c, lprops, old_cat);
+		ubifs_add_to_cat(c, lprops, new_cat);
+	}
+}
+
+/**
+ * calc_dark - calculate LEB dark space size.
+ * @c: the UBIFS file-system description object
+ * @spc: amount of free and dirty space in the LEB
+ *
+ * This function calculates amount of dark space in an LEB which has @spc bytes
+ * of free and dirty space. Returns the calculations result.
+ *
+ * Dark space is the space which is not always usable - it depends on which
+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
+ * count on this LEB and treat these 512 bytes as usable because it is not true
+ * if, for example, only big chunks of uncompressible data will be written to
+ * the FS.
+ */
+static int calc_dark(struct ubifs_info *c, int spc)
+{
+	ubifs_assert(!(spc & 7));
+
+	if (spc < c->dark_wm)
+		return spc;
+
+	/*
+	 * If we have slightly more space then the dark space watermark, we can
+	 * anyway safely assume it we'll be able to write a node of the
+	 * smallest size there.
+	 */
+	if (spc - c->dark_wm < MIN_WRITE_SZ)
+		return spc - MIN_WRITE_SZ;
+
+	return c->dark_wm;
+}
+
+/**
+ * is_lprops_dirty - determine if LEB properties are dirty.
+ * @c: the UBIFS file-system description object
+ * @lprops: LEB properties to test
+ */
+static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
+{
+	struct ubifs_pnode *pnode;
+	int pos;
+
+	pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
+	pnode = (struct ubifs_pnode *)container_of(lprops - pos,
+						   struct ubifs_pnode,
+						   lprops[0]);
+	return !test_bit(COW_ZNODE, &pnode->flags) &&
+	       test_bit(DIRTY_CNODE, &pnode->flags);
+}
+
+/**
+ * ubifs_change_lp - change LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lp: LEB properties to change
+ * @free: new free space amount
+ * @dirty: new dirty space amount
+ * @flags: new flags
+ * @idx_gc_cnt: change to the count of idx_gc list
+ *
+ * This function changes LEB properties (@free, @dirty or @flag). However, the
+ * property which has the %LPROPS_NC value is not changed. Returns a pointer to
+ * the updated LEB properties on success and a negative error code on failure.
+ *
+ * Note, the LEB properties may have had to be copied (due to COW) and
+ * consequently the pointer returned may not be the same as the pointer
+ * passed.
+ */
+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
+					   const struct ubifs_lprops *lp,
+					   int free, int dirty, int flags,
+					   int idx_gc_cnt)
+{
+	/*
+	 * This is the only function that is allowed to change lprops, so we
+	 * discard the const qualifier.
+	 */
+	struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
+
+	dbg_lp("LEB %d, free %d, dirty %d, flags %d",
+	       lprops->lnum, free, dirty, flags);
+
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+	ubifs_assert(c->lst.empty_lebs >= 0 &&
+		     c->lst.empty_lebs <= c->main_lebs);
+	ubifs_assert(c->freeable_cnt >= 0);
+	ubifs_assert(c->freeable_cnt <= c->main_lebs);
+	ubifs_assert(c->lst.taken_empty_lebs >= 0);
+	ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
+	ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
+	ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
+	ubifs_assert(!(c->lst.total_used & 7));
+	ubifs_assert(free == LPROPS_NC || free >= 0);
+	ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
+
+	if (!is_lprops_dirty(c, lprops)) {
+		lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
+		if (IS_ERR(lprops))
+			return lprops;
+	} else
+		ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
+
+	ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
+
+	spin_lock(&c->space_lock);
+	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
+		c->lst.taken_empty_lebs -= 1;
+
+	if (!(lprops->flags & LPROPS_INDEX)) {
+		int old_spc;
+
+		old_spc = lprops->free + lprops->dirty;
+		if (old_spc < c->dead_wm)
+			c->lst.total_dead -= old_spc;
+		else
+			c->lst.total_dark -= calc_dark(c, old_spc);
+
+		c->lst.total_used -= c->leb_size - old_spc;
+	}
+
+	if (free != LPROPS_NC) {
+		free = ALIGN(free, 8);
+		c->lst.total_free += free - lprops->free;
+
+		/* Increase or decrease empty LEBs counter if needed */
+		if (free == c->leb_size) {
+			if (lprops->free != c->leb_size)
+				c->lst.empty_lebs += 1;
+		} else if (lprops->free == c->leb_size)
+			c->lst.empty_lebs -= 1;
+		lprops->free = free;
+	}
+
+	if (dirty != LPROPS_NC) {
+		dirty = ALIGN(dirty, 8);
+		c->lst.total_dirty += dirty - lprops->dirty;
+		lprops->dirty = dirty;
+	}
+
+	if (flags != LPROPS_NC) {
+		/* Take care about indexing LEBs counter if needed */
+		if ((lprops->flags & LPROPS_INDEX)) {
+			if (!(flags & LPROPS_INDEX))
+				c->lst.idx_lebs -= 1;
+		} else if (flags & LPROPS_INDEX)
+			c->lst.idx_lebs += 1;
+		lprops->flags = flags;
+	}
+
+	if (!(lprops->flags & LPROPS_INDEX)) {
+		int new_spc;
+
+		new_spc = lprops->free + lprops->dirty;
+		if (new_spc < c->dead_wm)
+			c->lst.total_dead += new_spc;
+		else
+			c->lst.total_dark += calc_dark(c, new_spc);
+
+		c->lst.total_used += c->leb_size - new_spc;
+	}
+
+	if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
+		c->lst.taken_empty_lebs += 1;
+
+	change_category(c, lprops);
+	c->idx_gc_cnt += idx_gc_cnt;
+	spin_unlock(&c->space_lock);
+	return lprops;
+}
+
+/**
+ * ubifs_get_lp_stats - get lprops statistics.
+ * @c: UBIFS file-system description object
+ * @st: return statistics
+ */
+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
+{
+	spin_lock(&c->space_lock);
+	memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
+	spin_unlock(&c->space_lock);
+}
+
+/**
+ * ubifs_change_one_lp - change LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to change properties for
+ * @free: amount of free space
+ * @dirty: amount of dirty space
+ * @flags_set: flags to set
+ * @flags_clean: flags to clean
+ * @idx_gc_cnt: change to the count of idx_gc list
+ *
+ * This function changes properties of LEB @lnum. It is a helper wrapper over
+ * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
+ * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
+ * a negative error code in case of failure.
+ */
+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+			int flags_set, int flags_clean, int idx_gc_cnt)
+{
+	int err = 0, flags;
+	const struct ubifs_lprops *lp;
+
+	ubifs_get_lprops(c);
+
+	lp = ubifs_lpt_lookup_dirty(c, lnum);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+
+	flags = (lp->flags | flags_set) & ~flags_clean;
+	lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
+	if (IS_ERR(lp))
+		err = PTR_ERR(lp);
+
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * ubifs_update_one_lp - update LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to change properties for
+ * @free: amount of free space
+ * @dirty: amount of dirty space to add
+ * @flags_set: flags to set
+ * @flags_clean: flags to clean
+ *
+ * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
+ * current dirty space, not substitutes it.
+ */
+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+			int flags_set, int flags_clean)
+{
+	int err = 0, flags;
+	const struct ubifs_lprops *lp;
+
+	ubifs_get_lprops(c);
+
+	lp = ubifs_lpt_lookup_dirty(c, lnum);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+
+	flags = (lp->flags | flags_set) & ~flags_clean;
+	lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
+	if (IS_ERR(lp))
+		err = PTR_ERR(lp);
+
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * ubifs_read_one_lp - read LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to read properties for
+ * @lp: where to store read properties
+ *
+ * This helper function reads properties of a LEB @lnum and stores them in @lp.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
+{
+	int err = 0;
+	const struct ubifs_lprops *lpp;
+
+	ubifs_get_lprops(c);
+
+	lpp = ubifs_lpt_lookup(c, lnum);
+	if (IS_ERR(lpp)) {
+		err = PTR_ERR(lpp);
+		goto out;
+	}
+
+	memcpy(lp, lpp, sizeof(struct ubifs_lprops));
+
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * ubifs_fast_find_free - try to find a LEB with free space quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a LEB with free space or %NULL if
+ * the function is unable to find a LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
+{
+	struct ubifs_lprops *lprops;
+	struct ubifs_lpt_heap *heap;
+
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+	heap = &c->lpt_heap[LPROPS_FREE - 1];
+	if (heap->cnt == 0)
+		return NULL;
+
+	lprops = heap->arr[0];
+	ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+	ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+	return lprops;
+}
+
+/**
+ * ubifs_fast_find_empty - try to find an empty LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for an empty LEB or %NULL if the
+ * function is unable to find an empty LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
+{
+	struct ubifs_lprops *lprops;
+
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+	if (list_empty(&c->empty_list))
+		return NULL;
+
+	lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
+	ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+	ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+	ubifs_assert(lprops->free == c->leb_size);
+	return lprops;
+}
+
+/**
+ * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a freeable LEB or %NULL if the
+ * function is unable to find a freeable LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
+{
+	struct ubifs_lprops *lprops;
+
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+	if (list_empty(&c->freeable_list))
+		return NULL;
+
+	lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
+	ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+	ubifs_assert(!(lprops->flags & LPROPS_INDEX));
+	ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
+	ubifs_assert(c->freeable_cnt > 0);
+	return lprops;
+}
+
+/**
+ * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns LEB properties for a freeable index LEB or %NULL if the
+ * function is unable to find a freeable index LEB quickly.
+ */
+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
+{
+	struct ubifs_lprops *lprops;
+
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+
+	if (list_empty(&c->frdi_idx_list))
+		return NULL;
+
+	lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
+	ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
+	ubifs_assert((lprops->flags & LPROPS_INDEX));
+	ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
+	return lprops;
+}
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
new file mode 100644
index 0000000..1a50d4c
--- /dev/null
+++ b/fs/ubifs/lpt.c
@@ -0,0 +1,1105 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements the LEB properties tree (LPT) area. The LPT area
+ * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
+ * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
+ * between the log and the orphan area.
+ *
+ * The LPT area is like a miniature self-contained file system. It is required
+ * that it never runs out of space, is fast to access and update, and scales
+ * logarithmically. The LEB properties tree is implemented as a wandering tree
+ * much like the TNC, and the LPT area has its own garbage collection.
+ *
+ * The LPT has two slightly different forms called the "small model" and the
+ * "big model". The small model is used when the entire LEB properties table
+ * can be written into a single eraseblock. In that case, garbage collection
+ * consists of just writing the whole table, which therefore makes all other
+ * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
+ * selected for garbage collection, which consists of marking the clean nodes in
+ * that LEB as dirty, and then only the dirty nodes are written out. Also, in
+ * the case of the big model, a table of LEB numbers is saved so that the entire
+ * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
+ * mounted.
+ */
+
+#include "ubifs.h"
+#include "crc16.h"
+#include <linux/math64.h>
+
+/**
+ * do_calc_lpt_geom - calculate sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
+ * properties of the flash and whether LPT is "big" (c->big_lpt).
+ */
+static void do_calc_lpt_geom(struct ubifs_info *c)
+{
+	int i, n, bits, per_leb_wastage, max_pnode_cnt;
+	long long sz, tot_wastage;
+
+	n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
+	max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
+
+	c->lpt_hght = 1;
+	n = UBIFS_LPT_FANOUT;
+	while (n < max_pnode_cnt) {
+		c->lpt_hght += 1;
+		n <<= UBIFS_LPT_FANOUT_SHIFT;
+	}
+
+	c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
+
+	n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
+	c->nnode_cnt = n;
+	for (i = 1; i < c->lpt_hght; i++) {
+		n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
+		c->nnode_cnt += n;
+	}
+
+	c->space_bits = fls(c->leb_size) - 3;
+	c->lpt_lnum_bits = fls(c->lpt_lebs);
+	c->lpt_offs_bits = fls(c->leb_size - 1);
+	c->lpt_spc_bits = fls(c->leb_size);
+
+	n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
+	c->pcnt_bits = fls(n - 1);
+
+	c->lnum_bits = fls(c->max_leb_cnt - 1);
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
+	c->pnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       (c->big_lpt ? c->pcnt_bits : 0) +
+	       (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
+	c->nnode_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lpt_lebs * c->lpt_spc_bits * 2;
+	c->ltab_sz = (bits + 7) / 8;
+
+	bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+	       c->lnum_bits * c->lsave_cnt;
+	c->lsave_sz = (bits + 7) / 8;
+
+	/* Calculate the minimum LPT size */
+	c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+	c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+	c->lpt_sz += c->ltab_sz;
+	if (c->big_lpt)
+		c->lpt_sz += c->lsave_sz;
+
+	/* Add wastage */
+	sz = c->lpt_sz;
+	per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
+	sz += per_leb_wastage;
+	tot_wastage = per_leb_wastage;
+	while (sz > c->leb_size) {
+		sz += per_leb_wastage;
+		sz -= c->leb_size;
+		tot_wastage += per_leb_wastage;
+	}
+	tot_wastage += ALIGN(sz, c->min_io_size) - sz;
+	c->lpt_sz += tot_wastage;
+}
+
+/**
+ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_calc_lpt_geom(struct ubifs_info *c)
+{
+	int lebs_needed;
+	long long sz;
+
+	do_calc_lpt_geom(c);
+
+	/* Verify that lpt_lebs is big enough */
+	sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
+	lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
+	if (lebs_needed > c->lpt_lebs) {
+		ubifs_err("too few LPT LEBs");
+		return -EINVAL;
+	}
+
+	/* Verify that ltab fits in a single LEB (since ltab is a single node */
+	if (c->ltab_sz > c->leb_size) {
+		ubifs_err("LPT ltab too big");
+		return -EINVAL;
+	}
+
+	c->check_lpt_free = c->big_lpt;
+	return 0;
+}
+
+/**
+ * ubifs_unpack_bits - unpack bit fields.
+ * @addr: address at which to unpack (passed and next address returned)
+ * @pos: bit position at which to unpack (passed and next position returned)
+ * @nrbits: number of bits of value to unpack (1-32)
+ *
+ * This functions returns the value unpacked.
+ */
+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
+{
+	const int k = 32 - nrbits;
+	uint8_t *p = *addr;
+	int b = *pos;
+	uint32_t uninitialized_var(val);
+	const int bytes = (nrbits + b + 7) >> 3;
+
+	ubifs_assert(nrbits > 0);
+	ubifs_assert(nrbits <= 32);
+	ubifs_assert(*pos >= 0);
+	ubifs_assert(*pos < 8);
+	if (b) {
+		switch (bytes) {
+		case 2:
+			val = p[1];
+			break;
+		case 3:
+			val = p[1] | ((uint32_t)p[2] << 8);
+			break;
+		case 4:
+			val = p[1] | ((uint32_t)p[2] << 8) |
+				     ((uint32_t)p[3] << 16);
+			break;
+		case 5:
+			val = p[1] | ((uint32_t)p[2] << 8) |
+				     ((uint32_t)p[3] << 16) |
+				     ((uint32_t)p[4] << 24);
+		}
+		val <<= (8 - b);
+		val |= *p >> b;
+		nrbits += b;
+	} else {
+		switch (bytes) {
+		case 1:
+			val = p[0];
+			break;
+		case 2:
+			val = p[0] | ((uint32_t)p[1] << 8);
+			break;
+		case 3:
+			val = p[0] | ((uint32_t)p[1] << 8) |
+				     ((uint32_t)p[2] << 16);
+			break;
+		case 4:
+			val = p[0] | ((uint32_t)p[1] << 8) |
+				     ((uint32_t)p[2] << 16) |
+				     ((uint32_t)p[3] << 24);
+			break;
+		}
+	}
+	val <<= k;
+	val >>= k;
+	b = nrbits & 7;
+	p += nrbits >> 3;
+	*addr = p;
+	*pos = b;
+	ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
+	return val;
+}
+
+/**
+ * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to which to add dirty space
+ * @dirty: amount of dirty space to add
+ */
+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
+{
+	if (!dirty || !lnum)
+		return;
+	dbg_lp("LEB %d add %d to %d",
+	       lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
+	ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
+	c->ltab[lnum - c->lpt_first].dirty += dirty;
+}
+
+/**
+ * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode for which to add dirt
+ */
+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
+{
+	struct ubifs_nnode *np = nnode->parent;
+
+	if (np)
+		ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
+				   c->nnode_sz);
+	else {
+		ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
+		if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
+			c->lpt_drty_flgs |= LTAB_DIRTY;
+			ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
+		}
+	}
+}
+
+/**
+ * add_pnode_dirt - add dirty space to LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode for which to add dirt
+ */
+static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
+{
+	ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
+			   c->pnode_sz);
+}
+
+/**
+ * calc_nnode_num_from_parent - calculate nnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * The nnode number is a number that uniquely identifies a nnode and can be used
+ * easily to traverse the tree from the root to that nnode.
+ *
+ * This function calculates and returns the nnode number based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_nnode_num_from_parent(const struct ubifs_info *c,
+				      struct ubifs_nnode *parent, int iip)
+{
+	int num, shft;
+
+	if (!parent)
+		return 1;
+	shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
+	num = parent->num ^ (1 << shft);
+	num |= (UBIFS_LPT_FANOUT + iip) << shft;
+	return num;
+}
+
+/**
+ * calc_pnode_num_from_parent - calculate pnode number.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * The pnode number is a number that uniquely identifies a pnode and can be used
+ * easily to traverse the tree from the root to that pnode.
+ *
+ * This function calculates and returns the pnode number based on the parent's
+ * nnode number and the index in parent.
+ */
+static int calc_pnode_num_from_parent(const struct ubifs_info *c,
+				      struct ubifs_nnode *parent, int iip)
+{
+	int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
+
+	for (i = 0; i < n; i++) {
+		num <<= UBIFS_LPT_FANOUT_SHIFT;
+		num |= pnum & (UBIFS_LPT_FANOUT - 1);
+		pnum >>= UBIFS_LPT_FANOUT_SHIFT;
+	}
+	num <<= UBIFS_LPT_FANOUT_SHIFT;
+	num |= iip;
+	return num;
+}
+
+/**
+ * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode
+ *
+ * When a pnode is loaded into memory, the LEB properties it contains are added,
+ * by this function, to the LEB category lists and heaps.
+ */
+static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
+{
+	int i;
+
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
+		int lnum = pnode->lprops[i].lnum;
+
+		if (!lnum)
+			return;
+		ubifs_add_to_cat(c, &pnode->lprops[i], cat);
+	}
+}
+
+/**
+ * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
+ * @c: UBIFS file-system description object
+ * @old_pnode: pnode copied
+ * @new_pnode: pnode copy
+ *
+ * During commit it is sometimes necessary to copy a pnode
+ * (see dirty_cow_pnode).  When that happens, references in
+ * category lists and heaps must be replaced.  This function does that.
+ */
+static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
+			 struct ubifs_pnode *new_pnode)
+{
+	int i;
+
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		if (!new_pnode->lprops[i].lnum)
+			return;
+		ubifs_replace_cat(c, &old_pnode->lprops[i],
+				  &new_pnode->lprops[i]);
+	}
+}
+
+/**
+ * check_lpt_crc - check LPT node crc is correct.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing node
+ * @len: length of node
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int check_lpt_crc(void *buf, int len)
+{
+	int pos = 0;
+	uint8_t *addr = buf;
+	uint16_t crc, calc_crc;
+
+	crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
+	calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+			 len - UBIFS_LPT_CRC_BYTES);
+	if (crc != calc_crc) {
+		ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
+			  calc_crc);
+		dbg_dump_stack();
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * check_lpt_type - check LPT node type is correct.
+ * @c: UBIFS file-system description object
+ * @addr: address of type bit field is passed and returned updated here
+ * @pos: position of type bit field is passed and returned updated here
+ * @type: expected type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int check_lpt_type(uint8_t **addr, int *pos, int type)
+{
+	int node_type;
+
+	node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
+	if (node_type != type) {
+		ubifs_err("invalid type (%d) in LPT node type %d", node_type,
+			  type);
+		dbg_dump_stack();
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * unpack_pnode - unpack a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed pnode to unpack
+ * @pnode: pnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int unpack_pnode(const struct ubifs_info *c, void *buf,
+			struct ubifs_pnode *pnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE);
+	if (err)
+		return err;
+	if (c->big_lpt)
+		pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+		lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+		lprops->free <<= 3;
+		lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
+		lprops->dirty <<= 3;
+
+		if (ubifs_unpack_bits(&addr, &pos, 1))
+			lprops->flags = LPROPS_INDEX;
+		else
+			lprops->flags = 0;
+		lprops->flags |= ubifs_categorize_lprops(c, lprops);
+	}
+	err = check_lpt_crc(buf, c->pnode_sz);
+	return err;
+}
+
+/**
+ * ubifs_unpack_nnode - unpack a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing packed nnode to unpack
+ * @nnode: nnode structure to fill
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE);
+	if (err)
+		return err;
+	if (c->big_lpt)
+		nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int lnum;
+
+		lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
+		       c->lpt_first;
+		if (lnum == c->lpt_last + 1)
+			lnum = 0;
+		nnode->nbranch[i].lnum = lnum;
+		nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
+						     c->lpt_offs_bits);
+	}
+	err = check_lpt_crc(buf, c->nnode_sz);
+	return err;
+}
+
+/**
+ * unpack_ltab - unpack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer from which to unpack
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int unpack_ltab(const struct ubifs_info *c, void *buf)
+{
+	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+	int i, pos = 0, err;
+
+	err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB);
+	if (err)
+		return err;
+	for (i = 0; i < c->lpt_lebs; i++) {
+		int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+		int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
+
+		if (free < 0 || free > c->leb_size || dirty < 0 ||
+		    dirty > c->leb_size || free + dirty > c->leb_size)
+			return -EINVAL;
+
+		c->ltab[i].free = free;
+		c->ltab[i].dirty = dirty;
+		c->ltab[i].tgc = 0;
+		c->ltab[i].cmt = 0;
+	}
+	err = check_lpt_crc(buf, c->ltab_sz);
+	return err;
+}
+
+/**
+ * validate_nnode - validate a nnode.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode to validate
+ * @parent: parent nnode (or NULL for the root nnode)
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
+			  struct ubifs_nnode *parent, int iip)
+{
+	int i, lvl, max_offs;
+
+	if (c->big_lpt) {
+		int num = calc_nnode_num_from_parent(c, parent, iip);
+
+		if (nnode->num != num)
+			return -EINVAL;
+	}
+	lvl = parent ? parent->level - 1 : c->lpt_hght;
+	if (lvl < 1)
+		return -EINVAL;
+	if (lvl == 1)
+		max_offs = c->leb_size - c->pnode_sz;
+	else
+		max_offs = c->leb_size - c->nnode_sz;
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int lnum = nnode->nbranch[i].lnum;
+		int offs = nnode->nbranch[i].offs;
+
+		if (lnum == 0) {
+			if (offs != 0)
+				return -EINVAL;
+			continue;
+		}
+		if (lnum < c->lpt_first || lnum > c->lpt_last)
+			return -EINVAL;
+		if (offs < 0 || offs > max_offs)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * validate_pnode - validate a pnode.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to validate
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
+			  struct ubifs_nnode *parent, int iip)
+{
+	int i;
+
+	if (c->big_lpt) {
+		int num = calc_pnode_num_from_parent(c, parent, iip);
+
+		if (pnode->num != num)
+			return -EINVAL;
+	}
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		int free = pnode->lprops[i].free;
+		int dirty = pnode->lprops[i].dirty;
+
+		if (free < 0 || free > c->leb_size || free % c->min_io_size ||
+		    (free & 7))
+			return -EINVAL;
+		if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
+			return -EINVAL;
+		if (dirty + free > c->leb_size)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * set_pnode_lnum - set LEB numbers on a pnode.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to update
+ *
+ * This function calculates the LEB numbers for the LEB properties it contains
+ * based on the pnode number.
+ */
+static void set_pnode_lnum(const struct ubifs_info *c,
+			   struct ubifs_pnode *pnode)
+{
+	int i, lnum;
+
+	lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		if (lnum >= c->leb_cnt)
+			return;
+		pnode->lprops[i].lnum = lnum++;
+	}
+}
+
+/**
+ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode (or NULL for the root)
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch = NULL;
+	struct ubifs_nnode *nnode = NULL;
+	void *buf = c->lpt_nod_buf;
+	int err, lnum, offs;
+
+	if (parent) {
+		branch = &parent->nbranch[iip];
+		lnum = branch->lnum;
+		offs = branch->offs;
+	} else {
+		lnum = c->lpt_lnum;
+		offs = c->lpt_offs;
+	}
+	nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+	if (!nnode) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (lnum == 0) {
+		/*
+		 * This nnode was not written which just means that the LEB
+		 * properties in the subtree below it describe empty LEBs. We
+		 * make the nnode as though we had read it, which in fact means
+		 * doing almost nothing.
+		 */
+		if (c->big_lpt)
+			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	} else {
+		err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
+		if (err)
+			goto out;
+		err = ubifs_unpack_nnode(c, buf, nnode);
+		if (err)
+			goto out;
+	}
+	err = validate_nnode(c, nnode, parent, iip);
+	if (err)
+		goto out;
+	if (!c->big_lpt)
+		nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+	if (parent) {
+		branch->nnode = nnode;
+		nnode->level = parent->level - 1;
+	} else {
+		c->nroot = nnode;
+		nnode->level = c->lpt_hght;
+	}
+	nnode->parent = parent;
+	nnode->iip = iip;
+	return 0;
+
+out:
+	ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
+	kfree(nnode);
+	return err;
+}
+
+/**
+ * read_pnode - read a pnode from flash and link it to the tree in memory.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch;
+	struct ubifs_pnode *pnode = NULL;
+	void *buf = c->lpt_nod_buf;
+	int err, lnum, offs;
+
+	branch = &parent->nbranch[iip];
+	lnum = branch->lnum;
+	offs = branch->offs;
+	pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+	if (!pnode) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (lnum == 0) {
+		/*
+		 * This pnode was not written which just means that the LEB
+		 * properties in it describe empty LEBs. We make the pnode as
+		 * though we had read it.
+		 */
+		int i;
+
+		if (c->big_lpt)
+			pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+			struct ubifs_lprops * const lprops = &pnode->lprops[i];
+
+			lprops->free = c->leb_size;
+			lprops->flags = ubifs_categorize_lprops(c, lprops);
+		}
+	} else {
+		err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
+		if (err)
+			goto out;
+		err = unpack_pnode(c, buf, pnode);
+		if (err)
+			goto out;
+	}
+	err = validate_pnode(c, pnode, parent, iip);
+	if (err)
+		goto out;
+	if (!c->big_lpt)
+		pnode->num = calc_pnode_num_from_parent(c, parent, iip);
+	branch->pnode = pnode;
+	pnode->parent = parent;
+	pnode->iip = iip;
+	set_pnode_lnum(c, pnode);
+	c->pnodes_have += 1;
+	return 0;
+
+out:
+	ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+	dbg_dump_pnode(c, pnode, parent, iip);
+	dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+	kfree(pnode);
+	return err;
+}
+
+/**
+ * read_ltab - read LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int read_ltab(struct ubifs_info *c)
+{
+	int err;
+	void *buf;
+
+	buf = vmalloc(c->ltab_sz);
+	if (!buf)
+		return -ENOMEM;
+	err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
+	if (err)
+		goto out;
+	err = unpack_ltab(c, buf);
+out:
+	vfree(buf);
+	return err;
+}
+
+/**
+ * ubifs_get_nnode - get a nnode.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode (or NULL for the root)
+ * @iip: index in parent
+ *
+ * This function returns a pointer to the nnode on success or a negative error
+ * code on failure.
+ */
+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
+				    struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch;
+	struct ubifs_nnode *nnode;
+	int err;
+
+	branch = &parent->nbranch[iip];
+	nnode = branch->nnode;
+	if (nnode)
+		return nnode;
+	err = ubifs_read_nnode(c, parent, iip);
+	if (err)
+		return ERR_PTR(err);
+	return branch->nnode;
+}
+
+/**
+ * ubifs_get_pnode - get a pnode.
+ * @c: UBIFS file-system description object
+ * @parent: parent nnode
+ * @iip: index in parent
+ *
+ * This function returns a pointer to the pnode on success or a negative error
+ * code on failure.
+ */
+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
+				    struct ubifs_nnode *parent, int iip)
+{
+	struct ubifs_nbranch *branch;
+	struct ubifs_pnode *pnode;
+	int err;
+
+	branch = &parent->nbranch[iip];
+	pnode = branch->pnode;
+	if (pnode)
+		return pnode;
+	err = read_pnode(c, parent, iip);
+	if (err)
+		return ERR_PTR(err);
+	update_cats(c, branch->pnode);
+	return branch->pnode;
+}
+
+/**
+ * ubifs_lpt_lookup - lookup LEB properties in the LPT.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to lookup
+ *
+ * This function returns a pointer to the LEB properties on success or a
+ * negative error code on failure.
+ */
+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
+{
+	int err, i, h, iip, shft;
+	struct ubifs_nnode *nnode;
+	struct ubifs_pnode *pnode;
+
+	if (!c->nroot) {
+		err = ubifs_read_nnode(c, NULL, 0);
+		if (err)
+			return ERR_PTR(err);
+	}
+	nnode = c->nroot;
+	i = lnum - c->main_first;
+	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
+	for (h = 1; h < c->lpt_hght; h++) {
+		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+		shft -= UBIFS_LPT_FANOUT_SHIFT;
+		nnode = ubifs_get_nnode(c, nnode, iip);
+		if (IS_ERR(nnode))
+			return ERR_PTR(PTR_ERR(nnode));
+	}
+	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+	shft -= UBIFS_LPT_FANOUT_SHIFT;
+	pnode = ubifs_get_pnode(c, nnode, iip);
+	if (IS_ERR(pnode))
+		return ERR_PTR(PTR_ERR(pnode));
+	iip = (i & (UBIFS_LPT_FANOUT - 1));
+	dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
+	       pnode->lprops[iip].free, pnode->lprops[iip].dirty,
+	       pnode->lprops[iip].flags);
+	return &pnode->lprops[iip];
+}
+
+/**
+ * dirty_cow_nnode - ensure a nnode is not being committed.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode to check
+ *
+ * Returns dirtied nnode on success or negative error code on failure.
+ */
+static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
+					   struct ubifs_nnode *nnode)
+{
+	struct ubifs_nnode *n;
+	int i;
+
+	if (!test_bit(COW_CNODE, &nnode->flags)) {
+		/* nnode is not being committed */
+		if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
+			c->dirty_nn_cnt += 1;
+			ubifs_add_nnode_dirt(c, nnode);
+		}
+		return nnode;
+	}
+
+	/* nnode is being committed, so copy it */
+	n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+	if (unlikely(!n))
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(n, nnode, sizeof(struct ubifs_nnode));
+	n->cnext = NULL;
+	__set_bit(DIRTY_CNODE, &n->flags);
+	__clear_bit(COW_CNODE, &n->flags);
+
+	/* The children now have new parent */
+	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+		struct ubifs_nbranch *branch = &n->nbranch[i];
+
+		if (branch->cnode)
+			branch->cnode->parent = n;
+	}
+
+	ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
+	__set_bit(OBSOLETE_CNODE, &nnode->flags);
+
+	c->dirty_nn_cnt += 1;
+	ubifs_add_nnode_dirt(c, nnode);
+	if (nnode->parent)
+		nnode->parent->nbranch[n->iip].nnode = n;
+	else
+		c->nroot = n;
+	return n;
+}
+
+/**
+ * dirty_cow_pnode - ensure a pnode is not being committed.
+ * @c: UBIFS file-system description object
+ * @pnode: pnode to check
+ *
+ * Returns dirtied pnode on success or negative error code on failure.
+ */
+static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
+					   struct ubifs_pnode *pnode)
+{
+	struct ubifs_pnode *p;
+
+	if (!test_bit(COW_CNODE, &pnode->flags)) {
+		/* pnode is not being committed */
+		if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
+			c->dirty_pn_cnt += 1;
+			add_pnode_dirt(c, pnode);
+		}
+		return pnode;
+	}
+
+	/* pnode is being committed, so copy it */
+	p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+	if (unlikely(!p))
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(p, pnode, sizeof(struct ubifs_pnode));
+	p->cnext = NULL;
+	__set_bit(DIRTY_CNODE, &p->flags);
+	__clear_bit(COW_CNODE, &p->flags);
+	replace_cats(c, pnode, p);
+
+	ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
+	__set_bit(OBSOLETE_CNODE, &pnode->flags);
+
+	c->dirty_pn_cnt += 1;
+	add_pnode_dirt(c, pnode);
+	pnode->parent->nbranch[p->iip].pnode = p;
+	return p;
+}
+
+/**
+ * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to lookup
+ *
+ * This function returns a pointer to the LEB properties on success or a
+ * negative error code on failure.
+ */
+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
+{
+	int err, i, h, iip, shft;
+	struct ubifs_nnode *nnode;
+	struct ubifs_pnode *pnode;
+
+	if (!c->nroot) {
+		err = ubifs_read_nnode(c, NULL, 0);
+		if (err)
+			return ERR_PTR(err);
+	}
+	nnode = c->nroot;
+	nnode = dirty_cow_nnode(c, nnode);
+	if (IS_ERR(nnode))
+		return ERR_PTR(PTR_ERR(nnode));
+	i = lnum - c->main_first;
+	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
+	for (h = 1; h < c->lpt_hght; h++) {
+		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+		shft -= UBIFS_LPT_FANOUT_SHIFT;
+		nnode = ubifs_get_nnode(c, nnode, iip);
+		if (IS_ERR(nnode))
+			return ERR_PTR(PTR_ERR(nnode));
+		nnode = dirty_cow_nnode(c, nnode);
+		if (IS_ERR(nnode))
+			return ERR_PTR(PTR_ERR(nnode));
+	}
+	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
+	shft -= UBIFS_LPT_FANOUT_SHIFT;
+	pnode = ubifs_get_pnode(c, nnode, iip);
+	if (IS_ERR(pnode))
+		return ERR_PTR(PTR_ERR(pnode));
+	pnode = dirty_cow_pnode(c, pnode);
+	if (IS_ERR(pnode))
+		return ERR_PTR(PTR_ERR(pnode));
+	iip = (i & (UBIFS_LPT_FANOUT - 1));
+	dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
+	       pnode->lprops[iip].free, pnode->lprops[iip].dirty,
+	       pnode->lprops[iip].flags);
+	ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
+	return &pnode->lprops[iip];
+}
+
+/**
+ * lpt_init_rd - initialize the LPT for reading.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int lpt_init_rd(struct ubifs_info *c)
+{
+	int err, i;
+
+	c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
+	if (!c->ltab)
+		return -ENOMEM;
+
+	i = max_t(int, c->nnode_sz, c->pnode_sz);
+	c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
+	if (!c->lpt_nod_buf)
+		return -ENOMEM;
+
+	for (i = 0; i < LPROPS_HEAP_CNT; i++) {
+		c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ,
+					     GFP_KERNEL);
+		if (!c->lpt_heap[i].arr)
+			return -ENOMEM;
+		c->lpt_heap[i].cnt = 0;
+		c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
+	}
+
+	c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL);
+	if (!c->dirty_idx.arr)
+		return -ENOMEM;
+	c->dirty_idx.cnt = 0;
+	c->dirty_idx.max_cnt = LPT_HEAP_SZ;
+
+	err = read_ltab(c);
+	if (err)
+		return err;
+
+	dbg_lp("space_bits %d", c->space_bits);
+	dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
+	dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
+	dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
+	dbg_lp("pcnt_bits %d", c->pcnt_bits);
+	dbg_lp("lnum_bits %d", c->lnum_bits);
+	dbg_lp("pnode_sz %d", c->pnode_sz);
+	dbg_lp("nnode_sz %d", c->nnode_sz);
+	dbg_lp("ltab_sz %d", c->ltab_sz);
+	dbg_lp("lsave_sz %d", c->lsave_sz);
+	dbg_lp("lsave_cnt %d", c->lsave_cnt);
+	dbg_lp("lpt_hght %d", c->lpt_hght);
+	dbg_lp("big_lpt %d", c->big_lpt);
+	dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
+	dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
+	dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
+	if (c->big_lpt)
+		dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
+
+	return 0;
+}
+
+/**
+ * ubifs_lpt_init - initialize the LPT.
+ * @c: UBIFS file-system description object
+ * @rd: whether to initialize lpt for reading
+ * @wr: whether to initialize lpt for writing
+ *
+ * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
+ * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
+ * true.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
+{
+	int err;
+
+	if (rd) {
+		err = lpt_init_rd(c);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
new file mode 100644
index 0000000..c0af818
--- /dev/null
+++ b/fs/ubifs/lpt_commit.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements commit-related functionality of the LEB properties
+ * subsystem.
+ */
+
+#include "crc16.h"
+#include "ubifs.h"
+
+/**
+ * free_obsolete_cnodes - free obsolete cnodes for commit end.
+ * @c: UBIFS file-system description object
+ */
+static void free_obsolete_cnodes(struct ubifs_info *c)
+{
+	struct ubifs_cnode *cnode, *cnext;
+
+	cnext = c->lpt_cnext;
+	if (!cnext)
+		return;
+	do {
+		cnode = cnext;
+		cnext = cnode->cnext;
+		if (test_bit(OBSOLETE_CNODE, &cnode->flags))
+			kfree(cnode);
+		else
+			cnode->cnext = NULL;
+	} while (cnext != c->lpt_cnext);
+	c->lpt_cnext = NULL;
+}
+
+/**
+ * first_nnode - find the first nnode in memory.
+ * @c: UBIFS file-system description object
+ * @hght: height of tree where nnode found is returned here
+ *
+ * This function returns a pointer to the nnode found or %NULL if no nnode is
+ * found. This function is a helper to 'ubifs_lpt_free()'.
+ */
+static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
+{
+	struct ubifs_nnode *nnode;
+	int h, i, found;
+
+	nnode = c->nroot;
+	*hght = 0;
+	if (!nnode)
+		return NULL;
+	for (h = 1; h < c->lpt_hght; h++) {
+		found = 0;
+		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+			if (nnode->nbranch[i].nnode) {
+				found = 1;
+				nnode = nnode->nbranch[i].nnode;
+				*hght = h;
+				break;
+			}
+		}
+		if (!found)
+			break;
+	}
+	return nnode;
+}
+
+/**
+ * next_nnode - find the next nnode in memory.
+ * @c: UBIFS file-system description object
+ * @nnode: nnode from which to start.
+ * @hght: height of tree where nnode is, is passed and returned here
+ *
+ * This function returns a pointer to the nnode found or %NULL if no nnode is
+ * found. This function is a helper to 'ubifs_lpt_free()'.
+ */
+static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
+				      struct ubifs_nnode *nnode, int *hght)
+{
+	struct ubifs_nnode *parent;
+	int iip, h, i, found;
+
+	parent = nnode->parent;
+	if (!parent)
+		return NULL;
+	if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
+		*hght -= 1;
+		return parent;
+	}
+	for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
+		nnode = parent->nbranch[iip].nnode;
+		if (nnode)
+			break;
+	}
+	if (!nnode) {
+		*hght -= 1;
+		return parent;
+	}
+	for (h = *hght + 1; h < c->lpt_hght; h++) {
+		found = 0;
+		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+			if (nnode->nbranch[i].nnode) {
+				found = 1;
+				nnode = nnode->nbranch[i].nnode;
+				*hght = h;
+				break;
+			}
+		}
+		if (!found)
+			break;
+	}
+	return nnode;
+}
+
+/**
+ * ubifs_lpt_free - free resources owned by the LPT.
+ * @c: UBIFS file-system description object
+ * @wr_only: free only resources used for writing
+ */
+void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
+{
+	struct ubifs_nnode *nnode;
+	int i, hght;
+
+	/* Free write-only things first */
+
+	free_obsolete_cnodes(c); /* Leftover from a failed commit */
+
+	vfree(c->ltab_cmt);
+	c->ltab_cmt = NULL;
+	vfree(c->lpt_buf);
+	c->lpt_buf = NULL;
+	kfree(c->lsave);
+	c->lsave = NULL;
+
+	if (wr_only)
+		return;
+
+	/* Now free the rest */
+
+	nnode = first_nnode(c, &hght);
+	while (nnode) {
+		for (i = 0; i < UBIFS_LPT_FANOUT; i++)
+			kfree(nnode->nbranch[i].nnode);
+		nnode = next_nnode(c, nnode, &hght);
+	}
+	for (i = 0; i < LPROPS_HEAP_CNT; i++)
+		kfree(c->lpt_heap[i].arr);
+	kfree(c->dirty_idx.arr);
+	kfree(c->nroot);
+	vfree(c->ltab);
+	kfree(c->lpt_nod_buf);
+}
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
new file mode 100644
index 0000000..3f2926e
--- /dev/null
+++ b/fs/ubifs/master.c
@@ -0,0 +1,341 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/* This file implements reading and writing the master node */
+
+#include "ubifs.h"
+
+/**
+ * scan_for_master - search the valid master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the master node LEBs and search for the latest master
+ * node. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int scan_for_master(struct ubifs_info *c)
+{
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	int lnum, offs = 0, nodes_cnt;
+
+	lnum = UBIFS_MST_LNUM;
+
+	sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+	nodes_cnt = sleb->nodes_cnt;
+	if (nodes_cnt > 0) {
+		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+				  list);
+		if (snod->type != UBIFS_MST_NODE)
+			goto out;
+		memcpy(c->mst_node, snod->node, snod->len);
+		offs = snod->offs;
+	}
+	ubifs_scan_destroy(sleb);
+
+	lnum += 1;
+
+	sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+	if (sleb->nodes_cnt != nodes_cnt)
+		goto out;
+	if (!sleb->nodes_cnt)
+		goto out;
+	snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
+	if (snod->type != UBIFS_MST_NODE)
+		goto out;
+	if (snod->offs != offs)
+		goto out;
+	if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
+		   (void *)snod->node + UBIFS_CH_SZ,
+		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+		goto out;
+	c->mst_offs = offs;
+	ubifs_scan_destroy(sleb);
+	return 0;
+
+out:
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+}
+
+/**
+ * validate_master - validate master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function validates data which was read from master node. Returns zero
+ * if the data is all right and %-EINVAL if not.
+ */
+static int validate_master(const struct ubifs_info *c)
+{
+	long long main_sz;
+	int err;
+
+	if (c->max_sqnum >= SQNUM_WATERMARK) {
+		err = 1;
+		goto out;
+	}
+
+	if (c->cmt_no >= c->max_sqnum) {
+		err = 2;
+		goto out;
+	}
+
+	if (c->highest_inum >= INUM_WATERMARK) {
+		err = 3;
+		goto out;
+	}
+
+	if (c->lhead_lnum < UBIFS_LOG_LNUM ||
+	    c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
+	    c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
+	    c->lhead_offs & (c->min_io_size - 1)) {
+		err = 4;
+		goto out;
+	}
+
+	if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
+	    c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
+		err = 5;
+		goto out;
+	}
+
+	if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
+	    c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
+		err = 6;
+		goto out;
+	}
+
+	if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
+		err = 7;
+		goto out;
+	}
+
+	if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
+	    c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
+	    c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
+		err = 8;
+		goto out;
+	}
+
+	main_sz = (long long)c->main_lebs * c->leb_size;
+	if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
+		err = 9;
+		goto out;
+	}
+
+	if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
+	    c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
+		err = 10;
+		goto out;
+	}
+
+	if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
+	    c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
+	    c->nhead_offs > c->leb_size) {
+		err = 11;
+		goto out;
+	}
+
+	if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
+	    c->ltab_offs < 0 ||
+	    c->ltab_offs + c->ltab_sz > c->leb_size) {
+		err = 12;
+		goto out;
+	}
+
+	if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
+	    c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
+	    c->lsave_offs + c->lsave_sz > c->leb_size)) {
+		err = 13;
+		goto out;
+	}
+
+	if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
+		err = 14;
+		goto out;
+	}
+
+	if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
+		err = 15;
+		goto out;
+	}
+
+	if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
+		err = 16;
+		goto out;
+	}
+
+	if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
+	    c->lst.total_free & 7) {
+		err = 17;
+		goto out;
+	}
+
+	if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
+		err = 18;
+		goto out;
+	}
+
+	if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
+		err = 19;
+		goto out;
+	}
+
+	if (c->lst.total_free + c->lst.total_dirty +
+	    c->lst.total_used > main_sz) {
+		err = 20;
+		goto out;
+	}
+
+	if (c->lst.total_dead + c->lst.total_dark +
+	    c->lst.total_used + c->old_idx_sz > main_sz) {
+		err = 21;
+		goto out;
+	}
+
+	if (c->lst.total_dead < 0 ||
+	    c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
+	    c->lst.total_dead & 7) {
+		err = 22;
+		goto out;
+	}
+
+	if (c->lst.total_dark < 0 ||
+	    c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
+	    c->lst.total_dark & 7) {
+		err = 23;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
+	dbg_dump_node(c, c->mst_node);
+	return -EINVAL;
+}
+
+/**
+ * ubifs_read_master - read master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function finds and reads the master node during file-system mount. If
+ * the flash is empty, it creates default master node as well. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+int ubifs_read_master(struct ubifs_info *c)
+{
+	int err, old_leb_cnt;
+
+	c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
+	if (!c->mst_node)
+		return -ENOMEM;
+
+	err = scan_for_master(c);
+	if (err) {
+		err = ubifs_recover_master_node(c);
+		if (err)
+			/*
+			 * Note, we do not free 'c->mst_node' here because the
+			 * unmount routine will take care of this.
+			 */
+			return err;
+	}
+
+	/* Make sure that the recovery flag is clear */
+	c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
+
+	c->max_sqnum       = le64_to_cpu(c->mst_node->ch.sqnum);
+	c->highest_inum    = le64_to_cpu(c->mst_node->highest_inum);
+	c->cmt_no          = le64_to_cpu(c->mst_node->cmt_no);
+	c->zroot.lnum      = le32_to_cpu(c->mst_node->root_lnum);
+	c->zroot.offs      = le32_to_cpu(c->mst_node->root_offs);
+	c->zroot.len       = le32_to_cpu(c->mst_node->root_len);
+	c->lhead_lnum      = le32_to_cpu(c->mst_node->log_lnum);
+	c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
+	c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
+	c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
+	c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
+	c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
+	c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
+	c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
+	c->nhead_offs      = le32_to_cpu(c->mst_node->nhead_offs);
+	c->ltab_lnum       = le32_to_cpu(c->mst_node->ltab_lnum);
+	c->ltab_offs       = le32_to_cpu(c->mst_node->ltab_offs);
+	c->lsave_lnum      = le32_to_cpu(c->mst_node->lsave_lnum);
+	c->lsave_offs      = le32_to_cpu(c->mst_node->lsave_offs);
+	c->lscan_lnum      = le32_to_cpu(c->mst_node->lscan_lnum);
+	c->lst.empty_lebs  = le32_to_cpu(c->mst_node->empty_lebs);
+	c->lst.idx_lebs    = le32_to_cpu(c->mst_node->idx_lebs);
+	old_leb_cnt        = le32_to_cpu(c->mst_node->leb_cnt);
+	c->lst.total_free  = le64_to_cpu(c->mst_node->total_free);
+	c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
+	c->lst.total_used  = le64_to_cpu(c->mst_node->total_used);
+	c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
+	c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
+
+	c->calc_idx_sz = c->old_idx_sz;
+
+	if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
+		c->no_orphs = 1;
+
+	if (old_leb_cnt != c->leb_cnt) {
+		/* The file system has been resized */
+		int growth = c->leb_cnt - old_leb_cnt;
+
+		if (c->leb_cnt < old_leb_cnt ||
+		    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+			ubifs_err("bad leb_cnt on master node");
+			dbg_dump_node(c, c->mst_node);
+			return -EINVAL;
+		}
+
+		dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
+			old_leb_cnt, c->leb_cnt);
+		c->lst.empty_lebs += growth;
+		c->lst.total_free += growth * (long long)c->leb_size;
+		c->lst.total_dark += growth * (long long)c->dark_wm;
+
+		/*
+		 * Reflect changes back onto the master node. N.B. the master
+		 * node gets written immediately whenever mounting (or
+		 * remounting) in read-write mode, so we do not need to write it
+		 * here.
+		 */
+		c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
+		c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
+		c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
+		c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
+	}
+
+	err = validate_master(c);
+	if (err)
+		return err;
+
+	err = dbg_old_index_check_init(c, &c->zroot);
+
+	return err;
+}
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
new file mode 100644
index 0000000..b745d86
--- /dev/null
+++ b/fs/ubifs/misc.h
@@ -0,0 +1,310 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file contains miscellaneous helper functions.
+ */
+
+#ifndef __UBIFS_MISC_H__
+#define __UBIFS_MISC_H__
+
+/**
+ * ubifs_zn_dirty - check if znode is dirty.
+ * @znode: znode to check
+ *
+ * This helper function returns %1 if @znode is dirty and %0 otherwise.
+ */
+static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
+{
+	return !!test_bit(DIRTY_ZNODE, &znode->flags);
+}
+
+/**
+ * ubifs_wake_up_bgt - wake up background thread.
+ * @c: UBIFS file-system description object
+ */
+static inline void ubifs_wake_up_bgt(struct ubifs_info *c)
+{
+	if (c->bgt && !c->need_bgt) {
+		c->need_bgt = 1;
+		wake_up_process(c->bgt);
+	}
+}
+
+/**
+ * ubifs_tnc_find_child - find next child in znode.
+ * @znode: znode to search at
+ * @start: the zbranch index to start at
+ *
+ * This helper function looks for znode child starting at index @start. Returns
+ * the child or %NULL if no children were found.
+ */
+static inline struct ubifs_znode *
+ubifs_tnc_find_child(struct ubifs_znode *znode, int start)
+{
+	while (start < znode->child_cnt) {
+		if (znode->zbranch[start].znode)
+			return znode->zbranch[start].znode;
+		start += 1;
+	}
+
+	return NULL;
+}
+
+/**
+ * ubifs_inode - get UBIFS inode information by VFS 'struct inode' object.
+ * @inode: the VFS 'struct inode' pointer
+ */
+static inline struct ubifs_inode *ubifs_inode(const struct inode *inode)
+{
+	return container_of(inode, struct ubifs_inode, vfs_inode);
+}
+
+/**
+ * ubifs_compr_present - check if compressor was compiled in.
+ * @compr_type: compressor type to check
+ *
+ * This function returns %1 of compressor of type @compr_type is present, and
+ * %0 if not.
+ */
+static inline int ubifs_compr_present(int compr_type)
+{
+	ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+	return !!ubifs_compressors[compr_type]->capi_name;
+}
+
+/**
+ * ubifs_compr_name - get compressor name string by its type.
+ * @compr_type: compressor type
+ *
+ * This function returns compressor type string.
+ */
+static inline const char *ubifs_compr_name(int compr_type)
+{
+	ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+	return ubifs_compressors[compr_type]->name;
+}
+
+/**
+ * ubifs_wbuf_sync - synchronize write-buffer.
+ * @wbuf: write-buffer to synchronize
+ *
+ * This is the same as as 'ubifs_wbuf_sync_nolock()' but it does not assume
+ * that the write-buffer is already locked.
+ */
+static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
+{
+	int err;
+
+	mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
+	err = ubifs_wbuf_sync_nolock(wbuf);
+	mutex_unlock(&wbuf->io_mutex);
+	return err;
+}
+
+/**
+ * ubifs_leb_unmap - unmap an LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to unmap
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
+{
+	int err;
+
+	if (c->ro_media)
+		return -EROFS;
+	err = ubi_leb_unmap(c->ubi, lnum);
+	if (err) {
+		ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ubifs_leb_write - write to a LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to write
+ * @buf: buffer to write from
+ * @offs: offset within LEB to write to
+ * @len: length to write
+ * @dtype: data type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
+				  const void *buf, int offs, int len, int dtype)
+{
+	int err;
+
+	if (c->ro_media)
+		return -EROFS;
+	err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+	if (err) {
+		ubifs_err("writing %d bytes at %d:%d, error %d",
+			  len, lnum, offs, err);
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ubifs_leb_change - atomic LEB change.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number to write
+ * @buf: buffer to write from
+ * @len: length to write
+ * @dtype: data type
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
+				   const void *buf, int len, int dtype)
+{
+	int err;
+
+	if (c->ro_media)
+		return -EROFS;
+	err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+	if (err) {
+		ubifs_err("changing %d bytes in LEB %d, error %d",
+			  len, lnum, err);
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ubifs_add_dirt - add dirty space to LEB properties.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to add dirty space for
+ * @dirty: dirty space to add
+ *
+ * This is a helper function which increased amount of dirty LEB space. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
+{
+	return ubifs_update_one_lp(c, lnum, LPROPS_NC, dirty, 0, 0);
+}
+
+/**
+ * ubifs_return_leb - return LEB to lprops.
+ * @c: the UBIFS file-system description object
+ * @lnum: LEB to return
+ *
+ * This helper function cleans the "taken" flag of a logical eraseblock in the
+ * lprops. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
+{
+	return ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+				   LPROPS_TAKEN, 0);
+}
+
+/**
+ * ubifs_idx_node_sz - return index node size.
+ * @c: the UBIFS file-system description object
+ * @child_cnt: number of children of this index node
+ */
+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
+{
+	return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+}
+
+/**
+ * ubifs_idx_branch - return pointer to an index branch.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ * @bnum: branch number
+ */
+static inline
+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
+				      const struct ubifs_idx_node *idx,
+				      int bnum)
+{
+	return (struct ubifs_branch *)((void *)idx->branches +
+				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+}
+
+/**
+ * ubifs_idx_key - return pointer to an index key.
+ * @c: the UBIFS file-system description object
+ * @idx: index node
+ */
+static inline void *ubifs_idx_key(const struct ubifs_info *c,
+				  const struct ubifs_idx_node *idx)
+{
+	return (void *)((struct ubifs_branch *)idx->branches)->key;
+}
+
+/**
+ * ubifs_tnc_lookup - look up a file-system node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure.
+ */
+static inline int ubifs_tnc_lookup(struct ubifs_info *c,
+				   const union ubifs_key *key, void *node)
+{
+	return ubifs_tnc_locate(c, key, node, NULL, NULL);
+}
+
+/**
+ * ubifs_get_lprops - get reference to LEB properties.
+ * @c: the UBIFS file-system description object
+ *
+ * This function locks lprops. Lprops have to be unlocked by
+ * 'ubifs_release_lprops()'.
+ */
+static inline void ubifs_get_lprops(struct ubifs_info *c)
+{
+	mutex_lock(&c->lp_mutex);
+}
+
+/**
+ * ubifs_release_lprops - release lprops lock.
+ * @c: the UBIFS file-system description object
+ *
+ * This function has to be called after each 'ubifs_get_lprops()' call to
+ * unlock lprops.
+ */
+static inline void ubifs_release_lprops(struct ubifs_info *c)
+{
+	ubifs_assert(mutex_is_locked(&c->lp_mutex));
+	ubifs_assert(c->lst.empty_lebs >= 0 &&
+		     c->lst.empty_lebs <= c->main_lebs);
+	mutex_unlock(&c->lp_mutex);
+}
+
+#endif /* __UBIFS_MISC_H__ */
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
new file mode 100644
index 0000000..d091031
--- /dev/null
+++ b/fs/ubifs/orphan.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include "ubifs.h"
+
+/*
+ * An orphan is an inode number whose inode node has been committed to the index
+ * with a link count of zero. That happens when an open file is deleted
+ * (unlinked) and then a commit is run. In the normal course of events the inode
+ * would be deleted when the file is closed. However in the case of an unclean
+ * unmount, orphans need to be accounted for. After an unclean unmount, the
+ * orphans' inodes must be deleted which means either scanning the entire index
+ * looking for them, or keeping a list on flash somewhere. This unit implements
+ * the latter approach.
+ *
+ * The orphan area is a fixed number of LEBs situated between the LPT area and
+ * the main area. The number of orphan area LEBs is specified when the file
+ * system is created. The minimum number is 1. The size of the orphan area
+ * should be so that it can hold the maximum number of orphans that are expected
+ * to ever exist at one time.
+ *
+ * The number of orphans that can fit in a LEB is:
+ *
+ *         (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)
+ *
+ * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough.
+ *
+ * Orphans are accumulated in a rb-tree. When an inode's link count drops to
+ * zero, the inode number is added to the rb-tree. It is removed from the tree
+ * when the inode is deleted.  Any new orphans that are in the orphan tree when
+ * the commit is run, are written to the orphan area in 1 or more orphan nodes.
+ * If the orphan area is full, it is consolidated to make space.  There is
+ * always enough space because validation prevents the user from creating more
+ * than the maximum number of orphans allowed.
+ */
+
+/**
+ * tot_avail_orphs - calculate total space.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the number of orphans that can be written in half
+ * the total space. That leaves half the space for adding new orphans.
+ */
+static int tot_avail_orphs(struct ubifs_info *c)
+{
+	int avail_lebs, avail;
+
+	avail_lebs = c->orph_lebs;
+	avail = avail_lebs *
+	       ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
+	return avail / 2;
+}
+
+/**
+ * ubifs_clear_orphans - erase all LEBs used for orphans.
+ * @c: UBIFS file-system description object
+ *
+ * If recovery is not required, then the orphans from the previous session
+ * are not needed. This function locates the LEBs used to record
+ * orphans, and un-maps them.
+ */
+int ubifs_clear_orphans(struct ubifs_info *c)
+{
+	int lnum, err;
+
+	for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+		err = ubifs_leb_unmap(c, lnum);
+		if (err)
+			return err;
+	}
+	c->ohead_lnum = c->orph_first;
+	c->ohead_offs = 0;
+	return 0;
+}
+
+/**
+ * insert_dead_orphan - insert an orphan.
+ * @c: UBIFS file-system description object
+ * @inum: orphan inode number
+ *
+ * This function is a helper to the 'do_kill_orphans()' function. The orphan
+ * must be kept until the next commit, so it is added to the rb-tree and the
+ * deletion list.
+ */
+static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
+{
+	struct ubifs_orphan *orphan, *o;
+	struct rb_node **p, *parent = NULL;
+
+	orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL);
+	if (!orphan)
+		return -ENOMEM;
+	orphan->inum = inum;
+
+	p = &c->orph_tree.rb_node;
+	while (*p) {
+		parent = *p;
+		o = rb_entry(parent, struct ubifs_orphan, rb);
+		if (inum < o->inum)
+			p = &(*p)->rb_left;
+		else if (inum > o->inum)
+			p = &(*p)->rb_right;
+		else {
+			/* Already added - no problem */
+			kfree(orphan);
+			return 0;
+		}
+	}
+	c->tot_orphans += 1;
+	rb_link_node(&orphan->rb, parent, p);
+	rb_insert_color(&orphan->rb, &c->orph_tree);
+	list_add_tail(&orphan->list, &c->orph_list);
+	orphan->dnext = c->orph_dnext;
+	c->orph_dnext = orphan;
+	dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum,
+		c->new_orphans, c->tot_orphans);
+	return 0;
+}
+
+/**
+ * do_kill_orphans - remove orphan inodes from the index.
+ * @c: UBIFS file-system description object
+ * @sleb: scanned LEB
+ * @last_cmt_no: cmt_no of last orphan node read is passed and returned here
+ * @outofdate: whether the LEB is out of date is returned here
+ * @last_flagged: whether the end orphan node is encountered
+ *
+ * This function is a helper to the 'kill_orphans()' function. It goes through
+ * every orphan node in a LEB and for every inode number recorded, removes
+ * all keys for that inode from the TNC.
+ */
+static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+			   unsigned long long *last_cmt_no, int *outofdate,
+			   int *last_flagged)
+{
+	struct ubifs_scan_node *snod;
+	struct ubifs_orph_node *orph;
+	unsigned long long cmt_no;
+	ino_t inum;
+	int i, n, err, first = 1;
+
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		if (snod->type != UBIFS_ORPH_NODE) {
+			ubifs_err("invalid node type %d in orphan area at "
+				  "%d:%d", snod->type, sleb->lnum, snod->offs);
+			dbg_dump_node(c, snod->node);
+			return -EINVAL;
+		}
+
+		orph = snod->node;
+
+		/* Check commit number */
+		cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX;
+		/*
+		 * The commit number on the master node may be less, because
+		 * of a failed commit. If there are several failed commits in a
+		 * row, the commit number written on orphan nodes will continue
+		 * to increase (because the commit number is adjusted here) even
+		 * though the commit number on the master node stays the same
+		 * because the master node has not been re-written.
+		 */
+		if (cmt_no > c->cmt_no)
+			c->cmt_no = cmt_no;
+		if (cmt_no < *last_cmt_no && *last_flagged) {
+			/*
+			 * The last orphan node had a higher commit number and
+			 * was flagged as the last written for that commit
+			 * number. That makes this orphan node, out of date.
+			 */
+			if (!first) {
+				ubifs_err("out of order commit number %llu in "
+					  "orphan node at %d:%d",
+					  cmt_no, sleb->lnum, snod->offs);
+				dbg_dump_node(c, snod->node);
+				return -EINVAL;
+			}
+			dbg_rcvry("out of date LEB %d", sleb->lnum);
+			*outofdate = 1;
+			return 0;
+		}
+
+		if (first)
+			first = 0;
+
+		n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
+		for (i = 0; i < n; i++) {
+			inum = le64_to_cpu(orph->inos[i]);
+			dbg_rcvry("deleting orphaned inode %lu",
+				  (unsigned long)inum);
+			err = ubifs_tnc_remove_ino(c, inum);
+			if (err)
+				return err;
+			err = insert_dead_orphan(c, inum);
+			if (err)
+				return err;
+		}
+
+		*last_cmt_no = cmt_no;
+		if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) {
+			dbg_rcvry("last orph node for commit %llu at %d:%d",
+				  cmt_no, sleb->lnum, snod->offs);
+			*last_flagged = 1;
+		} else
+			*last_flagged = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * kill_orphans - remove all orphan inodes from the index.
+ * @c: UBIFS file-system description object
+ *
+ * If recovery is required, then orphan inodes recorded during the previous
+ * session (which ended with an unclean unmount) must be deleted from the index.
+ * This is done by updating the TNC, but since the index is not updated until
+ * the next commit, the LEBs where the orphan information is recorded are not
+ * erased until the next commit.
+ */
+static int kill_orphans(struct ubifs_info *c)
+{
+	unsigned long long last_cmt_no = 0;
+	int lnum, err = 0, outofdate = 0, last_flagged = 0;
+
+	c->ohead_lnum = c->orph_first;
+	c->ohead_offs = 0;
+	/* Check no-orphans flag and skip this if no orphans */
+	if (c->no_orphs) {
+		dbg_rcvry("no orphans");
+		return 0;
+	}
+	/*
+	 * Orph nodes always start at c->orph_first and are written to each
+	 * successive LEB in turn. Generally unused LEBs will have been unmapped
+	 * but may contain out of date orphan nodes if the unmap didn't go
+	 * through. In addition, the last orphan node written for each commit is
+	 * marked (top bit of orph->cmt_no is set to 1). It is possible that
+	 * there are orphan nodes from the next commit (i.e. the commit did not
+	 * complete successfully). In that case, no orphans will have been lost
+	 * due to the way that orphans are written, and any orphans added will
+	 * be valid orphans anyway and so can be deleted.
+	 */
+	for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+		struct ubifs_scan_leb *sleb;
+
+		dbg_rcvry("LEB %d", lnum);
+		sleb = ubifs_scan(c, lnum, 0, c->sbuf);
+		if (IS_ERR(sleb)) {
+			sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
+			if (IS_ERR(sleb)) {
+				err = PTR_ERR(sleb);
+				break;
+			}
+		}
+		err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate,
+				      &last_flagged);
+		if (err || outofdate) {
+			ubifs_scan_destroy(sleb);
+			break;
+		}
+		if (sleb->endpt) {
+			c->ohead_lnum = lnum;
+			c->ohead_offs = sleb->endpt;
+		}
+		ubifs_scan_destroy(sleb);
+	}
+	return err;
+}
+
+/**
+ * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them.
+ * @c: UBIFS file-system description object
+ * @unclean: indicates recovery from unclean unmount
+ * @read_only: indicates read only mount
+ *
+ * This function is called when mounting to erase orphans from the previous
+ * session. If UBIFS was not unmounted cleanly, then the inodes recorded as
+ * orphans are deleted.
+ */
+int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
+{
+	int err = 0;
+
+	c->max_orphans = tot_avail_orphs(c);
+
+	if (!read_only) {
+		c->orph_buf = vmalloc(c->leb_size);
+		if (!c->orph_buf)
+			return -ENOMEM;
+	}
+
+	if (unclean)
+		err = kill_orphans(c);
+	else if (!read_only)
+		err = ubifs_clear_orphans(c);
+
+	return err;
+}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
new file mode 100644
index 0000000..fe3b364
--- /dev/null
+++ b/fs/ubifs/recovery.c
@@ -0,0 +1,1249 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements functions needed to recover from unclean un-mounts.
+ * When UBIFS is mounted, it checks a flag on the master node to determine if
+ * an un-mount was completed sucessfully. If not, the process of mounting
+ * incorparates additional checking and fixing of on-flash data structures.
+ * UBIFS always cleans away all remnants of an unclean un-mount, so that
+ * errors do not accumulate. However UBIFS defers recovery if it is mounted
+ * read-only, and the flash is not modified in that case.
+ */
+
+#include "ubifs.h"
+
+/**
+ * is_empty - determine whether a buffer is empty (contains all 0xff).
+ * @buf: buffer to clean
+ * @len: length of buffer
+ *
+ * This function returns %1 if the buffer is empty (contains all 0xff) otherwise
+ * %0 is returned.
+ */
+static int is_empty(void *buf, int len)
+{
+	uint8_t *p = buf;
+	int i;
+
+	for (i = 0; i < len; i++)
+		if (*p++ != 0xff)
+			return 0;
+	return 1;
+}
+
+/**
+ * get_master_node - get the last valid master node allowing for corruption.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @pbuf: buffer containing the LEB read, is returned here
+ * @mst: master node, if found, is returned here
+ * @cor: corruption, if found, is returned here
+ *
+ * This function allocates a buffer, reads the LEB into it, and finds and
+ * returns the last valid master node allowing for one area of corruption.
+ * The corrupt area, if there is one, must be consistent with the assumption
+ * that it is the result of an unclean unmount while the master node was being
+ * written. Under those circumstances, it is valid to use the previously written
+ * master node.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
+			   struct ubifs_mst_node **mst, void **cor)
+{
+	const int sz = c->mst_node_alsz;
+	int err, offs, len;
+	void *sbuf, *buf;
+
+	sbuf = vmalloc(c->leb_size);
+	if (!sbuf)
+		return -ENOMEM;
+
+	err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
+	if (err && err != -EBADMSG)
+		goto out_free;
+
+	/* Find the first position that is definitely not a node */
+	offs = 0;
+	buf = sbuf;
+	len = c->leb_size;
+	while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) {
+		struct ubifs_ch *ch = buf;
+
+		if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
+			break;
+		offs += sz;
+		buf  += sz;
+		len  -= sz;
+	}
+	/* See if there was a valid master node before that */
+	if (offs) {
+		int ret;
+
+		offs -= sz;
+		buf  -= sz;
+		len  += sz;
+		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+		if (ret != SCANNED_A_NODE && offs) {
+			/* Could have been corruption so check one place back */
+			offs -= sz;
+			buf  -= sz;
+			len  += sz;
+			ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+			if (ret != SCANNED_A_NODE)
+				/*
+				 * We accept only one area of corruption because
+				 * we are assuming that it was caused while
+				 * trying to write a master node.
+				 */
+				goto out_err;
+		}
+		if (ret == SCANNED_A_NODE) {
+			struct ubifs_ch *ch = buf;
+
+			if (ch->node_type != UBIFS_MST_NODE)
+				goto out_err;
+			dbg_rcvry("found a master node at %d:%d", lnum, offs);
+			*mst = buf;
+			offs += sz;
+			buf  += sz;
+			len  -= sz;
+		}
+	}
+	/* Check for corruption */
+	if (offs < c->leb_size) {
+		if (!is_empty(buf, min_t(int, len, sz))) {
+			*cor = buf;
+			dbg_rcvry("found corruption at %d:%d", lnum, offs);
+		}
+		offs += sz;
+		buf  += sz;
+		len  -= sz;
+	}
+	/* Check remaining empty space */
+	if (offs < c->leb_size)
+		if (!is_empty(buf, len))
+			goto out_err;
+	*pbuf = sbuf;
+	return 0;
+
+out_err:
+	err = -EINVAL;
+out_free:
+	vfree(sbuf);
+	*mst = NULL;
+	*cor = NULL;
+	return err;
+}
+
+/**
+ * write_rcvrd_mst_node - write recovered master node.
+ * @c: UBIFS file-system description object
+ * @mst: master node
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int write_rcvrd_mst_node(struct ubifs_info *c,
+				struct ubifs_mst_node *mst)
+{
+	int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz;
+	__le32 save_flags;
+
+	dbg_rcvry("recovery");
+
+	save_flags = mst->flags;
+	mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
+
+	ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+	err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
+	if (err)
+		goto out;
+	err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
+	if (err)
+		goto out;
+out:
+	mst->flags = save_flags;
+	return err;
+}
+
+/**
+ * ubifs_recover_master_node - recover the master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function recovers the master node from corruption that may occur due to
+ * an unclean unmount.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_master_node(struct ubifs_info *c)
+{
+	void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL;
+	struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst;
+	const int sz = c->mst_node_alsz;
+	int err, offs1, offs2;
+
+	dbg_rcvry("recovery");
+
+	err = get_master_node(c, UBIFS_MST_LNUM, &buf1, &mst1, &cor1);
+	if (err)
+		goto out_free;
+
+	err = get_master_node(c, UBIFS_MST_LNUM + 1, &buf2, &mst2, &cor2);
+	if (err)
+		goto out_free;
+
+	if (mst1) {
+		offs1 = (void *)mst1 - buf1;
+		if ((le32_to_cpu(mst1->flags) & UBIFS_MST_RCVRY) &&
+		    (offs1 == 0 && !cor1)) {
+			/*
+			 * mst1 was written by recovery at offset 0 with no
+			 * corruption.
+			 */
+			dbg_rcvry("recovery recovery");
+			mst = mst1;
+		} else if (mst2) {
+			offs2 = (void *)mst2 - buf2;
+			if (offs1 == offs2) {
+				/* Same offset, so must be the same */
+				if (memcmp((void *)mst1 + UBIFS_CH_SZ,
+					   (void *)mst2 + UBIFS_CH_SZ,
+					   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+					goto out_err;
+				mst = mst1;
+			} else if (offs2 + sz == offs1) {
+				/* 1st LEB was written, 2nd was not */
+				if (cor1)
+					goto out_err;
+				mst = mst1;
+			} else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
+				/* 1st LEB was unmapped and written, 2nd not */
+				if (cor1)
+					goto out_err;
+				mst = mst1;
+			} else
+				goto out_err;
+		} else {
+			/*
+			 * 2nd LEB was unmapped and about to be written, so
+			 * there must be only one master node in the first LEB
+			 * and no corruption.
+			 */
+			if (offs1 != 0 || cor1)
+				goto out_err;
+			mst = mst1;
+		}
+	} else {
+		if (!mst2)
+			goto out_err;
+		/*
+		 * 1st LEB was unmapped and about to be written, so there must
+		 * be no room left in 2nd LEB.
+		 */
+		offs2 = (void *)mst2 - buf2;
+		if (offs2 + sz + sz <= c->leb_size)
+			goto out_err;
+		mst = mst2;
+	}
+
+	dbg_rcvry("recovered master node from LEB %d",
+		  (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1));
+
+	memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ);
+
+	if ((c->vfs_sb->s_flags & MS_RDONLY)) {
+		/* Read-only mode. Keep a copy for switching to rw mode */
+		c->rcvrd_mst_node = kmalloc(sz, GFP_KERNEL);
+		if (!c->rcvrd_mst_node) {
+			err = -ENOMEM;
+			goto out_free;
+		}
+		memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
+	}
+
+	vfree(buf2);
+	vfree(buf1);
+
+	return 0;
+
+out_err:
+	err = -EINVAL;
+out_free:
+	ubifs_err("failed to recover master node");
+	if (mst1) {
+		dbg_err("dumping first master node");
+		dbg_dump_node(c, mst1);
+	}
+	if (mst2) {
+		dbg_err("dumping second master node");
+		dbg_dump_node(c, mst2);
+	}
+	vfree(buf2);
+	vfree(buf1);
+	return err;
+}
+
+/**
+ * ubifs_write_rcvrd_mst_node - write the recovered master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function writes the master node that was recovered during mounting in
+ * read-only mode and must now be written because we are remounting rw.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+{
+	int err;
+
+	if (!c->rcvrd_mst_node)
+		return 0;
+	c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+	c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+	err = write_rcvrd_mst_node(c, c->rcvrd_mst_node);
+	if (err)
+		return err;
+	kfree(c->rcvrd_mst_node);
+	c->rcvrd_mst_node = NULL;
+	return 0;
+}
+
+/**
+ * is_last_write - determine if an offset was in the last write to a LEB.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to check
+ * @offs: offset to check
+ *
+ * This function returns %1 if @offs was in the last write to the LEB whose data
+ * is in @buf, otherwise %0 is returned.  The determination is made by checking
+ * for subsequent empty space starting from the next min_io_size boundary (or a
+ * bit less than the common header size if min_io_size is one).
+ */
+static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+{
+	int empty_offs;
+	int check_len;
+	uint8_t *p;
+
+	if (c->min_io_size == 1) {
+		check_len = c->leb_size - offs;
+		p = buf + check_len;
+		for (; check_len > 0; check_len--)
+			if (*--p != 0xff)
+				break;
+		/*
+		 * 'check_len' is the size of the corruption which cannot be
+		 * more than the size of 1 node if it was caused by an unclean
+		 * unmount.
+		 */
+		if (check_len > UBIFS_MAX_NODE_SZ)
+			return 0;
+		return 1;
+	}
+
+	/*
+	 * Round up to the next c->min_io_size boundary i.e. 'offs' is in the
+	 * last wbuf written. After that should be empty space.
+	 */
+	empty_offs = ALIGN(offs + 1, c->min_io_size);
+	check_len = c->leb_size - empty_offs;
+	p = buf + empty_offs - offs;
+
+	for (; check_len > 0; check_len--)
+		if (*p++ != 0xff)
+			return 0;
+	return 1;
+}
+
+/**
+ * clean_buf - clean the data from an LEB sitting in a buffer.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to clean
+ * @lnum: LEB number to clean
+ * @offs: offset from which to clean
+ * @len: length of buffer
+ *
+ * This function pads up to the next min_io_size boundary (if there is one) and
+ * sets empty space to all 0xff. @buf, @offs and @len are updated to the next
+ * min_io_size boundary (if there is one).
+ */
+static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
+		      int *offs, int *len)
+{
+	int empty_offs, pad_len;
+
+	lnum = lnum;
+	dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs);
+
+	if (c->min_io_size == 1) {
+		memset(*buf, 0xff, c->leb_size - *offs);
+		return;
+	}
+
+	ubifs_assert(!(*offs & 7));
+	empty_offs = ALIGN(*offs, c->min_io_size);
+	pad_len = empty_offs - *offs;
+	ubifs_pad(c, *buf, pad_len);
+	*offs += pad_len;
+	*buf += pad_len;
+	*len -= pad_len;
+	memset(*buf, 0xff, c->leb_size - empty_offs);
+}
+
+/**
+ * no_more_nodes - determine if there are no more nodes in a buffer.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to check
+ * @len: length of buffer
+ * @lnum: LEB number of the LEB from which @buf was read
+ * @offs: offset from which @buf was read
+ *
+ * This function scans @buf for more nodes and returns %0 is a node is found and
+ * %1 if no more nodes are found.
+ */
+static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+			int lnum, int offs)
+{
+	int skip, next_offs = 0;
+
+	if (len > UBIFS_DATA_NODE_SZ) {
+		struct ubifs_ch *ch = buf;
+		int dlen = le32_to_cpu(ch->len);
+
+		if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ &&
+		    dlen <= UBIFS_MAX_DATA_NODE_SZ)
+			/* The corrupt node looks like a data node */
+			next_offs = ALIGN(offs + dlen, 8);
+	}
+
+	if (c->min_io_size == 1)
+		skip = 8;
+	else
+		skip = ALIGN(offs + 1, c->min_io_size) - offs;
+
+	offs += skip;
+	buf += skip;
+	len -= skip;
+	while (len > 8) {
+		struct ubifs_ch *ch = buf;
+		uint32_t magic = le32_to_cpu(ch->magic);
+		int ret;
+
+		if (magic == UBIFS_NODE_MAGIC) {
+			ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+			if (ret == SCANNED_A_NODE || ret > 0) {
+				/*
+				 * There is a small chance this is just data in
+				 * a data node, so check that possibility. e.g.
+				 * this is part of a file that itself contains
+				 * a UBIFS image.
+				 */
+				if (next_offs && offs + le32_to_cpu(ch->len) <=
+				    next_offs)
+					continue;
+				dbg_rcvry("unexpected node at %d:%d", lnum,
+					  offs);
+				return 0;
+			}
+		}
+		offs += 8;
+		buf += 8;
+		len -= 8;
+	}
+	return 1;
+}
+
+/**
+ * fix_unclean_leb - fix an unclean LEB.
+ * @c: UBIFS file-system description object
+ * @sleb: scanned LEB information
+ * @start: offset where scan started
+ */
+static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+			   int start)
+{
+	int lnum = sleb->lnum, endpt = start;
+
+	/* Get the end offset of the last node we are keeping */
+	if (!list_empty(&sleb->nodes)) {
+		struct ubifs_scan_node *snod;
+
+		snod = list_entry(sleb->nodes.prev,
+				  struct ubifs_scan_node, list);
+		endpt = snod->offs + snod->len;
+	}
+
+	if ((c->vfs_sb->s_flags & MS_RDONLY) && !c->remounting_rw) {
+		/* Add to recovery list */
+		struct ubifs_unclean_leb *ucleb;
+
+		dbg_rcvry("need to fix LEB %d start %d endpt %d",
+			  lnum, start, sleb->endpt);
+		ucleb = kzalloc(sizeof(struct ubifs_unclean_leb), GFP_NOFS);
+		if (!ucleb)
+			return -ENOMEM;
+		ucleb->lnum = lnum;
+		ucleb->endpt = endpt;
+		list_add_tail(&ucleb->list, &c->unclean_leb_list);
+	}
+	return 0;
+}
+
+/**
+ * drop_incomplete_group - drop nodes from an incomplete group.
+ * @sleb: scanned LEB information
+ * @offs: offset of dropped nodes is returned here
+ *
+ * This function returns %1 if nodes are dropped and %0 otherwise.
+ */
+static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+{
+	int dropped = 0;
+
+	while (!list_empty(&sleb->nodes)) {
+		struct ubifs_scan_node *snod;
+		struct ubifs_ch *ch;
+
+		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+				  list);
+		ch = snod->node;
+		if (ch->group_type != UBIFS_IN_NODE_GROUP)
+			return dropped;
+		dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
+		*offs = snod->offs;
+		list_del(&snod->list);
+		kfree(snod);
+		sleb->nodes_cnt -= 1;
+		dropped = 1;
+	}
+	return dropped;
+}
+
+/**
+ * ubifs_recover_leb - scan and recover a LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @offs: offset
+ * @sbuf: LEB-sized buffer to use
+ * @grouped: nodes may be grouped for recovery
+ *
+ * This function does a scan of a LEB, but caters for errors that might have
+ * been caused by the unclean unmount from which we are attempting to recover.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+					 int offs, void *sbuf, int grouped)
+{
+	int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
+	int empty_chkd = 0, start = offs;
+	struct ubifs_scan_leb *sleb;
+	void *buf = sbuf + offs;
+
+	dbg_rcvry("%d:%d", lnum, offs);
+
+	sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+	if (IS_ERR(sleb))
+		return sleb;
+
+	if (sleb->ecc)
+		need_clean = 1;
+
+	while (len >= 8) {
+		int ret;
+
+		dbg_scan("look at LEB %d:%d (%d bytes left)",
+			 lnum, offs, len);
+
+		cond_resched();
+
+		/*
+		 * Scan quietly until there is an error from which we cannot
+		 * recover
+		 */
+		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+
+		if (ret == SCANNED_A_NODE) {
+			/* A valid node, and not a padding node */
+			struct ubifs_ch *ch = buf;
+			int node_len;
+
+			err = ubifs_add_snod(c, sleb, buf, offs);
+			if (err)
+				goto error;
+			node_len = ALIGN(le32_to_cpu(ch->len), 8);
+			offs += node_len;
+			buf += node_len;
+			len -= node_len;
+			continue;
+		}
+
+		if (ret > 0) {
+			/* Padding bytes or a valid padding node */
+			offs += ret;
+			buf += ret;
+			len -= ret;
+			continue;
+		}
+
+		if (ret == SCANNED_EMPTY_SPACE) {
+			if (!is_empty(buf, len)) {
+				if (!is_last_write(c, buf, offs))
+					break;
+				clean_buf(c, &buf, lnum, &offs, &len);
+				need_clean = 1;
+			}
+			empty_chkd = 1;
+			break;
+		}
+
+		if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
+			if (is_last_write(c, buf, offs)) {
+				clean_buf(c, &buf, lnum, &offs, &len);
+				need_clean = 1;
+				empty_chkd = 1;
+				break;
+			}
+
+		if (ret == SCANNED_A_CORRUPT_NODE)
+			if (no_more_nodes(c, buf, len, lnum, offs)) {
+				clean_buf(c, &buf, lnum, &offs, &len);
+				need_clean = 1;
+				empty_chkd = 1;
+				break;
+			}
+
+		if (quiet) {
+			/* Redo the last scan but noisily */
+			quiet = 0;
+			continue;
+		}
+
+		switch (ret) {
+		case SCANNED_GARBAGE:
+			dbg_err("garbage");
+			goto corrupted;
+		case SCANNED_A_CORRUPT_NODE:
+		case SCANNED_A_BAD_PAD_NODE:
+			dbg_err("bad node");
+			goto corrupted;
+		default:
+			dbg_err("unknown");
+			goto corrupted;
+		}
+	}
+
+	if (!empty_chkd && !is_empty(buf, len)) {
+		if (is_last_write(c, buf, offs)) {
+			clean_buf(c, &buf, lnum, &offs, &len);
+			need_clean = 1;
+		} else {
+			ubifs_err("corrupt empty space at LEB %d:%d",
+				  lnum, offs);
+			goto corrupted;
+		}
+	}
+
+	/* Drop nodes from incomplete group */
+	if (grouped && drop_incomplete_group(sleb, &offs)) {
+		buf = sbuf + offs;
+		len = c->leb_size - offs;
+		clean_buf(c, &buf, lnum, &offs, &len);
+		need_clean = 1;
+	}
+
+	if (offs % c->min_io_size) {
+		clean_buf(c, &buf, lnum, &offs, &len);
+		need_clean = 1;
+	}
+
+	ubifs_end_scan(c, sleb, lnum, offs);
+
+	if (need_clean) {
+		err = fix_unclean_leb(c, sleb, start);
+		if (err)
+			goto error;
+	}
+
+	return sleb;
+
+corrupted:
+	ubifs_scanned_corruption(c, lnum, offs, buf);
+	err = -EUCLEAN;
+error:
+	ubifs_err("LEB %d scanning failed", lnum);
+	ubifs_scan_destroy(sleb);
+	return ERR_PTR(err);
+}
+
+/**
+ * get_cs_sqnum - get commit start sequence number.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of commit start node
+ * @offs: offset of commit start node
+ * @cs_sqnum: commit start sequence number is returned here
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
+			unsigned long long *cs_sqnum)
+{
+	struct ubifs_cs_node *cs_node = NULL;
+	int err, ret;
+
+	dbg_rcvry("at %d:%d", lnum, offs);
+	cs_node = kmalloc(UBIFS_CS_NODE_SZ, GFP_KERNEL);
+	if (!cs_node)
+		return -ENOMEM;
+	if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
+		goto out_err;
+	err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
+	if (err && err != -EBADMSG)
+		goto out_free;
+	ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
+	if (ret != SCANNED_A_NODE) {
+		dbg_err("Not a valid node");
+		goto out_err;
+	}
+	if (cs_node->ch.node_type != UBIFS_CS_NODE) {
+		dbg_err("Node a CS node, type is %d", cs_node->ch.node_type);
+		goto out_err;
+	}
+	if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
+		dbg_err("CS node cmt_no %llu != current cmt_no %llu",
+			(unsigned long long)le64_to_cpu(cs_node->cmt_no),
+			c->cmt_no);
+		goto out_err;
+	}
+	*cs_sqnum = le64_to_cpu(cs_node->ch.sqnum);
+	dbg_rcvry("commit start sqnum %llu", *cs_sqnum);
+	kfree(cs_node);
+	return 0;
+
+out_err:
+	err = -EINVAL;
+out_free:
+	ubifs_err("failed to get CS sqnum");
+	kfree(cs_node);
+	return err;
+}
+
+/**
+ * ubifs_recover_log_leb - scan and recover a log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @offs: offset
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function does a scan of a LEB, but caters for errors that might have
+ * been caused by the unclean unmount from which we are attempting to recover.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+					     int offs, void *sbuf)
+{
+	struct ubifs_scan_leb *sleb;
+	int next_lnum;
+
+	dbg_rcvry("LEB %d", lnum);
+	next_lnum = lnum + 1;
+	if (next_lnum >= UBIFS_LOG_LNUM + c->log_lebs)
+		next_lnum = UBIFS_LOG_LNUM;
+	if (next_lnum != c->ltail_lnum) {
+		/*
+		 * We can only recover at the end of the log, so check that the
+		 * next log LEB is empty or out of date.
+		 */
+		sleb = ubifs_scan(c, next_lnum, 0, sbuf);
+		if (IS_ERR(sleb))
+			return sleb;
+		if (sleb->nodes_cnt) {
+			struct ubifs_scan_node *snod;
+			unsigned long long cs_sqnum = c->cs_sqnum;
+
+			snod = list_entry(sleb->nodes.next,
+					  struct ubifs_scan_node, list);
+			if (cs_sqnum == 0) {
+				int err;
+
+				err = get_cs_sqnum(c, lnum, offs, &cs_sqnum);
+				if (err) {
+					ubifs_scan_destroy(sleb);
+					return ERR_PTR(err);
+				}
+			}
+			if (snod->sqnum > cs_sqnum) {
+				ubifs_err("unrecoverable log corruption "
+					  "in LEB %d", lnum);
+				ubifs_scan_destroy(sleb);
+				return ERR_PTR(-EUCLEAN);
+			}
+		}
+		ubifs_scan_destroy(sleb);
+	}
+	return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
+}
+
+/**
+ * recover_head - recover a head.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of head to recover
+ * @offs: offset of head to recover
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function ensures that there is no data on the flash at a head location.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+			void *sbuf)
+{
+	int len, err, need_clean = 0;
+
+	if (c->min_io_size > 1)
+		len = c->min_io_size;
+	else
+		len = 512;
+	if (offs + len > c->leb_size)
+		len = c->leb_size - offs;
+
+	if (!len)
+		return 0;
+
+	/* Read at the head location and check it is empty flash */
+	err = ubi_read(c->ubi, lnum, sbuf, offs, len);
+	if (err)
+		need_clean = 1;
+	else {
+		uint8_t *p = sbuf;
+
+		while (len--)
+			if (*p++ != 0xff) {
+				need_clean = 1;
+				break;
+			}
+	}
+
+	if (need_clean) {
+		dbg_rcvry("cleaning head at %d:%d", lnum, offs);
+		if (offs == 0)
+			return ubifs_leb_unmap(c, lnum);
+		err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
+		if (err)
+			return err;
+		return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
+	}
+
+	return 0;
+}
+
+/**
+ * ubifs_recover_inl_heads - recover index and LPT heads.
+ * @c: UBIFS file-system description object
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function ensures that there is no data on the flash at the index and
+ * LPT head locations.
+ *
+ * This deals with the recovery of a half-completed journal commit. UBIFS is
+ * careful never to overwrite the last version of the index or the LPT. Because
+ * the index and LPT are wandering trees, data from a half-completed commit will
+ * not be referenced anywhere in UBIFS. The data will be either in LEBs that are
+ * assumed to be empty and will be unmapped anyway before use, or in the index
+ * and LPT heads.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+{
+	int err;
+
+	ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY) || c->remounting_rw);
+
+	dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs);
+	err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf);
+	if (err)
+		return err;
+
+	dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs);
+	err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/**
+ *  clean_an_unclean_leb - read and write a LEB to remove corruption.
+ * @c: UBIFS file-system description object
+ * @ucleb: unclean LEB information
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function reads a LEB up to a point pre-determined by the mount recovery,
+ * checks the nodes, and writes the result back to the flash, thereby cleaning
+ * off any following corruption, or non-fatal ECC errors.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int clean_an_unclean_leb(const struct ubifs_info *c,
+				struct ubifs_unclean_leb *ucleb, void *sbuf)
+{
+	int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
+	void *buf = sbuf;
+
+	dbg_rcvry("LEB %d len %d", lnum, len);
+
+	if (len == 0) {
+		/* Nothing to read, just unmap it */
+		err = ubifs_leb_unmap(c, lnum);
+		if (err)
+			return err;
+		return 0;
+	}
+
+	err = ubi_read(c->ubi, lnum, buf, offs, len);
+	if (err && err != -EBADMSG)
+		return err;
+
+	while (len >= 8) {
+		int ret;
+
+		cond_resched();
+
+		/* Scan quietly until there is an error */
+		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+
+		if (ret == SCANNED_A_NODE) {
+			/* A valid node, and not a padding node */
+			struct ubifs_ch *ch = buf;
+			int node_len;
+
+			node_len = ALIGN(le32_to_cpu(ch->len), 8);
+			offs += node_len;
+			buf += node_len;
+			len -= node_len;
+			continue;
+		}
+
+		if (ret > 0) {
+			/* Padding bytes or a valid padding node */
+			offs += ret;
+			buf += ret;
+			len -= ret;
+			continue;
+		}
+
+		if (ret == SCANNED_EMPTY_SPACE) {
+			ubifs_err("unexpected empty space at %d:%d",
+				  lnum, offs);
+			return -EUCLEAN;
+		}
+
+		if (quiet) {
+			/* Redo the last scan but noisily */
+			quiet = 0;
+			continue;
+		}
+
+		ubifs_scanned_corruption(c, lnum, offs, buf);
+		return -EUCLEAN;
+	}
+
+	/* Pad to min_io_size */
+	len = ALIGN(ucleb->endpt, c->min_io_size);
+	if (len > ucleb->endpt) {
+		int pad_len = len - ALIGN(ucleb->endpt, 8);
+
+		if (pad_len > 0) {
+			buf = c->sbuf + len - pad_len;
+			ubifs_pad(c, buf, pad_len);
+		}
+	}
+
+	/* Write back the LEB atomically */
+	err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
+	if (err)
+		return err;
+
+	dbg_rcvry("cleaned LEB %d", lnum);
+
+	return 0;
+}
+
+/**
+ * ubifs_clean_lebs - clean LEBs recovered during read-only mount.
+ * @c: UBIFS file-system description object
+ * @sbuf: LEB-sized buffer to use
+ *
+ * This function cleans a LEB identified during recovery that needs to be
+ * written but was not because UBIFS was mounted read-only. This happens when
+ * remounting to read-write mode.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
+{
+	dbg_rcvry("recovery");
+	while (!list_empty(&c->unclean_leb_list)) {
+		struct ubifs_unclean_leb *ucleb;
+		int err;
+
+		ucleb = list_entry(c->unclean_leb_list.next,
+				   struct ubifs_unclean_leb, list);
+		err = clean_an_unclean_leb(c, ucleb, sbuf);
+		if (err)
+			return err;
+		list_del(&ucleb->list);
+		kfree(ucleb);
+	}
+	return 0;
+}
+
+/**
+ * struct size_entry - inode size information for recovery.
+ * @rb: link in the RB-tree of sizes
+ * @inum: inode number
+ * @i_size: size on inode
+ * @d_size: maximum size based on data nodes
+ * @exists: indicates whether the inode exists
+ * @inode: inode if pinned in memory awaiting rw mode to fix it
+ */
+struct size_entry {
+	struct rb_node rb;
+	ino_t inum;
+	loff_t i_size;
+	loff_t d_size;
+	int exists;
+	struct inode *inode;
+};
+
+/**
+ * add_ino - add an entry to the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ * @i_size: size on inode
+ * @d_size: maximum size based on data nodes
+ * @exists: indicates whether the inode exists
+ */
+static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size,
+		   loff_t d_size, int exists)
+{
+	struct rb_node **p = &c->size_tree.rb_node, *parent = NULL;
+	struct size_entry *e;
+
+	while (*p) {
+		parent = *p;
+		e = rb_entry(parent, struct size_entry, rb);
+		if (inum < e->inum)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	e = kzalloc(sizeof(struct size_entry), GFP_KERNEL);
+	if (!e)
+		return -ENOMEM;
+
+	e->inum = inum;
+	e->i_size = i_size;
+	e->d_size = d_size;
+	e->exists = exists;
+
+	rb_link_node(&e->rb, parent, p);
+	rb_insert_color(&e->rb, &c->size_tree);
+
+	return 0;
+}
+
+/**
+ * find_ino - find an entry on the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ */
+static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum)
+{
+	struct rb_node *p = c->size_tree.rb_node;
+	struct size_entry *e;
+
+	while (p) {
+		e = rb_entry(p, struct size_entry, rb);
+		if (inum < e->inum)
+			p = p->rb_left;
+		else if (inum > e->inum)
+			p = p->rb_right;
+		else
+			return e;
+	}
+	return NULL;
+}
+
+/**
+ * remove_ino - remove an entry from the size tree.
+ * @c: UBIFS file-system description object
+ * @inum: inode number
+ */
+static void remove_ino(struct ubifs_info *c, ino_t inum)
+{
+	struct size_entry *e = find_ino(c, inum);
+
+	if (!e)
+		return;
+	rb_erase(&e->rb, &c->size_tree);
+	kfree(e);
+}
+
+/**
+ * ubifs_recover_size_accum - accumulate inode sizes for recovery.
+ * @c: UBIFS file-system description object
+ * @key: node key
+ * @deletion: node is for a deletion
+ * @new_size: inode size
+ *
+ * This function has two purposes:
+ *     1) to ensure there are no data nodes that fall outside the inode size
+ *     2) to ensure there are no data nodes for inodes that do not exist
+ * To accomplish those purposes, a rb-tree is constructed containing an entry
+ * for each inode number in the journal that has not been deleted, and recording
+ * the size from the inode node, the maximum size of any data node (also altered
+ * by truncations) and a flag indicating a inode number for which no inode node
+ * was present in the journal.
+ *
+ * Note that there is still the possibility that there are data nodes that have
+ * been committed that are beyond the inode size, however the only way to find
+ * them would be to scan the entire index. Alternatively, some provision could
+ * be made to record the size of inodes at the start of commit, which would seem
+ * very cumbersome for a scenario that is quite unlikely and the only negative
+ * consequence of which is wasted space.
+ *
+ * This functions returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+			     int deletion, loff_t new_size)
+{
+	ino_t inum = key_inum(c, key);
+	struct size_entry *e;
+	int err;
+
+	switch (key_type(c, key)) {
+	case UBIFS_INO_KEY:
+		if (deletion)
+			remove_ino(c, inum);
+		else {
+			e = find_ino(c, inum);
+			if (e) {
+				e->i_size = new_size;
+				e->exists = 1;
+			} else {
+				err = add_ino(c, inum, new_size, 0, 1);
+				if (err)
+					return err;
+			}
+		}
+		break;
+	case UBIFS_DATA_KEY:
+		e = find_ino(c, inum);
+		if (e) {
+			if (new_size > e->d_size)
+				e->d_size = new_size;
+		} else {
+			err = add_ino(c, inum, 0, new_size, 0);
+			if (err)
+				return err;
+		}
+		break;
+	case UBIFS_TRUN_KEY:
+		e = find_ino(c, inum);
+		if (e)
+			e->d_size = new_size;
+		break;
+	}
+	return 0;
+}
+
+/**
+ * ubifs_recover_size - recover inode size.
+ * @c: UBIFS file-system description object
+ *
+ * This function attempts to fix inode size discrepancies identified by the
+ * 'ubifs_recover_size_accum()' function.
+ *
+ * This functions returns %0 on success and a negative error code on failure.
+ */
+int ubifs_recover_size(struct ubifs_info *c)
+{
+	struct rb_node *this = rb_first(&c->size_tree);
+
+	while (this) {
+		struct size_entry *e;
+		int err;
+
+		e = rb_entry(this, struct size_entry, rb);
+		if (!e->exists) {
+			union ubifs_key key;
+
+			ino_key_init(c, &key, e->inum);
+			err = ubifs_tnc_lookup(c, &key, c->sbuf);
+			if (err && err != -ENOENT)
+				return err;
+			if (err == -ENOENT) {
+				/* Remove data nodes that have no inode */
+				dbg_rcvry("removing ino %lu",
+					  (unsigned long)e->inum);
+				err = ubifs_tnc_remove_ino(c, e->inum);
+				if (err)
+					return err;
+			} else {
+				struct ubifs_ino_node *ino = c->sbuf;
+
+				e->exists = 1;
+				e->i_size = le64_to_cpu(ino->size);
+			}
+		}
+		if (e->exists && e->i_size < e->d_size) {
+			if (!e->inode && (c->vfs_sb->s_flags & MS_RDONLY)) {
+				/* Fix the inode size and pin it in memory */
+				struct inode *inode;
+
+				inode = ubifs_iget(c->vfs_sb, e->inum);
+				if (IS_ERR(inode))
+					return PTR_ERR(inode);
+				if (inode->i_size < e->d_size) {
+					dbg_rcvry("ino %lu size %lld -> %lld",
+						  (unsigned long)e->inum,
+						  e->d_size, inode->i_size);
+					inode->i_size = e->d_size;
+					ubifs_inode(inode)->ui_size = e->d_size;
+					e->inode = inode;
+					this = rb_next(this);
+					continue;
+				}
+				iput(inode);
+			}
+		}
+		this = rb_next(this);
+		rb_erase(&e->rb, &c->size_tree);
+		kfree(e);
+	}
+	return 0;
+}
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
new file mode 100644
index 0000000..da33a14
--- /dev/null
+++ b/fs/ubifs/replay.c
@@ -0,0 +1,1070 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file contains journal replay code. It runs when the file-system is being
+ * mounted and requires no locking.
+ *
+ * The larger is the journal, the longer it takes to scan it, so the longer it
+ * takes to mount UBIFS. This is why the journal has limited size which may be
+ * changed depending on the system requirements. But a larger journal gives
+ * faster I/O speed because it writes the index less frequently. So this is a
+ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the
+ * larger is the journal, the more memory its index may consume.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Replay flags.
+ *
+ * REPLAY_DELETION: node was deleted
+ * REPLAY_REF: node is a reference node
+ */
+enum {
+	REPLAY_DELETION = 1,
+	REPLAY_REF = 2,
+};
+
+/**
+ * struct replay_entry - replay tree entry.
+ * @lnum: logical eraseblock number of the node
+ * @offs: node offset
+ * @len: node length
+ * @sqnum: node sequence number
+ * @flags: replay flags
+ * @rb: links the replay tree
+ * @key: node key
+ * @nm: directory entry name
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ * @free: amount of free space in a bud
+ * @dirty: amount of dirty space in a bud from padding and deletion nodes
+ *
+ * UBIFS journal replay must compare node sequence numbers, which means it must
+ * build a tree of node information to insert into the TNC.
+ */
+struct replay_entry {
+	int lnum;
+	int offs;
+	int len;
+	unsigned long long sqnum;
+	int flags;
+	struct rb_node rb;
+	union ubifs_key key;
+	union {
+		struct qstr nm;
+		struct {
+			loff_t old_size;
+			loff_t new_size;
+		};
+		struct {
+			int free;
+			int dirty;
+		};
+	};
+};
+
+/**
+ * struct bud_entry - entry in the list of buds to replay.
+ * @list: next bud in the list
+ * @bud: bud description object
+ * @free: free bytes in the bud
+ * @sqnum: reference node sequence number
+ */
+struct bud_entry {
+	struct list_head list;
+	struct ubifs_bud *bud;
+	int free;
+	unsigned long long sqnum;
+};
+
+/**
+ * set_bud_lprops - set free and dirty space used by a bud.
+ * @c: UBIFS file-system description object
+ * @r: replay entry of bud
+ */
+static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+{
+	const struct ubifs_lprops *lp;
+	int err = 0, dirty;
+
+	ubifs_get_lprops(c);
+
+	lp = ubifs_lpt_lookup_dirty(c, r->lnum);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+
+	dirty = lp->dirty;
+	if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+		/*
+		 * The LEB was added to the journal with a starting offset of
+		 * zero which means the LEB must have been empty. The LEB
+		 * property values should be lp->free == c->leb_size and
+		 * lp->dirty == 0, but that is not the case. The reason is that
+		 * the LEB was garbage collected. The garbage collector resets
+		 * the free and dirty space without recording it anywhere except
+		 * lprops, so if there is not a commit then lprops does not have
+		 * that information next time the file system is mounted.
+		 *
+		 * We do not need to adjust free space because the scan has told
+		 * us the exact value which is recorded in the replay entry as
+		 * r->free.
+		 *
+		 * However we do need to subtract from the dirty space the
+		 * amount of space that the garbage collector reclaimed, which
+		 * is the whole LEB minus the amount of space that was free.
+		 */
+		dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+			lp->free, lp->dirty);
+		dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+			lp->free, lp->dirty);
+		dirty -= c->leb_size - lp->free;
+		/*
+		 * If the replay order was perfect the dirty space would now be
+		 * zero. The order is not perfect because the the journal heads
+		 * race with each other. This is not a problem but is does mean
+		 * that the dirty space may temporarily exceed c->leb_size
+		 * during the replay.
+		 */
+		if (dirty != 0)
+			dbg_msg("LEB %d lp: %d free %d dirty "
+				"replay: %d free %d dirty", r->lnum, lp->free,
+				lp->dirty, r->free, r->dirty);
+	}
+	lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
+			     lp->flags | LPROPS_TAKEN, 0);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * trun_remove_range - apply a replay entry for a truncation to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry of truncation
+ */
+static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+{
+	unsigned min_blk, max_blk;
+	union ubifs_key min_key, max_key;
+	ino_t ino;
+
+	min_blk = r->new_size / UBIFS_BLOCK_SIZE;
+	if (r->new_size & (UBIFS_BLOCK_SIZE - 1))
+		min_blk += 1;
+
+	max_blk = r->old_size / UBIFS_BLOCK_SIZE;
+	if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0)
+		max_blk -= 1;
+
+	ino = key_inum(c, &r->key);
+
+	data_key_init(c, &min_key, ino, min_blk);
+	data_key_init(c, &max_key, ino, max_blk);
+
+	return ubifs_tnc_remove_range(c, &min_key, &max_key);
+}
+
+/**
+ * apply_replay_entry - apply a replay entry to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry to apply
+ *
+ * Apply a replay entry to the TNC.
+ */
+static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+{
+	int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
+
+	dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
+		r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
+
+	/* Set c->replay_sqnum to help deal with dangling branches. */
+	c->replay_sqnum = r->sqnum;
+
+	if (r->flags & REPLAY_REF)
+		err = set_bud_lprops(c, r);
+	else if (is_hash_key(c, &r->key)) {
+		if (deletion)
+			err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
+		else
+			err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
+					       r->len, &r->nm);
+	} else {
+		if (deletion)
+			switch (key_type(c, &r->key)) {
+			case UBIFS_INO_KEY:
+			{
+				ino_t inum = key_inum(c, &r->key);
+
+				err = ubifs_tnc_remove_ino(c, inum);
+				break;
+			}
+			case UBIFS_TRUN_KEY:
+				err = trun_remove_range(c, r);
+				break;
+			default:
+				err = ubifs_tnc_remove(c, &r->key);
+				break;
+			}
+		else
+			err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
+					    r->len);
+		if (err)
+			return err;
+
+		if (c->need_recovery)
+			err = ubifs_recover_size_accum(c, &r->key, deletion,
+						       r->new_size);
+	}
+
+	return err;
+}
+
+/**
+ * destroy_replay_tree - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay tree.
+ */
+static void destroy_replay_tree(struct ubifs_info *c)
+{
+	struct rb_node *this = c->replay_tree.rb_node;
+	struct replay_entry *r;
+
+	while (this) {
+		if (this->rb_left) {
+			this = this->rb_left;
+			continue;
+		} else if (this->rb_right) {
+			this = this->rb_right;
+			continue;
+		}
+		r = rb_entry(this, struct replay_entry, rb);
+		this = rb_parent(this);
+		if (this) {
+			if (this->rb_left == &r->rb)
+				this->rb_left = NULL;
+			else
+				this->rb_right = NULL;
+		}
+		if (is_hash_key(c, &r->key))
+			kfree((void *)r->nm.name);
+		kfree(r);
+	}
+	c->replay_tree = RB_ROOT;
+}
+
+/**
+ * apply_replay_tree - apply the replay tree to the TNC.
+ * @c: UBIFS file-system description object
+ *
+ * Apply the replay tree.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int apply_replay_tree(struct ubifs_info *c)
+{
+	struct rb_node *this = rb_first(&c->replay_tree);
+
+	while (this) {
+		struct replay_entry *r;
+		int err;
+
+		cond_resched();
+
+		r = rb_entry(this, struct replay_entry, rb);
+		err = apply_replay_entry(c, r);
+		if (err)
+			return err;
+		this = rb_next(this);
+	}
+	return 0;
+}
+
+/**
+ * insert_node - insert a node to the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ *
+ * This function inserts a scanned non-direntry node to the replay tree. The
+ * replay tree is an RB-tree containing @struct replay_entry elements which are
+ * indexed by the sequence number. The replay tree is applied at the very end
+ * of the replay process. Since the tree is sorted in sequence number order,
+ * the older modifications are applied first. This function returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+		       union ubifs_key *key, unsigned long long sqnum,
+		       int deletion, int *used, loff_t old_size,
+		       loff_t new_size)
+{
+	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+	struct replay_entry *r;
+
+	if (key_inum(c, key) >= c->highest_inum)
+		c->highest_inum = key_inum(c, key);
+
+	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+	while (*p) {
+		parent = *p;
+		r = rb_entry(parent, struct replay_entry, rb);
+		if (sqnum < r->sqnum) {
+			p = &(*p)->rb_left;
+			continue;
+		} else if (sqnum > r->sqnum) {
+			p = &(*p)->rb_right;
+			continue;
+		}
+		ubifs_err("duplicate sqnum in replay");
+		return -EINVAL;
+	}
+
+	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+	if (!r)
+		return -ENOMEM;
+
+	if (!deletion)
+		*used += ALIGN(len, 8);
+	r->lnum = lnum;
+	r->offs = offs;
+	r->len = len;
+	r->sqnum = sqnum;
+	r->flags = (deletion ? REPLAY_DELETION : 0);
+	r->old_size = old_size;
+	r->new_size = new_size;
+	key_copy(c, key, &r->key);
+
+	rb_link_node(&r->rb, parent, p);
+	rb_insert_color(&r->rb, &c->replay_tree);
+	return 0;
+}
+
+/**
+ * insert_dent - insert a directory entry node into the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @name: directory entry name
+ * @nlen: directory entry name length
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ *
+ * This function inserts a scanned directory entry node to the replay tree.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ *
+ * This function is also used for extended attribute entries because they are
+ * implemented as directory entry nodes.
+ */
+static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+		       union ubifs_key *key, const char *name, int nlen,
+		       unsigned long long sqnum, int deletion, int *used)
+{
+	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+	struct replay_entry *r;
+	char *nbuf;
+
+	if (key_inum(c, key) >= c->highest_inum)
+		c->highest_inum = key_inum(c, key);
+
+	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+	while (*p) {
+		parent = *p;
+		r = rb_entry(parent, struct replay_entry, rb);
+		if (sqnum < r->sqnum) {
+			p = &(*p)->rb_left;
+			continue;
+		}
+		if (sqnum > r->sqnum) {
+			p = &(*p)->rb_right;
+			continue;
+		}
+		ubifs_err("duplicate sqnum in replay");
+		return -EINVAL;
+	}
+
+	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+	if (!r)
+		return -ENOMEM;
+	nbuf = kmalloc(nlen + 1, GFP_KERNEL);
+	if (!nbuf) {
+		kfree(r);
+		return -ENOMEM;
+	}
+
+	if (!deletion)
+		*used += ALIGN(len, 8);
+	r->lnum = lnum;
+	r->offs = offs;
+	r->len = len;
+	r->sqnum = sqnum;
+	r->nm.len = nlen;
+	memcpy(nbuf, name, nlen);
+	nbuf[nlen] = '\0';
+	r->nm.name = nbuf;
+	r->flags = (deletion ? REPLAY_DELETION : 0);
+	key_copy(c, key, &r->key);
+
+	ubifs_assert(!*p);
+	rb_link_node(&r->rb, parent, p);
+	rb_insert_color(&r->rb, &c->replay_tree);
+	return 0;
+}
+
+/**
+ * ubifs_validate_entry - validate directory or extended attribute entry node.
+ * @c: UBIFS file-system description object
+ * @dent: the node to validate
+ *
+ * This function validates directory or extended attribute entry node @dent.
+ * Returns zero if the node is all right and a %-EINVAL if not.
+ */
+int ubifs_validate_entry(struct ubifs_info *c,
+			 const struct ubifs_dent_node *dent)
+{
+	int key_type = key_type_flash(c, dent->key);
+	int nlen = le16_to_cpu(dent->nlen);
+
+	if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
+	    dent->type >= UBIFS_ITYPES_CNT ||
+	    nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
+	    strnlen((char *)dent->name, nlen) != nlen ||
+	    le64_to_cpu(dent->inum) > MAX_INUM) {
+		ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ?
+			  "directory entry" : "extended attribute entry");
+		return -EINVAL;
+	}
+
+	if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
+		ubifs_err("bad key type %d", key_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * replay_bud - replay a bud logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: bud logical eraseblock number to replay
+ * @offs: bud start offset
+ * @jhead: journal head to which this bud belongs
+ * @free: amount of free space in the bud is returned here
+ * @dirty: amount of dirty space from padding and deletion nodes is returned
+ * here
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+		      int *free, int *dirty)
+{
+	int err = 0, used = 0;
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	struct ubifs_bud *bud;
+
+	dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+	if (c->need_recovery)
+		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
+	else
+		sleb = ubifs_scan(c, lnum, offs, c->sbuf);
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+
+	/*
+	 * The bud does not have to start from offset zero - the beginning of
+	 * the 'lnum' LEB may contain previously committed data. One of the
+	 * things we have to do in replay is to correctly update lprops with
+	 * newer information about this LEB.
+	 *
+	 * At this point lprops thinks that this LEB has 'c->leb_size - offs'
+	 * bytes of free space because it only contain information about
+	 * committed data.
+	 *
+	 * But we know that real amount of free space is 'c->leb_size -
+	 * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and
+	 * 'sleb->endpt' is used by bud data. We have to correctly calculate
+	 * how much of these data are dirty and update lprops with this
+	 * information.
+	 *
+	 * The dirt in that LEB region is comprised of padding nodes, deletion
+	 * nodes, truncation nodes and nodes which are obsoleted by subsequent
+	 * nodes in this LEB. So instead of calculating clean space, we
+	 * calculate used space ('used' variable).
+	 */
+
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		int deletion = 0;
+
+		cond_resched();
+
+		if (snod->sqnum >= SQNUM_WATERMARK) {
+			ubifs_err("file system's life ended");
+			goto out_dump;
+		}
+
+		if (snod->sqnum > c->max_sqnum)
+			c->max_sqnum = snod->sqnum;
+
+		switch (snod->type) {
+		case UBIFS_INO_NODE:
+		{
+			struct ubifs_ino_node *ino = snod->node;
+			loff_t new_size = le64_to_cpu(ino->size);
+
+			if (le32_to_cpu(ino->nlink) == 0)
+				deletion = 1;
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &snod->key, snod->sqnum, deletion,
+					  &used, 0, new_size);
+			break;
+		}
+		case UBIFS_DATA_NODE:
+		{
+			struct ubifs_data_node *dn = snod->node;
+			loff_t new_size = le32_to_cpu(dn->size) +
+					  key_block(c, &snod->key) *
+					  UBIFS_BLOCK_SIZE;
+
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &snod->key, snod->sqnum, deletion,
+					  &used, 0, new_size);
+			break;
+		}
+		case UBIFS_DENT_NODE:
+		case UBIFS_XENT_NODE:
+		{
+			struct ubifs_dent_node *dent = snod->node;
+
+			err = ubifs_validate_entry(c, dent);
+			if (err)
+				goto out_dump;
+
+			err = insert_dent(c, lnum, snod->offs, snod->len,
+					  &snod->key, (char *)dent->name,
+					  le16_to_cpu(dent->nlen), snod->sqnum,
+					  !le64_to_cpu(dent->inum), &used);
+			break;
+		}
+		case UBIFS_TRUN_NODE:
+		{
+			struct ubifs_trun_node *trun = snod->node;
+			loff_t old_size = le64_to_cpu(trun->old_size);
+			loff_t new_size = le64_to_cpu(trun->new_size);
+			union ubifs_key key;
+
+			/* Validate truncation node */
+			if (old_size < 0 || old_size > c->max_inode_sz ||
+			    new_size < 0 || new_size > c->max_inode_sz ||
+			    old_size <= new_size) {
+				ubifs_err("bad truncation node");
+				goto out_dump;
+			}
+
+			/*
+			 * Create a fake truncation key just to use the same
+			 * functions which expect nodes to have keys.
+			 */
+			trun_key_init(c, &key, le32_to_cpu(trun->inum));
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &key, snod->sqnum, 1, &used,
+					  old_size, new_size);
+			break;
+		}
+		default:
+			ubifs_err("unexpected node type %d in bud LEB %d:%d",
+				  snod->type, lnum, snod->offs);
+			err = -EINVAL;
+			goto out_dump;
+		}
+		if (err)
+			goto out;
+	}
+
+	bud = ubifs_search_bud(c, lnum);
+	if (!bud)
+		BUG();
+
+	ubifs_assert(sleb->endpt - offs >= used);
+	ubifs_assert(sleb->endpt % c->min_io_size == 0);
+
+	*dirty = sleb->endpt - offs - used;
+	*free = c->leb_size - sleb->endpt;
+
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+
+out_dump:
+	ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
+	dbg_dump_node(c, snod->node);
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+}
+
+/**
+ * insert_ref_node - insert a reference node to the replay tree.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @sqnum: sequence number
+ * @free: amount of free space in bud
+ * @dirty: amount of dirty space from padding and deletion nodes
+ *
+ * This function inserts a reference node to the replay tree and returns zero
+ * in case of success or a negative error code in case of failure.
+ */
+static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+			   unsigned long long sqnum, int free, int dirty)
+{
+	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+	struct replay_entry *r;
+
+	dbg_mnt("add ref LEB %d:%d", lnum, offs);
+	while (*p) {
+		parent = *p;
+		r = rb_entry(parent, struct replay_entry, rb);
+		if (sqnum < r->sqnum) {
+			p = &(*p)->rb_left;
+			continue;
+		} else if (sqnum > r->sqnum) {
+			p = &(*p)->rb_right;
+			continue;
+		}
+		ubifs_err("duplicate sqnum in replay tree");
+		return -EINVAL;
+	}
+
+	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+	if (!r)
+		return -ENOMEM;
+
+	r->lnum = lnum;
+	r->offs = offs;
+	r->sqnum = sqnum;
+	r->flags = REPLAY_REF;
+	r->free = free;
+	r->dirty = dirty;
+
+	rb_link_node(&r->rb, parent, p);
+	rb_insert_color(&r->rb, &c->replay_tree);
+	return 0;
+}
+
+/**
+ * replay_buds - replay all buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int replay_buds(struct ubifs_info *c)
+{
+	struct bud_entry *b;
+	int err, uninitialized_var(free), uninitialized_var(dirty);
+
+	list_for_each_entry(b, &c->replay_buds, list) {
+		err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
+				 &free, &dirty);
+		if (err)
+			return err;
+		err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
+				      free, dirty);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * destroy_bud_list - destroy the list of buds to replay.
+ * @c: UBIFS file-system description object
+ */
+static void destroy_bud_list(struct ubifs_info *c)
+{
+	struct bud_entry *b;
+
+	while (!list_empty(&c->replay_buds)) {
+		b = list_entry(c->replay_buds.next, struct bud_entry, list);
+		list_del(&b->list);
+		kfree(b);
+	}
+}
+
+/**
+ * add_replay_bud - add a bud to the list of buds to replay.
+ * @c: UBIFS file-system description object
+ * @lnum: bud logical eraseblock number to replay
+ * @offs: bud start offset
+ * @jhead: journal head to which this bud belongs
+ * @sqnum: reference node sequence number
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+			  unsigned long long sqnum)
+{
+	struct ubifs_bud *bud;
+	struct bud_entry *b;
+
+	dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
+
+	bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL);
+	if (!bud)
+		return -ENOMEM;
+
+	b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
+	if (!b) {
+		kfree(bud);
+		return -ENOMEM;
+	}
+
+	bud->lnum = lnum;
+	bud->start = offs;
+	bud->jhead = jhead;
+	ubifs_add_bud(c, bud);
+
+	b->bud = bud;
+	b->sqnum = sqnum;
+	list_add_tail(&b->list, &c->replay_buds);
+
+	return 0;
+}
+
+/**
+ * validate_ref - validate a reference node.
+ * @c: UBIFS file-system description object
+ * @ref: the reference node to validate
+ * @ref_lnum: LEB number of the reference node
+ * @ref_offs: reference node offset
+ *
+ * This function returns %1 if a bud reference already exists for the LEB. %0 is
+ * returned if the reference node is new, otherwise %-EINVAL is returned if
+ * validation failed.
+ */
+static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref)
+{
+	struct ubifs_bud *bud;
+	int lnum = le32_to_cpu(ref->lnum);
+	unsigned int offs = le32_to_cpu(ref->offs);
+	unsigned int jhead = le32_to_cpu(ref->jhead);
+
+	/*
+	 * ref->offs may point to the end of LEB when the journal head points
+	 * to the end of LEB and we write reference node for it during commit.
+	 * So this is why we require 'offs > c->leb_size'.
+	 */
+	if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt ||
+	    lnum < c->main_first || offs > c->leb_size ||
+	    offs & (c->min_io_size - 1))
+		return -EINVAL;
+
+	/* Make sure we have not already looked at this bud */
+	bud = ubifs_search_bud(c, lnum);
+	if (bud) {
+		if (bud->jhead == jhead && bud->start <= offs)
+			return 1;
+		ubifs_err("bud at LEB %d:%d was already referred", lnum, offs);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * replay_log_leb - replay a log logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: log logical eraseblock to replay
+ * @offs: offset to start replaying from
+ * @sbuf: scan buffer
+ *
+ * This function replays a log LEB and returns zero in case of success, %1 if
+ * this is the last LEB in the log, and a negative error code in case of
+ * failure.
+ */
+static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+{
+	int err;
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	const struct ubifs_cs_node *node;
+
+	dbg_mnt("replay log LEB %d:%d", lnum, offs);
+	sleb = ubifs_scan(c, lnum, offs, sbuf);
+	if (IS_ERR(sleb)) {
+		if (c->need_recovery)
+			sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
+		if (IS_ERR(sleb))
+			return PTR_ERR(sleb);
+	}
+
+	if (sleb->nodes_cnt == 0) {
+		err = 1;
+		goto out;
+	}
+
+	node = sleb->buf;
+
+	snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
+	if (c->cs_sqnum == 0) {
+		/*
+		 * This is the first log LEB we are looking at, make sure that
+		 * the first node is a commit start node. Also record its
+		 * sequence number so that UBIFS can determine where the log
+		 * ends, because all nodes which were have higher sequence
+		 * numbers.
+		 */
+		if (snod->type != UBIFS_CS_NODE) {
+			dbg_err("first log node at LEB %d:%d is not CS node",
+				lnum, offs);
+			goto out_dump;
+		}
+		if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
+			dbg_err("first CS node at LEB %d:%d has wrong "
+				"commit number %llu expected %llu",
+				lnum, offs,
+				(unsigned long long)le64_to_cpu(node->cmt_no),
+				c->cmt_no);
+			goto out_dump;
+		}
+
+		c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
+		dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
+	}
+
+	if (snod->sqnum < c->cs_sqnum) {
+		/*
+		 * This means that we reached end of log and now
+		 * look to the older log data, which was already
+		 * committed but the eraseblock was not erased (UBIFS
+		 * only un-maps it). So this basically means we have to
+		 * exit with "end of log" code.
+		 */
+		err = 1;
+		goto out;
+	}
+
+	/* Make sure the first node sits at offset zero of the LEB */
+	if (snod->offs != 0) {
+		dbg_err("first node is not at zero offset");
+		goto out_dump;
+	}
+
+	list_for_each_entry(snod, &sleb->nodes, list) {
+
+		cond_resched();
+
+		if (snod->sqnum >= SQNUM_WATERMARK) {
+			ubifs_err("file system's life ended");
+			goto out_dump;
+		}
+
+		if (snod->sqnum < c->cs_sqnum) {
+			dbg_err("bad sqnum %llu, commit sqnum %llu",
+				snod->sqnum, c->cs_sqnum);
+			goto out_dump;
+		}
+
+		if (snod->sqnum > c->max_sqnum)
+			c->max_sqnum = snod->sqnum;
+
+		switch (snod->type) {
+		case UBIFS_REF_NODE: {
+			const struct ubifs_ref_node *ref = snod->node;
+
+			err = validate_ref(c, ref);
+			if (err == 1)
+				break; /* Already have this bud */
+			if (err)
+				goto out_dump;
+
+			err = add_replay_bud(c, le32_to_cpu(ref->lnum),
+					     le32_to_cpu(ref->offs),
+					     le32_to_cpu(ref->jhead),
+					     snod->sqnum);
+			if (err)
+				goto out;
+
+			break;
+		}
+		case UBIFS_CS_NODE:
+			/* Make sure it sits at the beginning of LEB */
+			if (snod->offs != 0) {
+				ubifs_err("unexpected node in log");
+				goto out_dump;
+			}
+			break;
+		default:
+			ubifs_err("unexpected node in log");
+			goto out_dump;
+		}
+	}
+
+	if (sleb->endpt || c->lhead_offs >= c->leb_size) {
+		c->lhead_lnum = lnum;
+		c->lhead_offs = sleb->endpt;
+	}
+
+	err = !sleb->endpt;
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+
+out_dump:
+	ubifs_err("log error detected while replying the log at LEB %d:%d",
+		  lnum, offs + snod->offs);
+	dbg_dump_node(c, snod->node);
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+}
+
+/**
+ * take_ihead - update the status of the index head in lprops to 'taken'.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the amount of free space in the index head LEB or a
+ * negative error code.
+ */
+static int take_ihead(struct ubifs_info *c)
+{
+	const struct ubifs_lprops *lp;
+	int err, free;
+
+	ubifs_get_lprops(c);
+
+	lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+
+	free = lp->free;
+
+	lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
+			     lp->flags | LPROPS_TAKEN, 0);
+	if (IS_ERR(lp)) {
+		err = PTR_ERR(lp);
+		goto out;
+	}
+
+	err = free;
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * ubifs_replay_journal - replay journal.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the journal, replays and cleans it up. It makes sure all
+ * memory data structures related to uncommitted journal are built (dirty TNC
+ * tree, tree of buds, modified lprops, etc).
+ */
+int ubifs_replay_journal(struct ubifs_info *c)
+{
+	int err, i, lnum, offs, _free;
+	void *sbuf = NULL;
+
+	BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
+
+	/* Update the status of the index head in lprops to 'taken' */
+	_free = take_ihead(c);
+	if (_free < 0)
+		return _free; /* Error code */
+
+	if (c->ihead_offs != c->leb_size - _free) {
+		ubifs_err("bad index head LEB %d:%d", c->ihead_lnum,
+			  c->ihead_offs);
+		return -EINVAL;
+	}
+
+	sbuf = vmalloc(c->leb_size);
+	if (!sbuf)
+		return -ENOMEM;
+
+	dbg_mnt("start replaying the journal");
+
+	c->replaying = 1;
+
+	lnum = c->ltail_lnum = c->lhead_lnum;
+	offs = c->lhead_offs;
+
+	for (i = 0; i < c->log_lebs; i++, lnum++) {
+		if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) {
+			/*
+			 * The log is logically circular, we reached the last
+			 * LEB, switch to the first one.
+			 */
+			lnum = UBIFS_LOG_LNUM;
+			offs = 0;
+		}
+		err = replay_log_leb(c, lnum, offs, sbuf);
+		if (err == 1)
+			/* We hit the end of the log */
+			break;
+		if (err)
+			goto out;
+		offs = 0;
+	}
+
+	err = replay_buds(c);
+	if (err)
+		goto out;
+
+	err = apply_replay_tree(c);
+	if (err)
+		goto out;
+
+	ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+	dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
+		"highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
+		(unsigned long)c->highest_inum);
+out:
+	destroy_replay_tree(c);
+	destroy_bud_list(c);
+	vfree(sbuf);
+	c->replaying = 0;
+	return err;
+}
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
new file mode 100644
index 0000000..9708fda
--- /dev/null
+++ b/fs/ubifs/sb.c
@@ -0,0 +1,324 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file implements UBIFS superblock. The superblock is stored at the first
+ * LEB of the volume and is never changed by UBIFS. Only user-space tools may
+ * change it. The superblock node mostly contains geometry information.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Default journal size in logical eraseblocks as a percent of total
+ * flash size.
+ */
+#define DEFAULT_JNL_PERCENT 5
+
+/* Default maximum journal size in bytes */
+#define DEFAULT_MAX_JNL (32*1024*1024)
+
+/* Default indexing tree fanout */
+#define DEFAULT_FANOUT 8
+
+/* Default number of data journal heads */
+#define DEFAULT_JHEADS_CNT 1
+
+/* Default positions of different LEBs in the main area */
+#define DEFAULT_IDX_LEB  0
+#define DEFAULT_DATA_LEB 1
+#define DEFAULT_GC_LEB   2
+
+/* Default number of LEB numbers in LPT's save table */
+#define DEFAULT_LSAVE_CNT 256
+
+/* Default reserved pool size as a percent of maximum free space */
+#define DEFAULT_RP_PERCENT 5
+
+/* The default maximum size of reserved pool in bytes */
+#define DEFAULT_MAX_RP_SIZE (5*1024*1024)
+
+/* Default time granularity in nanoseconds */
+#define DEFAULT_TIME_GRAN 1000000000
+
+/**
+ * validate_sb - validate superblock node.
+ * @c: UBIFS file-system description object
+ * @sup: superblock node
+ *
+ * This function validates superblock node @sup. Since most of data was read
+ * from the superblock and stored in @c, the function validates fields in @c
+ * instead. Returns zero in case of success and %-EINVAL in case of validation
+ * failure.
+ */
+static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+{
+	long long max_bytes;
+	int err = 1, min_leb_cnt;
+
+	if (!c->key_hash) {
+		err = 2;
+		goto failed;
+	}
+
+	if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) {
+		err = 3;
+		goto failed;
+	}
+
+	if (le32_to_cpu(sup->min_io_size) != c->min_io_size) {
+		ubifs_err("min. I/O unit mismatch: %d in superblock, %d real",
+			  le32_to_cpu(sup->min_io_size), c->min_io_size);
+		goto failed;
+	}
+
+	if (le32_to_cpu(sup->leb_size) != c->leb_size) {
+		ubifs_err("LEB size mismatch: %d in superblock, %d real",
+			  le32_to_cpu(sup->leb_size), c->leb_size);
+		goto failed;
+	}
+
+	if (c->log_lebs < UBIFS_MIN_LOG_LEBS ||
+	    c->lpt_lebs < UBIFS_MIN_LPT_LEBS ||
+	    c->orph_lebs < UBIFS_MIN_ORPH_LEBS ||
+	    c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+		err = 4;
+		goto failed;
+	}
+
+	/*
+	 * Calculate minimum allowed amount of main area LEBs. This is very
+	 * similar to %UBIFS_MIN_LEB_CNT, but we take into account real what we
+	 * have just read from the superblock.
+	 */
+	min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
+	min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
+
+	if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
+		ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
+			  "%d minimum required", c->leb_cnt, c->vi.size,
+			  min_leb_cnt);
+		goto failed;
+	}
+
+	if (c->max_leb_cnt < c->leb_cnt) {
+		ubifs_err("max. LEB count %d less than LEB count %d",
+			  c->max_leb_cnt, c->leb_cnt);
+		goto failed;
+	}
+
+	if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+		err = 7;
+		goto failed;
+	}
+
+	if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
+	    c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
+		err = 8;
+		goto failed;
+	}
+
+	if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 ||
+	    c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) {
+		err = 9;
+		goto failed;
+	}
+
+	if (c->fanout < UBIFS_MIN_FANOUT ||
+	    ubifs_idx_node_sz(c, c->fanout) > c->leb_size) {
+		err = 10;
+		goto failed;
+	}
+
+	if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT &&
+	    c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS -
+	    c->log_lebs - c->lpt_lebs - c->orph_lebs)) {
+		err = 11;
+		goto failed;
+	}
+
+	if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
+	    c->orph_lebs + c->main_lebs != c->leb_cnt) {
+		err = 12;
+		goto failed;
+	}
+
+	if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) {
+		err = 13;
+		goto failed;
+	}
+
+	max_bytes = c->main_lebs * (long long)c->leb_size;
+	if (c->rp_size < 0 || max_bytes < c->rp_size) {
+		err = 14;
+		goto failed;
+	}
+
+	if (le32_to_cpu(sup->time_gran) > 1000000000 ||
+	    le32_to_cpu(sup->time_gran) < 1) {
+		err = 15;
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	ubifs_err("bad superblock, error %d", err);
+	dbg_dump_node(c, sup);
+	return -EINVAL;
+}
+
+/**
+ * ubifs_read_sb_node - read superblock node.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns a pointer to the superblock node or a negative error
+ * code.
+ */
+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+{
+	struct ubifs_sb_node *sup;
+	int err;
+
+	sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS);
+	if (!sup)
+		return ERR_PTR(-ENOMEM);
+
+	err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ,
+			      UBIFS_SB_LNUM, 0);
+	if (err) {
+		kfree(sup);
+		return ERR_PTR(err);
+	}
+
+	return sup;
+}
+
+/**
+ * ubifs_read_superblock - read superblock.
+ * @c: UBIFS file-system description object
+ *
+ * This function finds, reads and checks the superblock. If an empty UBI volume
+ * is being mounted, this function creates default superblock. Returns zero in
+ * case of success, and a negative error code in case of failure.
+ */
+int ubifs_read_superblock(struct ubifs_info *c)
+{
+	int err, sup_flags;
+	struct ubifs_sb_node *sup;
+
+	if (c->empty) {
+		printf("No UBIFS filesystem found!\n");
+		return -1;
+	}
+
+	sup = ubifs_read_sb_node(c);
+	if (IS_ERR(sup))
+		return PTR_ERR(sup);
+
+	/*
+	 * The software supports all previous versions but not future versions,
+	 * due to the unavailability of time-travelling equipment.
+	 */
+	c->fmt_version = le32_to_cpu(sup->fmt_version);
+	if (c->fmt_version > UBIFS_FORMAT_VERSION) {
+		ubifs_err("on-flash format version is %d, but software only "
+			  "supports up to version %d", c->fmt_version,
+			  UBIFS_FORMAT_VERSION);
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (c->fmt_version < 3) {
+		ubifs_err("on-flash format version %d is not supported",
+			  c->fmt_version);
+		err = -EINVAL;
+		goto out;
+	}
+
+	switch (sup->key_hash) {
+	case UBIFS_KEY_HASH_R5:
+		c->key_hash = key_r5_hash;
+		c->key_hash_type = UBIFS_KEY_HASH_R5;
+		break;
+
+	case UBIFS_KEY_HASH_TEST:
+		c->key_hash = key_test_hash;
+		c->key_hash_type = UBIFS_KEY_HASH_TEST;
+		break;
+	};
+
+	c->key_fmt = sup->key_fmt;
+
+	switch (c->key_fmt) {
+	case UBIFS_SIMPLE_KEY_FMT:
+		c->key_len = UBIFS_SK_LEN;
+		break;
+	default:
+		ubifs_err("unsupported key format");
+		err = -EINVAL;
+		goto out;
+	}
+
+	c->leb_cnt       = le32_to_cpu(sup->leb_cnt);
+	c->max_leb_cnt   = le32_to_cpu(sup->max_leb_cnt);
+	c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
+	c->log_lebs      = le32_to_cpu(sup->log_lebs);
+	c->lpt_lebs      = le32_to_cpu(sup->lpt_lebs);
+	c->orph_lebs     = le32_to_cpu(sup->orph_lebs);
+	c->jhead_cnt     = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
+	c->fanout        = le32_to_cpu(sup->fanout);
+	c->lsave_cnt     = le32_to_cpu(sup->lsave_cnt);
+	c->default_compr = le16_to_cpu(sup->default_compr);
+	c->rp_size       = le64_to_cpu(sup->rp_size);
+	c->rp_uid        = le32_to_cpu(sup->rp_uid);
+	c->rp_gid        = le32_to_cpu(sup->rp_gid);
+	sup_flags        = le32_to_cpu(sup->flags);
+
+	c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
+	memcpy(&c->uuid, &sup->uuid, 16);
+	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+
+	/* Automatically increase file system size to the maximum size */
+	c->old_leb_cnt = c->leb_cnt;
+	if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) {
+		c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size);
+		dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
+			c->old_leb_cnt,	c->leb_cnt);
+	}
+
+	c->log_bytes = (long long)c->log_lebs * c->leb_size;
+	c->log_last = UBIFS_LOG_LNUM + c->log_lebs - 1;
+	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+	c->orph_first = c->lpt_last + 1;
+	c->orph_last = c->orph_first + c->orph_lebs - 1;
+	c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+	c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+	c->main_first = c->leb_cnt - c->main_lebs;
+	c->report_rp_size = ubifs_reported_space(c, c->rp_size);
+
+	err = validate_sb(c, sup);
+out:
+	kfree(sup);
+	return err;
+}
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
new file mode 100644
index 0000000..0ed8247
--- /dev/null
+++ b/fs/ubifs/scan.c
@@ -0,0 +1,362 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements the scan which is a general-purpose function for
+ * determining what nodes are in an eraseblock. The scan is used to replay the
+ * journal, to do garbage collection. for the TNC in-the-gaps method, and by
+ * debugging functions.
+ */
+
+#include "ubifs.h"
+
+/**
+ * scan_padding_bytes - scan for padding bytes.
+ * @buf: buffer to scan
+ * @len: length of buffer
+ *
+ * This function returns the number of padding bytes on success and
+ * %SCANNED_GARBAGE on failure.
+ */
+static int scan_padding_bytes(void *buf, int len)
+{
+	int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len);
+	uint8_t *p = buf;
+
+	dbg_scan("not a node");
+
+	while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE)
+		pad_len += 1;
+
+	if (!pad_len || (pad_len & 7))
+		return SCANNED_GARBAGE;
+
+	dbg_scan("%d padding bytes", pad_len);
+
+	return pad_len;
+}
+
+/**
+ * ubifs_scan_a_node - scan for a node or padding.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to scan
+ * @len: length of buffer
+ * @lnum: logical eraseblock number
+ * @offs: offset within the logical eraseblock
+ * @quiet: print no messages
+ *
+ * This function returns a scanning code to indicate what was scanned.
+ */
+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
+		      int offs, int quiet)
+{
+	struct ubifs_ch *ch = buf;
+	uint32_t magic;
+
+	magic = le32_to_cpu(ch->magic);
+
+	if (magic == 0xFFFFFFFF) {
+		dbg_scan("hit empty space");
+		return SCANNED_EMPTY_SPACE;
+	}
+
+	if (magic != UBIFS_NODE_MAGIC)
+		return scan_padding_bytes(buf, len);
+
+	if (len < UBIFS_CH_SZ)
+		return SCANNED_GARBAGE;
+
+	dbg_scan("scanning %s", dbg_ntype(ch->node_type));
+
+	if (ubifs_check_node(c, buf, lnum, offs, quiet, 1))
+		return SCANNED_A_CORRUPT_NODE;
+
+	if (ch->node_type == UBIFS_PAD_NODE) {
+		struct ubifs_pad_node *pad = buf;
+		int pad_len = le32_to_cpu(pad->pad_len);
+		int node_len = le32_to_cpu(ch->len);
+
+		/* Validate the padding node */
+		if (pad_len < 0 ||
+		    offs + node_len + pad_len > c->leb_size) {
+			if (!quiet) {
+				ubifs_err("bad pad node at LEB %d:%d",
+					  lnum, offs);
+				dbg_dump_node(c, pad);
+			}
+			return SCANNED_A_BAD_PAD_NODE;
+		}
+
+		/* Make the node pads to 8-byte boundary */
+		if ((node_len + pad_len) & 7) {
+			if (!quiet) {
+				dbg_err("bad padding length %d - %d",
+					offs, offs + node_len + pad_len);
+			}
+			return SCANNED_A_BAD_PAD_NODE;
+		}
+
+		dbg_scan("%d bytes padded, offset now %d",
+			 pad_len, ALIGN(offs + node_len + pad_len, 8));
+
+		return node_len + pad_len;
+	}
+
+	return SCANNED_A_NODE;
+}
+
+/**
+ * ubifs_start_scan - create LEB scanning information at start of scan.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be c->leb_size)
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+					int offs, void *sbuf)
+{
+	struct ubifs_scan_leb *sleb;
+	int err;
+
+	dbg_scan("scan LEB %d:%d", lnum, offs);
+
+	sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS);
+	if (!sleb)
+		return ERR_PTR(-ENOMEM);
+
+	sleb->lnum = lnum;
+	INIT_LIST_HEAD(&sleb->nodes);
+	sleb->buf = sbuf;
+
+	err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
+	if (err && err != -EBADMSG) {
+		ubifs_err("cannot read %d bytes from LEB %d:%d,"
+			  " error %d", c->leb_size - offs, lnum, offs, err);
+		kfree(sleb);
+		return ERR_PTR(err);
+	}
+
+	if (err == -EBADMSG)
+		sleb->ecc = 1;
+
+	return sleb;
+}
+
+/**
+ * ubifs_end_scan - update LEB scanning information at end of scan.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		    int lnum, int offs)
+{
+	lnum = lnum;
+	dbg_scan("stop scanning LEB %d at offset %d", lnum, offs);
+	ubifs_assert(offs % c->min_io_size == 0);
+
+	sleb->endpt = ALIGN(offs, c->min_io_size);
+}
+
+/**
+ * ubifs_add_snod - add a scanned node to LEB scanning information.
+ * @c: UBIFS file-system description object
+ * @sleb: scanning information
+ * @buf: buffer containing node
+ * @offs: offset of node on flash
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		   void *buf, int offs)
+{
+	struct ubifs_ch *ch = buf;
+	struct ubifs_ino_node *ino = buf;
+	struct ubifs_scan_node *snod;
+
+	snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
+	if (!snod)
+		return -ENOMEM;
+
+	snod->sqnum = le64_to_cpu(ch->sqnum);
+	snod->type = ch->node_type;
+	snod->offs = offs;
+	snod->len = le32_to_cpu(ch->len);
+	snod->node = buf;
+
+	switch (ch->node_type) {
+	case UBIFS_INO_NODE:
+	case UBIFS_DENT_NODE:
+	case UBIFS_XENT_NODE:
+	case UBIFS_DATA_NODE:
+	case UBIFS_TRUN_NODE:
+		/*
+		 * The key is in the same place in all keyed
+		 * nodes.
+		 */
+		key_read(c, &ino->key, &snod->key);
+		break;
+	}
+	list_add_tail(&snod->list, &sleb->nodes);
+	sleb->nodes_cnt += 1;
+	return 0;
+}
+
+/**
+ * ubifs_scanned_corruption - print information after UBIFS scanned corruption.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of corruption
+ * @offs: offset of corruption
+ * @buf: buffer containing corruption
+ */
+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+			      void *buf)
+{
+	int len;
+
+	ubifs_err("corrupted data at LEB %d:%d", lnum, offs);
+	if (dbg_failure_mode)
+		return;
+	len = c->leb_size - offs;
+	if (len > 4096)
+		len = 4096;
+	dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
+	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
+}
+
+/**
+ * ubifs_scan - scan a logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number
+ * @offs: offset to start at (usually zero)
+ * @sbuf: scan buffer (must be c->leb_size)
+ *
+ * This function scans LEB number @lnum and returns complete information about
+ * its contents. Returns an error code in case of failure.
+ */
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+				  int offs, void *sbuf)
+{
+	void *buf = sbuf + offs;
+	int err, len = c->leb_size - offs;
+	struct ubifs_scan_leb *sleb;
+
+	sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+	if (IS_ERR(sleb))
+		return sleb;
+
+	while (len >= 8) {
+		struct ubifs_ch *ch = buf;
+		int node_len, ret;
+
+		dbg_scan("look at LEB %d:%d (%d bytes left)",
+			 lnum, offs, len);
+
+		cond_resched();
+
+		ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
+
+		if (ret > 0) {
+			/* Padding bytes or a valid padding node */
+			offs += ret;
+			buf += ret;
+			len -= ret;
+			continue;
+		}
+
+		if (ret == SCANNED_EMPTY_SPACE)
+			/* Empty space is checked later */
+			break;
+
+		switch (ret) {
+		case SCANNED_GARBAGE:
+			dbg_err("garbage");
+			goto corrupted;
+		case SCANNED_A_NODE:
+			break;
+		case SCANNED_A_CORRUPT_NODE:
+		case SCANNED_A_BAD_PAD_NODE:
+			dbg_err("bad node");
+			goto corrupted;
+		default:
+			dbg_err("unknown");
+			goto corrupted;
+		}
+
+		err = ubifs_add_snod(c, sleb, buf, offs);
+		if (err)
+			goto error;
+
+		node_len = ALIGN(le32_to_cpu(ch->len), 8);
+		offs += node_len;
+		buf += node_len;
+		len -= node_len;
+	}
+
+	if (offs % c->min_io_size)
+		goto corrupted;
+
+	ubifs_end_scan(c, sleb, lnum, offs);
+
+	for (; len > 4; offs += 4, buf = buf + 4, len -= 4)
+		if (*(uint32_t *)buf != 0xffffffff)
+			break;
+	for (; len; offs++, buf++, len--)
+		if (*(uint8_t *)buf != 0xff) {
+			ubifs_err("corrupt empty space at LEB %d:%d",
+				  lnum, offs);
+			goto corrupted;
+		}
+
+	return sleb;
+
+corrupted:
+	ubifs_scanned_corruption(c, lnum, offs, buf);
+	err = -EUCLEAN;
+error:
+	ubifs_err("LEB %d scanning failed", lnum);
+	ubifs_scan_destroy(sleb);
+	return ERR_PTR(err);
+}
+
+/**
+ * ubifs_scan_destroy - destroy LEB scanning information.
+ * @sleb: scanning information to free
+ */
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb)
+{
+	struct ubifs_scan_node *node;
+	struct list_head *head;
+
+	head = &sleb->nodes;
+	while (!list_empty(head)) {
+		node = list_entry(head->next, struct ubifs_scan_node, list);
+		list_del(&node->list);
+		kfree(node);
+	}
+	kfree(sleb);
+}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
new file mode 100644
index 0000000..95f2a41
--- /dev/null
+++ b/fs/ubifs/super.c
@@ -0,0 +1,1189 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file implements UBIFS initialization and VFS superblock operations. Some
+ * initialization stuff which is rather large and complex is placed at
+ * corresponding subsystems, but most of it is here.
+ */
+
+#include "ubifs.h"
+#include <linux/math64.h>
+
+#define INODE_LOCKED_MAX	64
+
+struct super_block *ubifs_sb;
+static struct inode *inodes_locked_down[INODE_LOCKED_MAX];
+
+/* shrinker.c */
+
+/* List of all UBIFS file-system instances */
+struct list_head ubifs_infos;
+
+/* linux/fs/super.c */
+
+static int sb_set(struct super_block *sb, void *data)
+{
+	dev_t *dev = data;
+
+	sb->s_dev = *dev;
+	return 0;
+}
+
+/**
+ *	sget	-	find or create a superblock
+ *	@type:	filesystem type superblock should belong to
+ *	@test:	comparison callback
+ *	@set:	setup callback
+ *	@data:	argument to each of them
+ */
+struct super_block *sget(struct file_system_type *type,
+			int (*test)(struct super_block *,void *),
+			int (*set)(struct super_block *,void *),
+			void *data)
+{
+	struct super_block *s = NULL;
+	int err;
+
+	s = kzalloc(sizeof(struct super_block),  GFP_USER);
+	if (!s) {
+		err = -ENOMEM;
+		return ERR_PTR(err);
+	}
+
+	INIT_LIST_HEAD(&s->s_instances);
+	INIT_LIST_HEAD(&s->s_inodes);
+	s->s_time_gran = 1000000000;
+
+	err = set(s, data);
+	if (err) {
+		return ERR_PTR(err);
+	}
+	s->s_type = type;
+	strncpy(s->s_id, type->name, sizeof(s->s_id));
+	list_add(&s->s_instances, &type->fs_supers);
+	return s;
+}
+
+/**
+ * validate_inode - validate inode.
+ * @c: UBIFS file-system description object
+ * @inode: the inode to validate
+ *
+ * This is a helper function for 'ubifs_iget()' which validates various fields
+ * of a newly built inode to make sure they contain sane values and prevent
+ * possible vulnerabilities. Returns zero if the inode is all right and
+ * a non-zero error code if not.
+ */
+static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+{
+	int err;
+	const struct ubifs_inode *ui = ubifs_inode(inode);
+
+	if (inode->i_size > c->max_inode_sz) {
+		ubifs_err("inode is too large (%lld)",
+			  (long long)inode->i_size);
+		return 1;
+	}
+
+	if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
+		ubifs_err("unknown compression type %d", ui->compr_type);
+		return 2;
+	}
+
+	if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
+		return 4;
+
+	if (!ubifs_compr_present(ui->compr_type)) {
+		ubifs_warn("inode %lu uses '%s' compression, but it was not "
+			   "compiled in", inode->i_ino,
+			   ubifs_compr_name(ui->compr_type));
+	}
+
+	err = dbg_check_dir_size(c, inode);
+	return err;
+}
+
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+	struct inode *inode;
+
+	inode = (struct inode *)malloc(sizeof(struct ubifs_inode));
+	if (inode) {
+		inode->i_ino = ino;
+		inode->i_sb = sb;
+		list_add(&inode->i_sb_list, &sb->s_inodes);
+		inode->i_state = I_LOCK | I_NEW;
+	}
+
+	return inode;
+}
+
+int ubifs_iput(struct inode *inode)
+{
+	list_del_init(&inode->i_sb_list);
+
+	free(inode);
+	return 0;
+}
+
+/*
+ * Lock (save) inode in inode array for readback after recovery
+ */
+void iput(struct inode *inode)
+{
+	int i;
+	struct inode *ino;
+
+	/*
+	 * Search end of list
+	 */
+	for (i = 0; i < INODE_LOCKED_MAX; i++) {
+		if (inodes_locked_down[i] == NULL)
+			break;
+	}
+
+	if (i >= INODE_LOCKED_MAX) {
+		ubifs_err("Error, can't lock (save) more inodes while recovery!!!");
+		return;
+	}
+
+	/*
+	 * Allocate and use new inode
+	 */
+	ino = (struct inode *)malloc(sizeof(struct ubifs_inode));
+	memcpy(ino, inode, sizeof(struct ubifs_inode));
+
+	/*
+	 * Finally save inode in array
+	 */
+	inodes_locked_down[i] = ino;
+}
+
+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
+{
+	int err;
+	union ubifs_key key;
+	struct ubifs_ino_node *ino;
+	struct ubifs_info *c = sb->s_fs_info;
+	struct inode *inode;
+	struct ubifs_inode *ui;
+	int i;
+
+	dbg_gen("inode %lu", inum);
+
+	/*
+	 * U-Boot special handling of locked down inodes via recovery
+	 * e.g. ubifs_recover_size()
+	 */
+	for (i = 0; i < INODE_LOCKED_MAX; i++) {
+		/*
+		 * Exit on last entry (NULL), inode not found in list
+		 */
+		if (inodes_locked_down[i] == NULL)
+			break;
+
+		if (inodes_locked_down[i]->i_ino == inum) {
+			/*
+			 * We found the locked down inode in our array,
+			 * so just return this pointer instead of creating
+			 * a new one.
+			 */
+			return inodes_locked_down[i];
+		}
+	}
+
+	inode = iget_locked(sb, inum);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+	ui = ubifs_inode(inode);
+
+	ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
+	if (!ino) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	ino_key_init(c, &key, inode->i_ino);
+
+	err = ubifs_tnc_lookup(c, &key, ino);
+	if (err)
+		goto out_ino;
+
+	inode->i_flags |= (S_NOCMTIME | S_NOATIME);
+	inode->i_nlink = le32_to_cpu(ino->nlink);
+	inode->i_uid   = le32_to_cpu(ino->uid);
+	inode->i_gid   = le32_to_cpu(ino->gid);
+	inode->i_atime.tv_sec  = (int64_t)le64_to_cpu(ino->atime_sec);
+	inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec);
+	inode->i_mtime.tv_sec  = (int64_t)le64_to_cpu(ino->mtime_sec);
+	inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec);
+	inode->i_ctime.tv_sec  = (int64_t)le64_to_cpu(ino->ctime_sec);
+	inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec);
+	inode->i_mode = le32_to_cpu(ino->mode);
+	inode->i_size = le64_to_cpu(ino->size);
+
+	ui->data_len    = le32_to_cpu(ino->data_len);
+	ui->flags       = le32_to_cpu(ino->flags);
+	ui->compr_type  = le16_to_cpu(ino->compr_type);
+	ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum);
+	ui->synced_i_size = ui->ui_size = inode->i_size;
+
+	err = validate_inode(c, inode);
+	if (err)
+		goto out_invalid;
+
+	if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+		if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
+			err = 12;
+			goto out_invalid;
+		}
+		ui->data = kmalloc(ui->data_len + 1, GFP_NOFS);
+		if (!ui->data) {
+			err = -ENOMEM;
+			goto out_ino;
+		}
+		memcpy(ui->data, ino->data, ui->data_len);
+		((char *)ui->data)[ui->data_len] = '\0';
+	}
+
+	kfree(ino);
+	inode->i_state &= ~(I_LOCK | I_NEW);
+	return inode;
+
+out_invalid:
+	ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
+	dbg_dump_node(c, ino);
+	dbg_dump_inode(c, inode);
+	err = -EINVAL;
+out_ino:
+	kfree(ino);
+out:
+	ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err);
+	return ERR_PTR(err);
+}
+
+/**
+ * init_constants_early - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This function initialize UBIFS constants which do not need the superblock to
+ * be read. It also checks that the UBI volume satisfies basic UBIFS
+ * requirements. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int init_constants_early(struct ubifs_info *c)
+{
+	if (c->vi.corrupted) {
+		ubifs_warn("UBI volume is corrupted - read-only mode");
+		c->ro_media = 1;
+	}
+
+	if (c->di.ro_mode) {
+		ubifs_msg("read-only UBI device");
+		c->ro_media = 1;
+	}
+
+	if (c->vi.vol_type == UBI_STATIC_VOLUME) {
+		ubifs_msg("static UBI volume - read-only mode");
+		c->ro_media = 1;
+	}
+
+	c->leb_cnt = c->vi.size;
+	c->leb_size = c->vi.usable_leb_size;
+	c->half_leb_size = c->leb_size / 2;
+	c->min_io_size = c->di.min_io_size;
+	c->min_io_shift = fls(c->min_io_size) - 1;
+
+	if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+		ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+			  c->leb_size, UBIFS_MIN_LEB_SZ);
+		return -EINVAL;
+	}
+
+	if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+		ubifs_err("too few LEBs (%d), min. is %d",
+			  c->leb_cnt, UBIFS_MIN_LEB_CNT);
+		return -EINVAL;
+	}
+
+	if (!is_power_of_2(c->min_io_size)) {
+		ubifs_err("bad min. I/O size %d", c->min_io_size);
+		return -EINVAL;
+	}
+
+	/*
+	 * UBIFS aligns all node to 8-byte boundary, so to make function in
+	 * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
+	 * less than 8.
+	 */
+	if (c->min_io_size < 8) {
+		c->min_io_size = 8;
+		c->min_io_shift = 3;
+	}
+
+	c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+	c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size);
+
+	/*
+	 * Initialize node length ranges which are mostly needed for node
+	 * length validation.
+	 */
+	c->ranges[UBIFS_PAD_NODE].len  = UBIFS_PAD_NODE_SZ;
+	c->ranges[UBIFS_SB_NODE].len   = UBIFS_SB_NODE_SZ;
+	c->ranges[UBIFS_MST_NODE].len  = UBIFS_MST_NODE_SZ;
+	c->ranges[UBIFS_REF_NODE].len  = UBIFS_REF_NODE_SZ;
+	c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
+	c->ranges[UBIFS_CS_NODE].len   = UBIFS_CS_NODE_SZ;
+
+	c->ranges[UBIFS_INO_NODE].min_len  = UBIFS_INO_NODE_SZ;
+	c->ranges[UBIFS_INO_NODE].max_len  = UBIFS_MAX_INO_NODE_SZ;
+	c->ranges[UBIFS_ORPH_NODE].min_len =
+				UBIFS_ORPH_NODE_SZ + sizeof(__le64);
+	c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size;
+	c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ;
+	c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ;
+	c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ;
+	c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ;
+	c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ;
+	c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ;
+	/*
+	 * Minimum indexing node size is amended later when superblock is
+	 * read and the key length is known.
+	 */
+	c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ;
+	/*
+	 * Maximum indexing node size is amended later when superblock is
+	 * read and the fanout is known.
+	 */
+	c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX;
+
+	/*
+	 * Initialize dead and dark LEB space watermarks. See gc.c for comments
+	 * about these values.
+	 */
+	c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
+	c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+
+	/*
+	 * Calculate how many bytes would be wasted at the end of LEB if it was
+	 * fully filled with data nodes of maximum size. This is used in
+	 * calculations when reporting free space.
+	 */
+	c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ;
+
+	return 0;
+}
+
+/*
+ * init_constants_sb - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the superblock has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int init_constants_sb(struct ubifs_info *c)
+{
+	int tmp, err;
+	long long tmp64;
+
+	c->main_bytes = (long long)c->main_lebs * c->leb_size;
+	c->max_znode_sz = sizeof(struct ubifs_znode) +
+				c->fanout * sizeof(struct ubifs_zbranch);
+
+	tmp = ubifs_idx_node_sz(c, 1);
+	c->ranges[UBIFS_IDX_NODE].min_len = tmp;
+	c->min_idx_node_sz = ALIGN(tmp, 8);
+
+	tmp = ubifs_idx_node_sz(c, c->fanout);
+	c->ranges[UBIFS_IDX_NODE].max_len = tmp;
+	c->max_idx_node_sz = ALIGN(tmp, 8);
+
+	/* Make sure LEB size is large enough to fit full commit */
+	tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
+	tmp = ALIGN(tmp, c->min_io_size);
+	if (tmp > c->leb_size) {
+		dbg_err("too small LEB size %d, at least %d needed",
+			c->leb_size, tmp);
+		return -EINVAL;
+	}
+
+	/*
+	 * Make sure that the log is large enough to fit reference nodes for
+	 * all buds plus one reserved LEB.
+	 */
+	tmp64 = c->max_bud_bytes + c->leb_size - 1;
+	c->max_bud_cnt = div_u64(tmp64, c->leb_size);
+	tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1);
+	tmp /= c->leb_size;
+	tmp += 1;
+	if (c->log_lebs < tmp) {
+		dbg_err("too small log %d LEBs, required min. %d LEBs",
+			c->log_lebs, tmp);
+		return -EINVAL;
+	}
+
+	/*
+	 * When budgeting we assume worst-case scenarios when the pages are not
+	 * be compressed and direntries are of the maximum size.
+	 *
+	 * Note, data, which may be stored in inodes is budgeted separately, so
+	 * it is not included into 'c->inode_budget'.
+	 */
+	c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+	c->inode_budget = UBIFS_INO_NODE_SZ;
+	c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+
+	/*
+	 * When the amount of flash space used by buds becomes
+	 * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit.
+	 * The writers are unblocked when the commit is finished. To avoid
+	 * writers to be blocked UBIFS initiates background commit in advance,
+	 * when number of bud bytes becomes above the limit defined below.
+	 */
+	c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4;
+
+	/*
+	 * Ensure minimum journal size. All the bytes in the journal heads are
+	 * considered to be used, when calculating the current journal usage.
+	 * Consequently, if the journal is too small, UBIFS will treat it as
+	 * always full.
+	 */
+	tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1;
+	if (c->bg_bud_bytes < tmp64)
+		c->bg_bud_bytes = tmp64;
+	if (c->max_bud_bytes < tmp64 + c->leb_size)
+		c->max_bud_bytes = tmp64 + c->leb_size;
+
+	err = ubifs_calc_lpt_geom(c);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/*
+ * init_constants_master - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the master node has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right.
+ */
+static void init_constants_master(struct ubifs_info *c)
+{
+	long long tmp64;
+
+	c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
+	/*
+	 * Calculate total amount of FS blocks. This number is not used
+	 * internally because it does not make much sense for UBIFS, but it is
+	 * necessary to report something for the 'statfs()' call.
+	 *
+	 * Subtract the LEB reserved for GC, the LEB which is reserved for
+	 * deletions, minimum LEBs for the index, and assume only one journal
+	 * head is available.
+	 */
+	tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
+	tmp64 *= (long long)c->leb_size - c->leb_overhead;
+	tmp64 = ubifs_reported_space(c, tmp64);
+	c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
+}
+
+/**
+ * free_orphans - free orphans.
+ * @c: UBIFS file-system description object
+ */
+static void free_orphans(struct ubifs_info *c)
+{
+	struct ubifs_orphan *orph;
+
+	while (c->orph_dnext) {
+		orph = c->orph_dnext;
+		c->orph_dnext = orph->dnext;
+		list_del(&orph->list);
+		kfree(orph);
+	}
+
+	while (!list_empty(&c->orph_list)) {
+		orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
+		list_del(&orph->list);
+		kfree(orph);
+		dbg_err("orphan list not empty at unmount");
+	}
+
+	vfree(c->orph_buf);
+	c->orph_buf = NULL;
+}
+
+/**
+ * check_volume_empty - check if the UBI volume is empty.
+ * @c: UBIFS file-system description object
+ *
+ * This function checks if the UBIFS volume is empty by looking if its LEBs are
+ * mapped or not. The result of checking is stored in the @c->empty variable.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int check_volume_empty(struct ubifs_info *c)
+{
+	int lnum, err;
+
+	c->empty = 1;
+	for (lnum = 0; lnum < c->leb_cnt; lnum++) {
+		err = ubi_is_mapped(c->ubi, lnum);
+		if (unlikely(err < 0))
+			return err;
+		if (err == 1) {
+			c->empty = 0;
+			break;
+		}
+
+		cond_resched();
+	}
+
+	return 0;
+}
+
+/**
+ * mount_ubifs - mount UBIFS file-system.
+ * @c: UBIFS file-system description object
+ *
+ * This function mounts UBIFS file system. Returns zero in case of success and
+ * a negative error code in case of failure.
+ *
+ * Note, the function does not de-allocate resources it it fails half way
+ * through, and the caller has to do this instead.
+ */
+static int mount_ubifs(struct ubifs_info *c)
+{
+	struct super_block *sb = c->vfs_sb;
+	int err, mounted_read_only = (sb->s_flags & MS_RDONLY);
+	long long x;
+	size_t sz;
+
+	err = init_constants_early(c);
+	if (err)
+		return err;
+
+	err = ubifs_debugging_init(c);
+	if (err)
+		return err;
+
+	err = check_volume_empty(c);
+	if (err)
+		goto out_free;
+
+	if (c->empty && (mounted_read_only || c->ro_media)) {
+		/*
+		 * This UBI volume is empty, and read-only, or the file system
+		 * is mounted read-only - we cannot format it.
+		 */
+		ubifs_err("can't format empty UBI volume: read-only %s",
+			  c->ro_media ? "UBI volume" : "mount");
+		err = -EROFS;
+		goto out_free;
+	}
+
+	if (c->ro_media && !mounted_read_only) {
+		ubifs_err("cannot mount read-write - read-only media");
+		err = -EROFS;
+		goto out_free;
+	}
+
+	/*
+	 * The requirement for the buffer is that it should fit indexing B-tree
+	 * height amount of integers. We assume the height if the TNC tree will
+	 * never exceed 64.
+	 */
+	err = -ENOMEM;
+	c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL);
+	if (!c->bottom_up_buf)
+		goto out_free;
+
+	c->sbuf = vmalloc(c->leb_size);
+	if (!c->sbuf)
+		goto out_free;
+
+	/*
+	 * We have to check all CRCs, even for data nodes, when we mount the FS
+	 * (specifically, when we are replaying).
+	 */
+	c->always_chk_crc = 1;
+
+	err = ubifs_read_superblock(c);
+	if (err)
+		goto out_free;
+
+	/*
+	 * Make sure the compressor which is set as default in the superblock
+	 * or overridden by mount options is actually compiled in.
+	 */
+	if (!ubifs_compr_present(c->default_compr)) {
+		ubifs_err("'compressor \"%s\" is not compiled in",
+			  ubifs_compr_name(c->default_compr));
+		goto out_free;
+	}
+
+	dbg_failure_mode_registration(c);
+
+	err = init_constants_sb(c);
+	if (err)
+		goto out_free;
+
+	sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
+	sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
+	c->cbuf = kmalloc(sz, GFP_NOFS);
+	if (!c->cbuf) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
+
+	err = ubifs_read_master(c);
+	if (err)
+		goto out_master;
+
+	init_constants_master(c);
+
+	if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+		ubifs_msg("recovery needed");
+		c->need_recovery = 1;
+	}
+
+	err = ubifs_lpt_init(c, 1, !mounted_read_only);
+	if (err)
+		goto out_lpt;
+
+	err = dbg_check_idx_size(c, c->old_idx_sz);
+	if (err)
+		goto out_lpt;
+
+	err = ubifs_replay_journal(c);
+	if (err)
+		goto out_journal;
+
+	err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only);
+	if (err)
+		goto out_orphans;
+
+	if (c->need_recovery) {
+		err = ubifs_recover_size(c);
+		if (err)
+			goto out_orphans;
+	}
+
+	spin_lock(&ubifs_infos_lock);
+	list_add_tail(&c->infos_list, &ubifs_infos);
+	spin_unlock(&ubifs_infos_lock);
+
+	if (c->need_recovery) {
+		if (mounted_read_only)
+			ubifs_msg("recovery deferred");
+		else {
+			c->need_recovery = 0;
+			ubifs_msg("recovery completed");
+		}
+	}
+
+	err = dbg_check_filesystem(c);
+	if (err)
+		goto out_infos;
+
+	c->always_chk_crc = 0;
+
+	ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+		  c->vi.ubi_num, c->vi.vol_id, c->vi.name);
+	if (mounted_read_only)
+		ubifs_msg("mounted read-only");
+	x = (long long)c->main_lebs * c->leb_size;
+	ubifs_msg("file system size:   %lld bytes (%lld KiB, %lld MiB, %d "
+		  "LEBs)", x, x >> 10, x >> 20, c->main_lebs);
+	x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
+	ubifs_msg("journal size:       %lld bytes (%lld KiB, %lld MiB, %d "
+		  "LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
+	ubifs_msg("media format:       %d (latest is %d)",
+		  c->fmt_version, UBIFS_FORMAT_VERSION);
+	ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
+	ubifs_msg("reserved for root:  %llu bytes (%llu KiB)",
+		c->report_rp_size, c->report_rp_size >> 10);
+
+	dbg_msg("compiled on:         " __DATE__ " at " __TIME__);
+	dbg_msg("min. I/O unit size:  %d bytes", c->min_io_size);
+	dbg_msg("LEB size:            %d bytes (%d KiB)",
+		c->leb_size, c->leb_size >> 10);
+	dbg_msg("data journal heads:  %d",
+		c->jhead_cnt - NONDATA_JHEADS_CNT);
+	dbg_msg("UUID:                %02X%02X%02X%02X-%02X%02X"
+	       "-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+	       c->uuid[0], c->uuid[1], c->uuid[2], c->uuid[3],
+	       c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
+	       c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
+	       c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
+	dbg_msg("big_lpt              %d", c->big_lpt);
+	dbg_msg("log LEBs:            %d (%d - %d)",
+		c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
+	dbg_msg("LPT area LEBs:       %d (%d - %d)",
+		c->lpt_lebs, c->lpt_first, c->lpt_last);
+	dbg_msg("orphan area LEBs:    %d (%d - %d)",
+		c->orph_lebs, c->orph_first, c->orph_last);
+	dbg_msg("main area LEBs:      %d (%d - %d)",
+		c->main_lebs, c->main_first, c->leb_cnt - 1);
+	dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
+	dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
+		c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
+	dbg_msg("key hash type:       %d", c->key_hash_type);
+	dbg_msg("tree fanout:         %d", c->fanout);
+	dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
+	dbg_msg("first main LEB:      %d", c->main_first);
+	dbg_msg("max. znode size      %d", c->max_znode_sz);
+	dbg_msg("max. index node size %d", c->max_idx_node_sz);
+	dbg_msg("node sizes:          data %zu, inode %zu, dentry %zu",
+		UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ);
+	dbg_msg("node sizes:          trun %zu, sb %zu, master %zu",
+		UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+	dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
+		UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+	dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu",
+	        UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+		UBIFS_MAX_DENT_NODE_SZ);
+	dbg_msg("dead watermark:      %d", c->dead_wm);
+	dbg_msg("dark watermark:      %d", c->dark_wm);
+	dbg_msg("LEB overhead:        %d", c->leb_overhead);
+	x = (long long)c->main_lebs * c->dark_wm;
+	dbg_msg("max. dark space:     %lld (%lld KiB, %lld MiB)",
+		x, x >> 10, x >> 20);
+	dbg_msg("maximum bud bytes:   %lld (%lld KiB, %lld MiB)",
+		c->max_bud_bytes, c->max_bud_bytes >> 10,
+		c->max_bud_bytes >> 20);
+	dbg_msg("BG commit bud bytes: %lld (%lld KiB, %lld MiB)",
+		c->bg_bud_bytes, c->bg_bud_bytes >> 10,
+		c->bg_bud_bytes >> 20);
+	dbg_msg("current bud bytes    %lld (%lld KiB, %lld MiB)",
+		c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
+	dbg_msg("max. seq. number:    %llu", c->max_sqnum);
+	dbg_msg("commit number:       %llu", c->cmt_no);
+
+	return 0;
+
+out_infos:
+	spin_lock(&ubifs_infos_lock);
+	list_del(&c->infos_list);
+	spin_unlock(&ubifs_infos_lock);
+out_orphans:
+	free_orphans(c);
+out_journal:
+out_lpt:
+	ubifs_lpt_free(c, 0);
+out_master:
+	kfree(c->mst_node);
+	kfree(c->rcvrd_mst_node);
+	if (c->bgt)
+		kthread_stop(c->bgt);
+	kfree(c->cbuf);
+out_free:
+	vfree(c->ileb_buf);
+	vfree(c->sbuf);
+	kfree(c->bottom_up_buf);
+	ubifs_debugging_exit(c);
+	return err;
+}
+
+/**
+ * ubifs_umount - un-mount UBIFS file-system.
+ * @c: UBIFS file-system description object
+ *
+ * Note, this function is called to free allocated resourced when un-mounting,
+ * as well as free resources when an error occurred while we were half way
+ * through mounting (error path cleanup function). So it has to make sure the
+ * resource was actually allocated before freeing it.
+ */
+static void ubifs_umount(struct ubifs_info *c)
+{
+	dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
+		c->vi.vol_id);
+
+	spin_lock(&ubifs_infos_lock);
+	list_del(&c->infos_list);
+	spin_unlock(&ubifs_infos_lock);
+
+	if (c->bgt)
+		kthread_stop(c->bgt);
+
+	free_orphans(c);
+	ubifs_lpt_free(c, 0);
+
+	kfree(c->cbuf);
+	kfree(c->rcvrd_mst_node);
+	kfree(c->mst_node);
+	vfree(c->ileb_buf);
+	vfree(c->sbuf);
+	kfree(c->bottom_up_buf);
+	ubifs_debugging_exit(c);
+
+	/* Finally free U-Boot's global copy of superblock */
+	free(ubifs_sb->s_fs_info);
+	free(ubifs_sb);
+}
+
+/**
+ * open_ubi - parse UBI device name string and open the UBI device.
+ * @name: UBI volume name
+ * @mode: UBI volume open mode
+ *
+ * There are several ways to specify UBI volumes when mounting UBIFS:
+ * o ubiX_Y    - UBI device number X, volume Y;
+ * o ubiY      - UBI device number 0, volume Y;
+ * o ubiX:NAME - mount UBI device X, volume with name NAME;
+ * o ubi:NAME  - mount UBI device 0, volume with name NAME.
+ *
+ * Alternative '!' separator may be used instead of ':' (because some shells
+ * like busybox may interpret ':' as an NFS host name separator). This function
+ * returns ubi volume object in case of success and a negative error code in
+ * case of failure.
+ */
+static struct ubi_volume_desc *open_ubi(const char *name, int mode)
+{
+	int dev, vol;
+	char *endptr;
+
+	if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i')
+		return ERR_PTR(-EINVAL);
+
+	/* ubi:NAME method */
+	if ((name[3] == ':' || name[3] == '!') && name[4] != '\0')
+		return ubi_open_volume_nm(0, name + 4, mode);
+
+	if (!isdigit(name[3]))
+		return ERR_PTR(-EINVAL);
+
+	dev = simple_strtoul(name + 3, &endptr, 0);
+
+	/* ubiY method */
+	if (*endptr == '\0')
+		return ubi_open_volume(0, dev, mode);
+
+	/* ubiX_Y method */
+	if (*endptr == '_' && isdigit(endptr[1])) {
+		vol = simple_strtoul(endptr + 1, &endptr, 0);
+		if (*endptr != '\0')
+			return ERR_PTR(-EINVAL);
+		return ubi_open_volume(dev, vol, mode);
+	}
+
+	/* ubiX:NAME method */
+	if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0')
+		return ubi_open_volume_nm(dev, ++endptr, mode);
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct ubi_volume_desc *ubi = sb->s_fs_info;
+	struct ubifs_info *c;
+	struct inode *root;
+	int err;
+
+	c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL);
+	if (!c)
+		return -ENOMEM;
+
+	spin_lock_init(&c->cnt_lock);
+	spin_lock_init(&c->cs_lock);
+	spin_lock_init(&c->buds_lock);
+	spin_lock_init(&c->space_lock);
+	spin_lock_init(&c->orphan_lock);
+	init_rwsem(&c->commit_sem);
+	mutex_init(&c->lp_mutex);
+	mutex_init(&c->tnc_mutex);
+	mutex_init(&c->log_mutex);
+	mutex_init(&c->mst_mutex);
+	mutex_init(&c->umount_mutex);
+	init_waitqueue_head(&c->cmt_wq);
+	c->buds = RB_ROOT;
+	c->old_idx = RB_ROOT;
+	c->size_tree = RB_ROOT;
+	c->orph_tree = RB_ROOT;
+	INIT_LIST_HEAD(&c->infos_list);
+	INIT_LIST_HEAD(&c->idx_gc);
+	INIT_LIST_HEAD(&c->replay_list);
+	INIT_LIST_HEAD(&c->replay_buds);
+	INIT_LIST_HEAD(&c->uncat_list);
+	INIT_LIST_HEAD(&c->empty_list);
+	INIT_LIST_HEAD(&c->freeable_list);
+	INIT_LIST_HEAD(&c->frdi_idx_list);
+	INIT_LIST_HEAD(&c->unclean_leb_list);
+	INIT_LIST_HEAD(&c->old_buds);
+	INIT_LIST_HEAD(&c->orph_list);
+	INIT_LIST_HEAD(&c->orph_new);
+
+	c->highest_inum = UBIFS_FIRST_INO;
+	c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
+
+	ubi_get_volume_info(ubi, &c->vi);
+	ubi_get_device_info(c->vi.ubi_num, &c->di);
+
+	/* Re-open the UBI device in read-write mode */
+	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+	if (IS_ERR(c->ubi)) {
+		err = PTR_ERR(c->ubi);
+		goto out_free;
+	}
+
+	c->vfs_sb = sb;
+
+	sb->s_fs_info = c;
+	sb->s_magic = UBIFS_SUPER_MAGIC;
+	sb->s_blocksize = UBIFS_BLOCK_SIZE;
+	sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
+	sb->s_dev = c->vi.cdev;
+	sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
+	if (c->max_inode_sz > MAX_LFS_FILESIZE)
+		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
+
+	mutex_lock(&c->umount_mutex);
+	err = mount_ubifs(c);
+	if (err) {
+		ubifs_assert(err < 0);
+		goto out_unlock;
+	}
+
+	/* Read the root inode */
+	root = ubifs_iget(sb, UBIFS_ROOT_INO);
+	if (IS_ERR(root)) {
+		err = PTR_ERR(root);
+		goto out_umount;
+	}
+
+	sb->s_root = NULL;
+
+	mutex_unlock(&c->umount_mutex);
+	return 0;
+
+out_umount:
+	ubifs_umount(c);
+out_unlock:
+	mutex_unlock(&c->umount_mutex);
+	ubi_close_volume(c->ubi);
+out_free:
+	kfree(c);
+	return err;
+}
+
+static int sb_test(struct super_block *sb, void *data)
+{
+	dev_t *dev = data;
+
+	return sb->s_dev == *dev;
+}
+
+static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
+			const char *name, void *data, struct vfsmount *mnt)
+{
+	struct ubi_volume_desc *ubi;
+	struct ubi_volume_info vi;
+	struct super_block *sb;
+	int err;
+
+	dbg_gen("name %s, flags %#x", name, flags);
+
+	/*
+	 * Get UBI device number and volume ID. Mount it read-only so far
+	 * because this might be a new mount point, and UBI allows only one
+	 * read-write user at a time.
+	 */
+	ubi = open_ubi(name, UBI_READONLY);
+	if (IS_ERR(ubi)) {
+		ubifs_err("cannot open \"%s\", error %d",
+			  name, (int)PTR_ERR(ubi));
+		return PTR_ERR(ubi);
+	}
+	ubi_get_volume_info(ubi, &vi);
+
+	dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
+
+	sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev);
+	if (IS_ERR(sb)) {
+		err = PTR_ERR(sb);
+		goto out_close;
+	}
+
+	if (sb->s_root) {
+		/* A new mount point for already mounted UBIFS */
+		dbg_gen("this ubi volume is already mounted");
+		if ((flags ^ sb->s_flags) & MS_RDONLY) {
+			err = -EBUSY;
+			goto out_deact;
+		}
+	} else {
+		sb->s_flags = flags;
+		/*
+		 * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
+		 * replaced by 'c'.
+		 */
+		sb->s_fs_info = ubi;
+		err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+		if (err)
+			goto out_deact;
+		/* We do not support atime */
+		sb->s_flags |= MS_ACTIVE | MS_NOATIME;
+	}
+
+	/* 'fill_super()' opens ubi again so we must close it here */
+	ubi_close_volume(ubi);
+
+	ubifs_sb = sb;
+	return 0;
+
+out_deact:
+	up_write(&sb->s_umount);
+out_close:
+	ubi_close_volume(ubi);
+	return err;
+}
+
+int __init ubifs_init(void)
+{
+	int err;
+
+	BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24);
+
+	/* Make sure node sizes are 8-byte aligned */
+	BUILD_BUG_ON(UBIFS_CH_SZ        & 7);
+	BUILD_BUG_ON(UBIFS_INO_NODE_SZ  & 7);
+	BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_SB_NODE_SZ   & 7);
+	BUILD_BUG_ON(UBIFS_MST_NODE_SZ  & 7);
+	BUILD_BUG_ON(UBIFS_REF_NODE_SZ  & 7);
+	BUILD_BUG_ON(UBIFS_CS_NODE_SZ   & 7);
+	BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7);
+
+	BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ  & 7);
+	BUILD_BUG_ON(UBIFS_MAX_NODE_SZ      & 7);
+	BUILD_BUG_ON(MIN_WRITE_SZ           & 7);
+
+	/* Check min. node size */
+	BUILD_BUG_ON(UBIFS_INO_NODE_SZ  < MIN_WRITE_SZ);
+	BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ);
+	BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ);
+	BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ);
+
+	BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
+	BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ);
+	BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ);
+	BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ  > UBIFS_MAX_NODE_SZ);
+
+	/* Defined node sizes */
+	BUILD_BUG_ON(UBIFS_SB_NODE_SZ  != 4096);
+	BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512);
+	BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160);
+	BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64);
+
+	/*
+	 * We use 2 bit wide bit-fields to store compression type, which should
+	 * be amended if more compressors are added. The bit-fields are:
+	 * @compr_type in 'struct ubifs_inode', @default_compr in
+	 * 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'.
+	 */
+	BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
+
+	/*
+	 * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
+	 * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
+	 */
+	if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) {
+		ubifs_err("VFS page cache size is %u bytes, but UBIFS requires"
+			  " at least 4096 bytes",
+			  (unsigned int)PAGE_CACHE_SIZE);
+		return -EINVAL;
+	}
+
+	err = -ENOMEM;
+
+	err = ubifs_compressors_init();
+	if (err)
+		goto out_shrinker;
+
+	return 0;
+
+out_shrinker:
+	return err;
+}
+
+/*
+ * ubifsmount...
+ */
+
+static struct file_system_type ubifs_fs_type = {
+	.name    = "ubifs",
+	.owner   = THIS_MODULE,
+	.get_sb  = ubifs_get_sb,
+};
+
+int ubifs_mount(char *vol_name)
+{
+	int flags;
+	char name[80] = "ubi:";
+	void *data;
+	struct vfsmount *mnt;
+	int ret;
+	struct ubifs_info *c;
+
+	/*
+	 * First unmount if allready mounted
+	 */
+	if (ubifs_sb)
+		ubifs_umount(ubifs_sb->s_fs_info);
+
+	INIT_LIST_HEAD(&ubifs_infos);
+
+	/*
+	 * Mount in read-only mode
+	 */
+	flags = MS_RDONLY;
+	strcat(name, vol_name);
+	data = NULL;
+	mnt = NULL;
+	ret = ubifs_get_sb(&ubifs_fs_type, flags, name, data, mnt);
+	if (ret) {
+		printf("Error reading superblock on volume '%s'!\n", name);
+		return -1;
+	}
+
+	c = ubifs_sb->s_fs_info;
+	ubi_close_volume(c->ubi);
+
+	return 0;
+}
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
new file mode 100644
index 0000000..ccda938
--- /dev/null
+++ b/fs/ubifs/tnc.c
@@ -0,0 +1,2767 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file implements TNC (Tree Node Cache) which caches indexing nodes of
+ * the UBIFS B-tree.
+ *
+ * At the moment the locking rules of the TNC tree are quite simple and
+ * straightforward. We just have a mutex and lock it when we traverse the
+ * tree. If a znode is not in memory, we read it from flash while still having
+ * the mutex locked.
+ */
+
+#include "ubifs.h"
+
+/*
+ * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
+ * @NAME_LESS: name corresponding to the first argument is less than second
+ * @NAME_MATCHES: names match
+ * @NAME_GREATER: name corresponding to the second argument is greater than
+ *                first
+ * @NOT_ON_MEDIA: node referred by zbranch does not exist on the media
+ *
+ * These constants were introduce to improve readability.
+ */
+enum {
+	NAME_LESS    = 0,
+	NAME_MATCHES = 1,
+	NAME_GREATER = 2,
+	NOT_ON_MEDIA = 3,
+};
+
+/**
+ * insert_old_idx - record an index node obsoleted since the last commit start.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ *
+ * For recovery, there must always be a complete intact version of the index on
+ * flash at all times. That is called the "old index". It is the index as at the
+ * time of the last successful commit. Many of the index nodes in the old index
+ * may be dirty, but they must not be erased until the next successful commit
+ * (at which point that index becomes the old index).
+ *
+ * That means that the garbage collection and the in-the-gaps method of
+ * committing must be able to determine if an index node is in the old index.
+ * Most of the old index nodes can be found by looking up the TNC using the
+ * 'lookup_znode()' function. However, some of the old index nodes may have
+ * been deleted from the current index or may have been changed so much that
+ * they cannot be easily found. In those cases, an entry is added to an RB-tree.
+ * That is what this function does. The RB-tree is ordered by LEB number and
+ * offset because they uniquely identify the old index node.
+ */
+static int insert_old_idx(struct ubifs_info *c, int lnum, int offs)
+{
+	struct ubifs_old_idx *old_idx, *o;
+	struct rb_node **p, *parent = NULL;
+
+	old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
+	if (unlikely(!old_idx))
+		return -ENOMEM;
+	old_idx->lnum = lnum;
+	old_idx->offs = offs;
+
+	p = &c->old_idx.rb_node;
+	while (*p) {
+		parent = *p;
+		o = rb_entry(parent, struct ubifs_old_idx, rb);
+		if (lnum < o->lnum)
+			p = &(*p)->rb_left;
+		else if (lnum > o->lnum)
+			p = &(*p)->rb_right;
+		else if (offs < o->offs)
+			p = &(*p)->rb_left;
+		else if (offs > o->offs)
+			p = &(*p)->rb_right;
+		else {
+			ubifs_err("old idx added twice!");
+			kfree(old_idx);
+			return 0;
+		}
+	}
+	rb_link_node(&old_idx->rb, parent, p);
+	rb_insert_color(&old_idx->rb, &c->old_idx);
+	return 0;
+}
+
+/**
+ * insert_old_idx_znode - record a znode obsoleted since last commit start.
+ * @c: UBIFS file-system description object
+ * @znode: znode of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ */
+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode)
+{
+	if (znode->parent) {
+		struct ubifs_zbranch *zbr;
+
+		zbr = &znode->parent->zbranch[znode->iip];
+		if (zbr->len)
+			return insert_old_idx(c, zbr->lnum, zbr->offs);
+	} else
+		if (c->zroot.len)
+			return insert_old_idx(c, c->zroot.lnum,
+					      c->zroot.offs);
+	return 0;
+}
+
+/**
+ * ins_clr_old_idx_znode - record a znode obsoleted since last commit start.
+ * @c: UBIFS file-system description object
+ * @znode: znode of obsoleted index node
+ *
+ * Returns %0 on success, and a negative error code on failure.
+ */
+static int ins_clr_old_idx_znode(struct ubifs_info *c,
+				 struct ubifs_znode *znode)
+{
+	int err;
+
+	if (znode->parent) {
+		struct ubifs_zbranch *zbr;
+
+		zbr = &znode->parent->zbranch[znode->iip];
+		if (zbr->len) {
+			err = insert_old_idx(c, zbr->lnum, zbr->offs);
+			if (err)
+				return err;
+			zbr->lnum = 0;
+			zbr->offs = 0;
+			zbr->len = 0;
+		}
+	} else
+		if (c->zroot.len) {
+			err = insert_old_idx(c, c->zroot.lnum, c->zroot.offs);
+			if (err)
+				return err;
+			c->zroot.lnum = 0;
+			c->zroot.offs = 0;
+			c->zroot.len = 0;
+		}
+	return 0;
+}
+
+/**
+ * destroy_old_idx - destroy the old_idx RB-tree.
+ * @c: UBIFS file-system description object
+ *
+ * During start commit, the old_idx RB-tree is used to avoid overwriting index
+ * nodes that were in the index last commit but have since been deleted.  This
+ * is necessary for recovery i.e. the old index must be kept intact until the
+ * new index is successfully written.  The old-idx RB-tree is used for the
+ * in-the-gaps method of writing index nodes and is destroyed every commit.
+ */
+void destroy_old_idx(struct ubifs_info *c)
+{
+	struct rb_node *this = c->old_idx.rb_node;
+	struct ubifs_old_idx *old_idx;
+
+	while (this) {
+		if (this->rb_left) {
+			this = this->rb_left;
+			continue;
+		} else if (this->rb_right) {
+			this = this->rb_right;
+			continue;
+		}
+		old_idx = rb_entry(this, struct ubifs_old_idx, rb);
+		this = rb_parent(this);
+		if (this) {
+			if (this->rb_left == &old_idx->rb)
+				this->rb_left = NULL;
+			else
+				this->rb_right = NULL;
+		}
+		kfree(old_idx);
+	}
+	c->old_idx = RB_ROOT;
+}
+
+/**
+ * copy_znode - copy a dirty znode.
+ * @c: UBIFS file-system description object
+ * @znode: znode to copy
+ *
+ * A dirty znode being committed may not be changed, so it is copied.
+ */
+static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+				      struct ubifs_znode *znode)
+{
+	struct ubifs_znode *zn;
+
+	zn = kmalloc(c->max_znode_sz, GFP_NOFS);
+	if (unlikely(!zn))
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(zn, znode, c->max_znode_sz);
+	zn->cnext = NULL;
+	__set_bit(DIRTY_ZNODE, &zn->flags);
+	__clear_bit(COW_ZNODE, &zn->flags);
+
+	ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
+	__set_bit(OBSOLETE_ZNODE, &znode->flags);
+
+	if (znode->level != 0) {
+		int i;
+		const int n = zn->child_cnt;
+
+		/* The children now have new parent */
+		for (i = 0; i < n; i++) {
+			struct ubifs_zbranch *zbr = &zn->zbranch[i];
+
+			if (zbr->znode)
+				zbr->znode->parent = zn;
+		}
+	}
+
+	atomic_long_inc(&c->dirty_zn_cnt);
+	return zn;
+}
+
+/**
+ * add_idx_dirt - add dirt due to a dirty znode.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of index node
+ * @dirt: size of index node
+ *
+ * This function updates lprops dirty space and the new size of the index.
+ */
+static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
+{
+	c->calc_idx_sz -= ALIGN(dirt, 8);
+	return ubifs_add_dirt(c, lnum, dirt);
+}
+
+/**
+ * dirty_cow_znode - ensure a znode is not being committed.
+ * @c: UBIFS file-system description object
+ * @zbr: branch of znode to check
+ *
+ * Returns dirtied znode on success or negative error code on failure.
+ */
+static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
+					   struct ubifs_zbranch *zbr)
+{
+	struct ubifs_znode *znode = zbr->znode;
+	struct ubifs_znode *zn;
+	int err;
+
+	if (!test_bit(COW_ZNODE, &znode->flags)) {
+		/* znode is not being committed */
+		if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
+			atomic_long_inc(&c->dirty_zn_cnt);
+			atomic_long_dec(&c->clean_zn_cnt);
+			atomic_long_dec(&ubifs_clean_zn_cnt);
+			err = add_idx_dirt(c, zbr->lnum, zbr->len);
+			if (unlikely(err))
+				return ERR_PTR(err);
+		}
+		return znode;
+	}
+
+	zn = copy_znode(c, znode);
+	if (IS_ERR(zn))
+		return zn;
+
+	if (zbr->len) {
+		err = insert_old_idx(c, zbr->lnum, zbr->offs);
+		if (unlikely(err))
+			return ERR_PTR(err);
+		err = add_idx_dirt(c, zbr->lnum, zbr->len);
+	} else
+		err = 0;
+
+	zbr->znode = zn;
+	zbr->lnum = 0;
+	zbr->offs = 0;
+	zbr->len = 0;
+
+	if (unlikely(err))
+		return ERR_PTR(err);
+	return zn;
+}
+
+/**
+ * lnc_add - add a leaf node to the leaf node cache.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ *
+ * Leaf nodes are non-index nodes directory entry nodes or data nodes. The
+ * purpose of the leaf node cache is to save re-reading the same leaf node over
+ * and over again. Most things are cached by VFS, however the file system must
+ * cache directory entries for readdir and for resolving hash collisions. The
+ * present implementation of the leaf node cache is extremely simple, and
+ * allows for error returns that are not used but that may be needed if a more
+ * complex implementation is created.
+ *
+ * Note, this function does not add the @node object to LNC directly, but
+ * allocates a copy of the object and adds the copy to LNC. The reason for this
+ * is that @node has been allocated outside of the TNC subsystem and will be
+ * used with @c->tnc_mutex unlock upon return from the TNC subsystem. But LNC
+ * may be changed at any time, e.g. freed by the shrinker.
+ */
+static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+		   const void *node)
+{
+	int err;
+	void *lnc_node;
+	const struct ubifs_dent_node *dent = node;
+
+	ubifs_assert(!zbr->leaf);
+	ubifs_assert(zbr->len != 0);
+	ubifs_assert(is_hash_key(c, &zbr->key));
+
+	err = ubifs_validate_entry(c, dent);
+	if (err) {
+		dbg_dump_stack();
+		dbg_dump_node(c, dent);
+		return err;
+	}
+
+	lnc_node = kmalloc(zbr->len, GFP_NOFS);
+	if (!lnc_node)
+		/* We don't have to have the cache, so no error */
+		return 0;
+
+	memcpy(lnc_node, node, zbr->len);
+	zbr->leaf = lnc_node;
+	return 0;
+}
+
+ /**
+ * lnc_add_directly - add a leaf node to the leaf-node-cache.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ *
+ * This function is similar to 'lnc_add()', but it does not create a copy of
+ * @node but inserts @node to TNC directly.
+ */
+static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+			    void *node)
+{
+	int err;
+
+	ubifs_assert(!zbr->leaf);
+	ubifs_assert(zbr->len != 0);
+
+	err = ubifs_validate_entry(c, node);
+	if (err) {
+		dbg_dump_stack();
+		dbg_dump_node(c, node);
+		return err;
+	}
+
+	zbr->leaf = node;
+	return 0;
+}
+
+/**
+ * lnc_free - remove a leaf node from the leaf node cache.
+ * @zbr: zbranch of leaf node
+ * @node: leaf node
+ */
+static void lnc_free(struct ubifs_zbranch *zbr)
+{
+	if (!zbr->leaf)
+		return;
+	kfree(zbr->leaf);
+	zbr->leaf = NULL;
+}
+
+/**
+ * tnc_read_node_nm - read a "hashed" leaf node.
+ * @c: UBIFS file-system description object
+ * @zbr: key and position of the node
+ * @node: node is returned here
+ *
+ * This function reads a "hashed" node defined by @zbr from the leaf node cache
+ * (in it is there) or from the hash media, in which case the node is also
+ * added to LNC. Returns zero in case of success or a negative negative error
+ * code in case of failure.
+ */
+static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+			    void *node)
+{
+	int err;
+
+	ubifs_assert(is_hash_key(c, &zbr->key));
+
+	if (zbr->leaf) {
+		/* Read from the leaf node cache */
+		ubifs_assert(zbr->len != 0);
+		memcpy(node, zbr->leaf, zbr->len);
+		return 0;
+	}
+
+	err = ubifs_tnc_read_node(c, zbr, node);
+	if (err)
+		return err;
+
+	/* Add the node to the leaf node cache */
+	err = lnc_add(c, zbr, node);
+	return err;
+}
+
+/**
+ * try_read_node - read a node if it is a node.
+ * @c: UBIFS file-system description object
+ * @buf: buffer to read to
+ * @type: node type
+ * @len: node length (not aligned)
+ * @lnum: LEB number of node to read
+ * @offs: offset of node to read
+ *
+ * This function tries to read a node of known type and length, checks it and
+ * stores it in @buf. This function returns %1 if a node is present and %0 if
+ * a node is not present. A negative error code is returned for I/O errors.
+ * This function performs that same function as ubifs_read_node except that
+ * it does not require that there is actually a node present and instead
+ * the return code indicates if a node was read.
+ *
+ * Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
+ * is true (it is controlled by corresponding mount option). However, if
+ * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
+ * checked.
+ */
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+			 int len, int lnum, int offs)
+{
+	int err, node_len;
+	struct ubifs_ch *ch = buf;
+	uint32_t crc, node_crc;
+
+	dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+
+	err = ubi_read(c->ubi, lnum, buf, offs, len);
+	if (err) {
+		ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+			  type, lnum, offs, err);
+		return err;
+	}
+
+	if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC)
+		return 0;
+
+	if (ch->node_type != type)
+		return 0;
+
+	node_len = le32_to_cpu(ch->len);
+	if (node_len != len)
+		return 0;
+
+	if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
+		return 1;
+
+	crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+	node_crc = le32_to_cpu(ch->crc);
+	if (crc != node_crc)
+		return 0;
+
+	return 1;
+}
+
+/**
+ * fallible_read_node - try to read a leaf node.
+ * @c: UBIFS file-system description object
+ * @key:  key of node to read
+ * @zbr:  position of node
+ * @node: node returned
+ *
+ * This function tries to read a node and returns %1 if the node is read, %0
+ * if the node is not present, and a negative error code in the case of error.
+ */
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+			      struct ubifs_zbranch *zbr, void *node)
+{
+	int ret;
+
+	dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
+
+	ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
+			    zbr->offs);
+	if (ret == 1) {
+		union ubifs_key node_key;
+		struct ubifs_dent_node *dent = node;
+
+		/* All nodes have key in the same place */
+		key_read(c, &dent->key, &node_key);
+		if (keys_cmp(c, key, &node_key) != 0)
+			ret = 0;
+	}
+	if (ret == 0 && c->replaying)
+		dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
+			zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
+	return ret;
+}
+
+/**
+ * matches_name - determine if a direntry or xattr entry matches a given name.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of dent
+ * @nm: name to match
+ *
+ * This function checks if xentry/direntry referred by zbranch @zbr matches name
+ * @nm. Returns %NAME_MATCHES if it does, %NAME_LESS if the name referred by
+ * @zbr is less than @nm, and %NAME_GREATER if it is greater than @nm. In case
+ * of failure, a negative error code is returned.
+ */
+static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+			const struct qstr *nm)
+{
+	struct ubifs_dent_node *dent;
+	int nlen, err;
+
+	/* If possible, match against the dent in the leaf node cache */
+	if (!zbr->leaf) {
+		dent = kmalloc(zbr->len, GFP_NOFS);
+		if (!dent)
+			return -ENOMEM;
+
+		err = ubifs_tnc_read_node(c, zbr, dent);
+		if (err)
+			goto out_free;
+
+		/* Add the node to the leaf node cache */
+		err = lnc_add_directly(c, zbr, dent);
+		if (err)
+			goto out_free;
+	} else
+		dent = zbr->leaf;
+
+	nlen = le16_to_cpu(dent->nlen);
+	err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+	if (err == 0) {
+		if (nlen == nm->len)
+			return NAME_MATCHES;
+		else if (nlen < nm->len)
+			return NAME_LESS;
+		else
+			return NAME_GREATER;
+	} else if (err < 0)
+		return NAME_LESS;
+	else
+		return NAME_GREATER;
+
+out_free:
+	kfree(dent);
+	return err;
+}
+
+/**
+ * get_znode - get a TNC znode that may not be loaded yet.
+ * @c: UBIFS file-system description object
+ * @znode: parent znode
+ * @n: znode branch slot number
+ *
+ * This function returns the znode or a negative error code.
+ */
+static struct ubifs_znode *get_znode(struct ubifs_info *c,
+				     struct ubifs_znode *znode, int n)
+{
+	struct ubifs_zbranch *zbr;
+
+	zbr = &znode->zbranch[n];
+	if (zbr->znode)
+		znode = zbr->znode;
+	else
+		znode = ubifs_load_znode(c, zbr, znode, n);
+	return znode;
+}
+
+/**
+ * tnc_next - find next TNC entry.
+ * @c: UBIFS file-system description object
+ * @zn: znode is passed and returned here
+ * @n: znode branch slot number is passed and returned here
+ *
+ * This function returns %0 if the next TNC entry is found, %-ENOENT if there is
+ * no next entry, or a negative error code otherwise.
+ */
+static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
+{
+	struct ubifs_znode *znode = *zn;
+	int nn = *n;
+
+	nn += 1;
+	if (nn < znode->child_cnt) {
+		*n = nn;
+		return 0;
+	}
+	while (1) {
+		struct ubifs_znode *zp;
+
+		zp = znode->parent;
+		if (!zp)
+			return -ENOENT;
+		nn = znode->iip + 1;
+		znode = zp;
+		if (nn < znode->child_cnt) {
+			znode = get_znode(c, znode, nn);
+			if (IS_ERR(znode))
+				return PTR_ERR(znode);
+			while (znode->level != 0) {
+				znode = get_znode(c, znode, 0);
+				if (IS_ERR(znode))
+					return PTR_ERR(znode);
+			}
+			nn = 0;
+			break;
+		}
+	}
+	*zn = znode;
+	*n = nn;
+	return 0;
+}
+
+/**
+ * tnc_prev - find previous TNC entry.
+ * @c: UBIFS file-system description object
+ * @zn: znode is returned here
+ * @n: znode branch slot number is passed and returned here
+ *
+ * This function returns %0 if the previous TNC entry is found, %-ENOENT if
+ * there is no next entry, or a negative error code otherwise.
+ */
+static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
+{
+	struct ubifs_znode *znode = *zn;
+	int nn = *n;
+
+	if (nn > 0) {
+		*n = nn - 1;
+		return 0;
+	}
+	while (1) {
+		struct ubifs_znode *zp;
+
+		zp = znode->parent;
+		if (!zp)
+			return -ENOENT;
+		nn = znode->iip - 1;
+		znode = zp;
+		if (nn >= 0) {
+			znode = get_znode(c, znode, nn);
+			if (IS_ERR(znode))
+				return PTR_ERR(znode);
+			while (znode->level != 0) {
+				nn = znode->child_cnt - 1;
+				znode = get_znode(c, znode, nn);
+				if (IS_ERR(znode))
+					return PTR_ERR(znode);
+			}
+			nn = znode->child_cnt - 1;
+			break;
+		}
+	}
+	*zn = znode;
+	*n = nn;
+	return 0;
+}
+
+/**
+ * resolve_collision - resolve a collision.
+ * @c: UBIFS file-system description object
+ * @key: key of a directory or extended attribute entry
+ * @zn: znode is returned here
+ * @n: zbranch number is passed and returned here
+ * @nm: name of the entry
+ *
+ * This function is called for "hashed" keys to make sure that the found key
+ * really corresponds to the looked up node (directory or extended attribute
+ * entry). It returns %1 and sets @zn and @n if the collision is resolved.
+ * %0 is returned if @nm is not found and @zn and @n are set to the previous
+ * entry, i.e. to the entry after which @nm could follow if it were in TNC.
+ * This means that @n may be set to %-1 if the leftmost key in @zn is the
+ * previous one. A negative error code is returned on failures.
+ */
+static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
+			     struct ubifs_znode **zn, int *n,
+			     const struct qstr *nm)
+{
+	int err;
+
+	err = matches_name(c, &(*zn)->zbranch[*n], nm);
+	if (unlikely(err < 0))
+		return err;
+	if (err == NAME_MATCHES)
+		return 1;
+
+	if (err == NAME_GREATER) {
+		/* Look left */
+		while (1) {
+			err = tnc_prev(c, zn, n);
+			if (err == -ENOENT) {
+				ubifs_assert(*n == 0);
+				*n = -1;
+				return 0;
+			}
+			if (err < 0)
+				return err;
+			if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
+				/*
+				 * We have found the branch after which we would
+				 * like to insert, but inserting in this znode
+				 * may still be wrong. Consider the following 3
+				 * znodes, in the case where we are resolving a
+				 * collision with Key2.
+				 *
+				 *                  znode zp
+				 *            ----------------------
+				 * level 1     |  Key0  |  Key1  |
+				 *            -----------------------
+				 *                 |            |
+				 *       znode za  |            |  znode zb
+				 *          ------------      ------------
+				 * level 0  |  Key0  |        |  Key2  |
+				 *          ------------      ------------
+				 *
+				 * The lookup finds Key2 in znode zb. Lets say
+				 * there is no match and the name is greater so
+				 * we look left. When we find Key0, we end up
+				 * here. If we return now, we will insert into
+				 * znode za at slot n = 1.  But that is invalid
+				 * according to the parent's keys.  Key2 must
+				 * be inserted into znode zb.
+				 *
+				 * Note, this problem is not relevant for the
+				 * case when we go right, because
+				 * 'tnc_insert()' would correct the parent key.
+				 */
+				if (*n == (*zn)->child_cnt - 1) {
+					err = tnc_next(c, zn, n);
+					if (err) {
+						/* Should be impossible */
+						ubifs_assert(0);
+						if (err == -ENOENT)
+							err = -EINVAL;
+						return err;
+					}
+					ubifs_assert(*n == 0);
+					*n = -1;
+				}
+				return 0;
+			}
+			err = matches_name(c, &(*zn)->zbranch[*n], nm);
+			if (err < 0)
+				return err;
+			if (err == NAME_LESS)
+				return 0;
+			if (err == NAME_MATCHES)
+				return 1;
+			ubifs_assert(err == NAME_GREATER);
+		}
+	} else {
+		int nn = *n;
+		struct ubifs_znode *znode = *zn;
+
+		/* Look right */
+		while (1) {
+			err = tnc_next(c, &znode, &nn);
+			if (err == -ENOENT)
+				return 0;
+			if (err < 0)
+				return err;
+			if (keys_cmp(c, &znode->zbranch[nn].key, key))
+				return 0;
+			err = matches_name(c, &znode->zbranch[nn], nm);
+			if (err < 0)
+				return err;
+			if (err == NAME_GREATER)
+				return 0;
+			*zn = znode;
+			*n = nn;
+			if (err == NAME_MATCHES)
+				return 1;
+			ubifs_assert(err == NAME_LESS);
+		}
+	}
+}
+
+/**
+ * fallible_matches_name - determine if a dent matches a given name.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of dent
+ * @nm: name to match
+ *
+ * This is a "fallible" version of 'matches_name()' function which does not
+ * panic if the direntry/xentry referred by @zbr does not exist on the media.
+ *
+ * This function checks if xentry/direntry referred by zbranch @zbr matches name
+ * @nm. Returns %NAME_MATCHES it does, %NAME_LESS if the name referred by @zbr
+ * is less than @nm, %NAME_GREATER if it is greater than @nm, and @NOT_ON_MEDIA
+ * if xentry/direntry referred by @zbr does not exist on the media. A negative
+ * error code is returned in case of failure.
+ */
+static int fallible_matches_name(struct ubifs_info *c,
+				 struct ubifs_zbranch *zbr,
+				 const struct qstr *nm)
+{
+	struct ubifs_dent_node *dent;
+	int nlen, err;
+
+	/* If possible, match against the dent in the leaf node cache */
+	if (!zbr->leaf) {
+		dent = kmalloc(zbr->len, GFP_NOFS);
+		if (!dent)
+			return -ENOMEM;
+
+		err = fallible_read_node(c, &zbr->key, zbr, dent);
+		if (err < 0)
+			goto out_free;
+		if (err == 0) {
+			/* The node was not present */
+			err = NOT_ON_MEDIA;
+			goto out_free;
+		}
+		ubifs_assert(err == 1);
+
+		err = lnc_add_directly(c, zbr, dent);
+		if (err)
+			goto out_free;
+	} else
+		dent = zbr->leaf;
+
+	nlen = le16_to_cpu(dent->nlen);
+	err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+	if (err == 0) {
+		if (nlen == nm->len)
+			return NAME_MATCHES;
+		else if (nlen < nm->len)
+			return NAME_LESS;
+		else
+			return NAME_GREATER;
+	} else if (err < 0)
+		return NAME_LESS;
+	else
+		return NAME_GREATER;
+
+out_free:
+	kfree(dent);
+	return err;
+}
+
+/**
+ * fallible_resolve_collision - resolve a collision even if nodes are missing.
+ * @c: UBIFS file-system description object
+ * @key: key
+ * @zn: znode is returned here
+ * @n: branch number is passed and returned here
+ * @nm: name of directory entry
+ * @adding: indicates caller is adding a key to the TNC
+ *
+ * This is a "fallible" version of the 'resolve_collision()' function which
+ * does not panic if one of the nodes referred to by TNC does not exist on the
+ * media. This may happen when replaying the journal if a deleted node was
+ * Garbage-collected and the commit was not done. A branch that refers to a node
+ * that is not present is called a dangling branch. The following are the return
+ * codes for this function:
+ *  o if @nm was found, %1 is returned and @zn and @n are set to the found
+ *    branch;
+ *  o if we are @adding and @nm was not found, %0 is returned;
+ *  o if we are not @adding and @nm was not found, but a dangling branch was
+ *    found, then %1 is returned and @zn and @n are set to the dangling branch;
+ *  o a negative error code is returned in case of failure.
+ */
+static int fallible_resolve_collision(struct ubifs_info *c,
+				      const union ubifs_key *key,
+				      struct ubifs_znode **zn, int *n,
+				      const struct qstr *nm, int adding)
+{
+	struct ubifs_znode *o_znode = NULL, *znode = *zn;
+	int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
+
+	cmp = fallible_matches_name(c, &znode->zbranch[nn], nm);
+	if (unlikely(cmp < 0))
+		return cmp;
+	if (cmp == NAME_MATCHES)
+		return 1;
+	if (cmp == NOT_ON_MEDIA) {
+		o_znode = znode;
+		o_n = nn;
+		/*
+		 * We are unlucky and hit a dangling branch straight away.
+		 * Now we do not really know where to go to find the needed
+		 * branch - to the left or to the right. Well, let's try left.
+		 */
+		unsure = 1;
+	} else if (!adding)
+		unsure = 1; /* Remove a dangling branch wherever it is */
+
+	if (cmp == NAME_GREATER || unsure) {
+		/* Look left */
+		while (1) {
+			err = tnc_prev(c, zn, n);
+			if (err == -ENOENT) {
+				ubifs_assert(*n == 0);
+				*n = -1;
+				break;
+			}
+			if (err < 0)
+				return err;
+			if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) {
+				/* See comments in 'resolve_collision()' */
+				if (*n == (*zn)->child_cnt - 1) {
+					err = tnc_next(c, zn, n);
+					if (err) {
+						/* Should be impossible */
+						ubifs_assert(0);
+						if (err == -ENOENT)
+							err = -EINVAL;
+						return err;
+					}
+					ubifs_assert(*n == 0);
+					*n = -1;
+				}
+				break;
+			}
+			err = fallible_matches_name(c, &(*zn)->zbranch[*n], nm);
+			if (err < 0)
+				return err;
+			if (err == NAME_MATCHES)
+				return 1;
+			if (err == NOT_ON_MEDIA) {
+				o_znode = *zn;
+				o_n = *n;
+				continue;
+			}
+			if (!adding)
+				continue;
+			if (err == NAME_LESS)
+				break;
+			else
+				unsure = 0;
+		}
+	}
+
+	if (cmp == NAME_LESS || unsure) {
+		/* Look right */
+		*zn = znode;
+		*n = nn;
+		while (1) {
+			err = tnc_next(c, &znode, &nn);
+			if (err == -ENOENT)
+				break;
+			if (err < 0)
+				return err;
+			if (keys_cmp(c, &znode->zbranch[nn].key, key))
+				break;
+			err = fallible_matches_name(c, &znode->zbranch[nn], nm);
+			if (err < 0)
+				return err;
+			if (err == NAME_GREATER)
+				break;
+			*zn = znode;
+			*n = nn;
+			if (err == NAME_MATCHES)
+				return 1;
+			if (err == NOT_ON_MEDIA) {
+				o_znode = znode;
+				o_n = nn;
+			}
+		}
+	}
+
+	/* Never match a dangling branch when adding */
+	if (adding || !o_znode)
+		return 0;
+
+	dbg_mnt("dangling match LEB %d:%d len %d %s",
+		o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
+		o_znode->zbranch[o_n].len, DBGKEY(key));
+	*zn = o_znode;
+	*n = o_n;
+	return 1;
+}
+
+/**
+ * matches_position - determine if a zbranch matches a given position.
+ * @zbr: zbranch of dent
+ * @lnum: LEB number of dent to match
+ * @offs: offset of dent to match
+ *
+ * This function returns %1 if @lnum:@offs matches, and %0 otherwise.
+ */
+static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs)
+{
+	if (zbr->lnum == lnum && zbr->offs == offs)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * resolve_collision_directly - resolve a collision directly.
+ * @c: UBIFS file-system description object
+ * @key: key of directory entry
+ * @zn: znode is passed and returned here
+ * @n: zbranch number is passed and returned here
+ * @lnum: LEB number of dent node to match
+ * @offs: offset of dent node to match
+ *
+ * This function is used for "hashed" keys to make sure the found directory or
+ * extended attribute entry node is what was looked for. It is used when the
+ * flash address of the right node is known (@lnum:@offs) which makes it much
+ * easier to resolve collisions (no need to read entries and match full
+ * names). This function returns %1 and sets @zn and @n if the collision is
+ * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the
+ * previous directory entry. Otherwise a negative error code is returned.
+ */
+static int resolve_collision_directly(struct ubifs_info *c,
+				      const union ubifs_key *key,
+				      struct ubifs_znode **zn, int *n,
+				      int lnum, int offs)
+{
+	struct ubifs_znode *znode;
+	int nn, err;
+
+	znode = *zn;
+	nn = *n;
+	if (matches_position(&znode->zbranch[nn], lnum, offs))
+		return 1;
+
+	/* Look left */
+	while (1) {
+		err = tnc_prev(c, &znode, &nn);
+		if (err == -ENOENT)
+			break;
+		if (err < 0)
+			return err;
+		if (keys_cmp(c, &znode->zbranch[nn].key, key))
+			break;
+		if (matches_position(&znode->zbranch[nn], lnum, offs)) {
+			*zn = znode;
+			*n = nn;
+			return 1;
+		}
+	}
+
+	/* Look right */
+	znode = *zn;
+	nn = *n;
+	while (1) {
+		err = tnc_next(c, &znode, &nn);
+		if (err == -ENOENT)
+			return 0;
+		if (err < 0)
+			return err;
+		if (keys_cmp(c, &znode->zbranch[nn].key, key))
+			return 0;
+		*zn = znode;
+		*n = nn;
+		if (matches_position(&znode->zbranch[nn], lnum, offs))
+			return 1;
+	}
+}
+
+/**
+ * dirty_cow_bottom_up - dirty a znode and its ancestors.
+ * @c: UBIFS file-system description object
+ * @znode: znode to dirty
+ *
+ * If we do not have a unique key that resides in a znode, then we cannot
+ * dirty that znode from the top down (i.e. by using lookup_level0_dirty)
+ * This function records the path back to the last dirty ancestor, and then
+ * dirties the znodes on that path.
+ */
+static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
+					       struct ubifs_znode *znode)
+{
+	struct ubifs_znode *zp;
+	int *path = c->bottom_up_buf, p = 0;
+
+	ubifs_assert(c->zroot.znode);
+	ubifs_assert(znode);
+	if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) {
+		kfree(c->bottom_up_buf);
+		c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int),
+					   GFP_NOFS);
+		if (!c->bottom_up_buf)
+			return ERR_PTR(-ENOMEM);
+		path = c->bottom_up_buf;
+	}
+	if (c->zroot.znode->level) {
+		/* Go up until parent is dirty */
+		while (1) {
+			int n;
+
+			zp = znode->parent;
+			if (!zp)
+				break;
+			n = znode->iip;
+			ubifs_assert(p < c->zroot.znode->level);
+			path[p++] = n;
+			if (!zp->cnext && ubifs_zn_dirty(znode))
+				break;
+			znode = zp;
+		}
+	}
+
+	/* Come back down, dirtying as we go */
+	while (1) {
+		struct ubifs_zbranch *zbr;
+
+		zp = znode->parent;
+		if (zp) {
+			ubifs_assert(path[p - 1] >= 0);
+			ubifs_assert(path[p - 1] < zp->child_cnt);
+			zbr = &zp->zbranch[path[--p]];
+			znode = dirty_cow_znode(c, zbr);
+		} else {
+			ubifs_assert(znode == c->zroot.znode);
+			znode = dirty_cow_znode(c, &c->zroot);
+		}
+		if (IS_ERR(znode) || !p)
+			break;
+		ubifs_assert(path[p - 1] >= 0);
+		ubifs_assert(path[p - 1] < znode->child_cnt);
+		znode = znode->zbranch[path[p - 1]].znode;
+	}
+
+	return znode;
+}
+
+/**
+ * ubifs_lookup_level0 - search for zero-level znode.
+ * @c: UBIFS file-system description object
+ * @key:  key to lookup
+ * @zn: znode is returned here
+ * @n: znode branch slot number is returned here
+ *
+ * This function looks up the TNC tree and search for zero-level znode which
+ * refers key @key. The found zero-level znode is returned in @zn. There are 3
+ * cases:
+ *   o exact match, i.e. the found zero-level znode contains key @key, then %1
+ *     is returned and slot number of the matched branch is stored in @n;
+ *   o not exact match, which means that zero-level znode does not contain
+ *     @key, then %0 is returned and slot number of the closed branch is stored
+ *     in  @n;
+ *   o @key is so small that it is even less than the lowest key of the
+ *     leftmost zero-level node, then %0 is returned and %0 is stored in @n.
+ *
+ * Note, when the TNC tree is traversed, some znodes may be absent, then this
+ * function reads corresponding indexing nodes and inserts them to TNC. In
+ * case of failure, a negative error code is returned.
+ */
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+			struct ubifs_znode **zn, int *n)
+{
+	int err, exact;
+	struct ubifs_znode *znode;
+	unsigned long time = get_seconds();
+
+	dbg_tnc("search key %s", DBGKEY(key));
+
+	znode = c->zroot.znode;
+	if (unlikely(!znode)) {
+		znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+	}
+
+	znode->time = time;
+
+	while (1) {
+		struct ubifs_zbranch *zbr;
+
+		exact = ubifs_search_zbranch(c, znode, key, n);
+
+		if (znode->level == 0)
+			break;
+
+		if (*n < 0)
+			*n = 0;
+		zbr = &znode->zbranch[*n];
+
+		if (zbr->znode) {
+			znode->time = time;
+			znode = zbr->znode;
+			continue;
+		}
+
+		/* znode is not in TNC cache, load it from the media */
+		znode = ubifs_load_znode(c, zbr, znode, *n);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+	}
+
+	*zn = znode;
+	if (exact || !is_hash_key(c, key) || *n != -1) {
+		dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
+		return exact;
+	}
+
+	/*
+	 * Here is a tricky place. We have not found the key and this is a
+	 * "hashed" key, which may collide. The rest of the code deals with
+	 * situations like this:
+	 *
+	 *                  | 3 | 5 |
+	 *                  /       \
+	 *          | 3 | 5 |      | 6 | 7 | (x)
+	 *
+	 * Or more a complex example:
+	 *
+	 *                | 1 | 5 |
+	 *                /       \
+	 *       | 1 | 3 |         | 5 | 8 |
+	 *              \           /
+	 *          | 5 | 5 |   | 6 | 7 | (x)
+	 *
+	 * In the examples, if we are looking for key "5", we may reach nodes
+	 * marked with "(x)". In this case what we have do is to look at the
+	 * left and see if there is "5" key there. If there is, we have to
+	 * return it.
+	 *
+	 * Note, this whole situation is possible because we allow to have
+	 * elements which are equivalent to the next key in the parent in the
+	 * children of current znode. For example, this happens if we split a
+	 * znode like this: | 3 | 5 | 5 | 6 | 7 |, which results in something
+	 * like this:
+	 *                      | 3 | 5 |
+	 *                       /     \
+	 *                | 3 | 5 |   | 5 | 6 | 7 |
+	 *                              ^
+	 * And this becomes what is at the first "picture" after key "5" marked
+	 * with "^" is removed. What could be done is we could prohibit
+	 * splitting in the middle of the colliding sequence. Also, when
+	 * removing the leftmost key, we would have to correct the key of the
+	 * parent node, which would introduce additional complications. Namely,
+	 * if we changed the the leftmost key of the parent znode, the garbage
+	 * collector would be unable to find it (GC is doing this when GC'ing
+	 * indexing LEBs). Although we already have an additional RB-tree where
+	 * we save such changed znodes (see 'ins_clr_old_idx_znode()') until
+	 * after the commit. But anyway, this does not look easy to implement
+	 * so we did not try this.
+	 */
+	err = tnc_prev(c, &znode, n);
+	if (err == -ENOENT) {
+		dbg_tnc("found 0, lvl %d, n -1", znode->level);
+		*n = -1;
+		return 0;
+	}
+	if (unlikely(err < 0))
+		return err;
+	if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
+		dbg_tnc("found 0, lvl %d, n -1", znode->level);
+		*n = -1;
+		return 0;
+	}
+
+	dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
+	*zn = znode;
+	return 1;
+}
+
+/**
+ * lookup_level0_dirty - search for zero-level znode dirtying.
+ * @c: UBIFS file-system description object
+ * @key:  key to lookup
+ * @zn: znode is returned here
+ * @n: znode branch slot number is returned here
+ *
+ * This function looks up the TNC tree and search for zero-level znode which
+ * refers key @key. The found zero-level znode is returned in @zn. There are 3
+ * cases:
+ *   o exact match, i.e. the found zero-level znode contains key @key, then %1
+ *     is returned and slot number of the matched branch is stored in @n;
+ *   o not exact match, which means that zero-level znode does not contain @key
+ *     then %0 is returned and slot number of the closed branch is stored in
+ *     @n;
+ *   o @key is so small that it is even less than the lowest key of the
+ *     leftmost zero-level node, then %0 is returned and %-1 is stored in @n.
+ *
+ * Additionally all znodes in the path from the root to the located zero-level
+ * znode are marked as dirty.
+ *
+ * Note, when the TNC tree is traversed, some znodes may be absent, then this
+ * function reads corresponding indexing nodes and inserts them to TNC. In
+ * case of failure, a negative error code is returned.
+ */
+static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
+			       struct ubifs_znode **zn, int *n)
+{
+	int err, exact;
+	struct ubifs_znode *znode;
+	unsigned long time = get_seconds();
+
+	dbg_tnc("search and dirty key %s", DBGKEY(key));
+
+	znode = c->zroot.znode;
+	if (unlikely(!znode)) {
+		znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+	}
+
+	znode = dirty_cow_znode(c, &c->zroot);
+	if (IS_ERR(znode))
+		return PTR_ERR(znode);
+
+	znode->time = time;
+
+	while (1) {
+		struct ubifs_zbranch *zbr;
+
+		exact = ubifs_search_zbranch(c, znode, key, n);
+
+		if (znode->level == 0)
+			break;
+
+		if (*n < 0)
+			*n = 0;
+		zbr = &znode->zbranch[*n];
+
+		if (zbr->znode) {
+			znode->time = time;
+			znode = dirty_cow_znode(c, zbr);
+			if (IS_ERR(znode))
+				return PTR_ERR(znode);
+			continue;
+		}
+
+		/* znode is not in TNC cache, load it from the media */
+		znode = ubifs_load_znode(c, zbr, znode, *n);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+		znode = dirty_cow_znode(c, zbr);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+	}
+
+	*zn = znode;
+	if (exact || !is_hash_key(c, key) || *n != -1) {
+		dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n);
+		return exact;
+	}
+
+	/*
+	 * See huge comment at 'lookup_level0_dirty()' what is the rest of the
+	 * code.
+	 */
+	err = tnc_prev(c, &znode, n);
+	if (err == -ENOENT) {
+		*n = -1;
+		dbg_tnc("found 0, lvl %d, n -1", znode->level);
+		return 0;
+	}
+	if (unlikely(err < 0))
+		return err;
+	if (keys_cmp(c, key, &znode->zbranch[*n].key)) {
+		*n = -1;
+		dbg_tnc("found 0, lvl %d, n -1", znode->level);
+		return 0;
+	}
+
+	if (znode->cnext || !ubifs_zn_dirty(znode)) {
+		znode = dirty_cow_bottom_up(c, znode);
+		if (IS_ERR(znode))
+			return PTR_ERR(znode);
+	}
+
+	dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
+	*zn = znode;
+	return 1;
+}
+
+/**
+ * maybe_leb_gced - determine if a LEB may have been garbage collected.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @gc_seq1: garbage collection sequence number
+ *
+ * This function determines if @lnum may have been garbage collected since
+ * sequence number @gc_seq1. If it may have been then %1 is returned, otherwise
+ * %0 is returned.
+ */
+static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
+{
+	/*
+	 * No garbage collection in the read-only U-Boot implementation
+	 */
+	return 0;
+}
+
+/**
+ * ubifs_tnc_locate - look up a file-system node and return it and its location.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @lnum: LEB number is returned here
+ * @offs: offset is returned here
+ *
+ * This function look up and reads node with key @key. The caller has to make
+ * sure the @node buffer is large enough to fit the node. Returns zero in case
+ * of success, %-ENOENT if the node was not found, and a negative error code in
+ * case of failure. The node location can be returned in @lnum and @offs.
+ */
+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
+		     void *node, int *lnum, int *offs)
+{
+	int found, n, err, safely = 0, gc_seq1;
+	struct ubifs_znode *znode;
+	struct ubifs_zbranch zbr, *zt;
+
+again:
+	mutex_lock(&c->tnc_mutex);
+	found = ubifs_lookup_level0(c, key, &znode, &n);
+	if (!found) {
+		err = -ENOENT;
+		goto out;
+	} else if (found < 0) {
+		err = found;
+		goto out;
+	}
+	zt = &znode->zbranch[n];
+	if (lnum) {
+		*lnum = zt->lnum;
+		*offs = zt->offs;
+	}
+	if (is_hash_key(c, key)) {
+		/*
+		 * In this case the leaf node cache gets used, so we pass the
+		 * address of the zbranch and keep the mutex locked
+		 */
+		err = tnc_read_node_nm(c, zt, node);
+		goto out;
+	}
+	if (safely) {
+		err = ubifs_tnc_read_node(c, zt, node);
+		goto out;
+	}
+	/* Drop the TNC mutex prematurely and race with garbage collection */
+	zbr = znode->zbranch[n];
+	gc_seq1 = c->gc_seq;
+	mutex_unlock(&c->tnc_mutex);
+
+	err = fallible_read_node(c, key, &zbr, node);
+	if (err <= 0 || maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
+		/*
+		 * The node may have been GC'ed out from under us so try again
+		 * while keeping the TNC mutex locked.
+		 */
+		safely = 1;
+		goto again;
+	}
+	return 0;
+
+out:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_get_bu_keys - lookup keys for bulk-read.
+ * @c: UBIFS file-system description object
+ * @bu: bulk-read parameters and results
+ *
+ * Lookup consecutive data node keys for the same inode that reside
+ * consecutively in the same LEB. This function returns zero in case of success
+ * and a negative error code in case of failure.
+ *
+ * Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
+ * makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
+ * maximum possible amount of nodes for bulk-read.
+ */
+int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
+{
+	int n, err = 0, lnum = -1, uninitialized_var(offs);
+	int uninitialized_var(len);
+	unsigned int block = key_block(c, &bu->key);
+	struct ubifs_znode *znode;
+
+	bu->cnt = 0;
+	bu->blk_cnt = 0;
+	bu->eof = 0;
+
+	mutex_lock(&c->tnc_mutex);
+	/* Find first key */
+	err = ubifs_lookup_level0(c, &bu->key, &znode, &n);
+	if (err < 0)
+		goto out;
+	if (err) {
+		/* Key found */
+		len = znode->zbranch[n].len;
+		/* The buffer must be big enough for at least 1 node */
+		if (len > bu->buf_len) {
+			err = -EINVAL;
+			goto out;
+		}
+		/* Add this key */
+		bu->zbranch[bu->cnt++] = znode->zbranch[n];
+		bu->blk_cnt += 1;
+		lnum = znode->zbranch[n].lnum;
+		offs = ALIGN(znode->zbranch[n].offs + len, 8);
+	}
+	while (1) {
+		struct ubifs_zbranch *zbr;
+		union ubifs_key *key;
+		unsigned int next_block;
+
+		/* Find next key */
+		err = tnc_next(c, &znode, &n);
+		if (err)
+			goto out;
+		zbr = &znode->zbranch[n];
+		key = &zbr->key;
+		/* See if there is another data key for this file */
+		if (key_inum(c, key) != key_inum(c, &bu->key) ||
+		    key_type(c, key) != UBIFS_DATA_KEY) {
+			err = -ENOENT;
+			goto out;
+		}
+		if (lnum < 0) {
+			/* First key found */
+			lnum = zbr->lnum;
+			offs = ALIGN(zbr->offs + zbr->len, 8);
+			len = zbr->len;
+			if (len > bu->buf_len) {
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			/*
+			 * The data nodes must be in consecutive positions in
+			 * the same LEB.
+			 */
+			if (zbr->lnum != lnum || zbr->offs != offs)
+				goto out;
+			offs += ALIGN(zbr->len, 8);
+			len = ALIGN(len, 8) + zbr->len;
+			/* Must not exceed buffer length */
+			if (len > bu->buf_len)
+				goto out;
+		}
+		/* Allow for holes */
+		next_block = key_block(c, key);
+		bu->blk_cnt += (next_block - block - 1);
+		if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
+			goto out;
+		block = next_block;
+		/* Add this key */
+		bu->zbranch[bu->cnt++] = *zbr;
+		bu->blk_cnt += 1;
+		/* See if we have room for more */
+		if (bu->cnt >= UBIFS_MAX_BULK_READ)
+			goto out;
+		if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
+			goto out;
+	}
+out:
+	if (err == -ENOENT) {
+		bu->eof = 1;
+		err = 0;
+	}
+	bu->gc_seq = c->gc_seq;
+	mutex_unlock(&c->tnc_mutex);
+	if (err)
+		return err;
+	/*
+	 * An enormous hole could cause bulk-read to encompass too many
+	 * page cache pages, so limit the number here.
+	 */
+	if (bu->blk_cnt > UBIFS_MAX_BULK_READ)
+		bu->blk_cnt = UBIFS_MAX_BULK_READ;
+	/*
+	 * Ensure that bulk-read covers a whole number of page cache
+	 * pages.
+	 */
+	if (UBIFS_BLOCKS_PER_PAGE == 1 ||
+	    !(bu->blk_cnt & (UBIFS_BLOCKS_PER_PAGE - 1)))
+		return 0;
+	if (bu->eof) {
+		/* At the end of file we can round up */
+		bu->blk_cnt += UBIFS_BLOCKS_PER_PAGE - 1;
+		return 0;
+	}
+	/* Exclude data nodes that do not make up a whole page cache page */
+	block = key_block(c, &bu->key) + bu->blk_cnt;
+	block &= ~(UBIFS_BLOCKS_PER_PAGE - 1);
+	while (bu->cnt) {
+		if (key_block(c, &bu->zbranch[bu->cnt - 1].key) < block)
+			break;
+		bu->cnt -= 1;
+	}
+	return 0;
+}
+
+/**
+ * validate_data_node - validate data nodes for bulk-read.
+ * @c: UBIFS file-system description object
+ * @buf: buffer containing data node to validate
+ * @zbr: zbranch of data node to validate
+ *
+ * This functions returns %0 on success or a negative error code on failure.
+ */
+static int validate_data_node(struct ubifs_info *c, void *buf,
+			      struct ubifs_zbranch *zbr)
+{
+	union ubifs_key key1;
+	struct ubifs_ch *ch = buf;
+	int err, len;
+
+	if (ch->node_type != UBIFS_DATA_NODE) {
+		ubifs_err("bad node type (%d but expected %d)",
+			  ch->node_type, UBIFS_DATA_NODE);
+		goto out_err;
+	}
+
+	err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
+	if (err) {
+		ubifs_err("expected node type %d", UBIFS_DATA_NODE);
+		goto out;
+	}
+
+	len = le32_to_cpu(ch->len);
+	if (len != zbr->len) {
+		ubifs_err("bad node length %d, expected %d", len, zbr->len);
+		goto out_err;
+	}
+
+	/* Make sure the key of the read node is correct */
+	key_read(c, buf + UBIFS_KEY_OFFSET, &key1);
+	if (!keys_eq(c, &zbr->key, &key1)) {
+		ubifs_err("bad key in node at LEB %d:%d",
+			  zbr->lnum, zbr->offs);
+		dbg_tnc("looked for key %s found node's key %s",
+			DBGKEY(&zbr->key), DBGKEY1(&key1));
+		goto out_err;
+	}
+
+	return 0;
+
+out_err:
+	err = -EINVAL;
+out:
+	ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
+	dbg_dump_node(c, buf);
+	dbg_dump_stack();
+	return err;
+}
+
+/**
+ * ubifs_tnc_bulk_read - read a number of data nodes in one go.
+ * @c: UBIFS file-system description object
+ * @bu: bulk-read parameters and results
+ *
+ * This functions reads and validates the data nodes that were identified by the
+ * 'ubifs_tnc_get_bu_keys()' function. This functions returns %0 on success,
+ * -EAGAIN to indicate a race with GC, or another negative error code on
+ * failure.
+ */
+int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+{
+	int lnum = bu->zbranch[0].lnum, offs = bu->zbranch[0].offs, len, err, i;
+	void *buf;
+
+	len = bu->zbranch[bu->cnt - 1].offs;
+	len += bu->zbranch[bu->cnt - 1].len - offs;
+	if (len > bu->buf_len) {
+		ubifs_err("buffer too small %d vs %d", bu->buf_len, len);
+		return -EINVAL;
+	}
+
+	/* Do the read */
+	err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
+
+	/* Check for a race with GC */
+	if (maybe_leb_gced(c, lnum, bu->gc_seq))
+		return -EAGAIN;
+
+	if (err && err != -EBADMSG) {
+		ubifs_err("failed to read from LEB %d:%d, error %d",
+			  lnum, offs, err);
+		dbg_dump_stack();
+		dbg_tnc("key %s", DBGKEY(&bu->key));
+		return err;
+	}
+
+	/* Validate the nodes read */
+	buf = bu->buf;
+	for (i = 0; i < bu->cnt; i++) {
+		err = validate_data_node(c, buf, &bu->zbranch[i]);
+		if (err)
+			return err;
+		buf = buf + ALIGN(bu->zbranch[i].len, 8);
+	}
+
+	return 0;
+}
+
+/**
+ * do_lookup_nm- look up a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @nm: node name
+ *
+ * This function look up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one is
+ * found. This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+			void *node, const struct qstr *nm)
+{
+	int found, n, err;
+	struct ubifs_znode *znode;
+
+	dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
+	mutex_lock(&c->tnc_mutex);
+	found = ubifs_lookup_level0(c, key, &znode, &n);
+	if (!found) {
+		err = -ENOENT;
+		goto out_unlock;
+	} else if (found < 0) {
+		err = found;
+		goto out_unlock;
+	}
+
+	ubifs_assert(n >= 0);
+
+	err = resolve_collision(c, key, &znode, &n, nm);
+	dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
+	if (unlikely(err < 0))
+		goto out_unlock;
+	if (err == 0) {
+		err = -ENOENT;
+		goto out_unlock;
+	}
+
+	err = tnc_read_node_nm(c, &znode->zbranch[n], node);
+
+out_unlock:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_lookup_nm - look up a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @nm: node name
+ *
+ * This function look up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one is
+ * found. This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+			void *node, const struct qstr *nm)
+{
+	int err, len;
+	const struct ubifs_dent_node *dent = node;
+
+	/*
+	 * We assume that in most of the cases there are no name collisions and
+	 * 'ubifs_tnc_lookup()' returns us the right direntry.
+	 */
+	err = ubifs_tnc_lookup(c, key, node);
+	if (err)
+		return err;
+
+	len = le16_to_cpu(dent->nlen);
+	if (nm->len == len && !memcmp(dent->name, nm->name, len))
+		return 0;
+
+	/*
+	 * Unluckily, there are hash collisions and we have to iterate over
+	 * them look at each direntry with colliding name hash sequentially.
+	 */
+	return do_lookup_nm(c, key, node, nm);
+}
+
+/**
+ * correct_parent_keys - correct parent znodes' keys.
+ * @c: UBIFS file-system description object
+ * @znode: znode to correct parent znodes for
+ *
+ * This is a helper function for 'tnc_insert()'. When the key of the leftmost
+ * zbranch changes, keys of parent znodes have to be corrected. This helper
+ * function is called in such situations and corrects the keys if needed.
+ */
+static void correct_parent_keys(const struct ubifs_info *c,
+				struct ubifs_znode *znode)
+{
+	union ubifs_key *key, *key1;
+
+	ubifs_assert(znode->parent);
+	ubifs_assert(znode->iip == 0);
+
+	key = &znode->zbranch[0].key;
+	key1 = &znode->parent->zbranch[0].key;
+
+	while (keys_cmp(c, key, key1) < 0) {
+		key_copy(c, key, key1);
+		znode = znode->parent;
+		znode->alt = 1;
+		if (!znode->parent || znode->iip)
+			break;
+		key1 = &znode->parent->zbranch[0].key;
+	}
+}
+
+/**
+ * insert_zbranch - insert a zbranch into a znode.
+ * @znode: znode into which to insert
+ * @zbr: zbranch to insert
+ * @n: slot number to insert to
+ *
+ * This is a helper function for 'tnc_insert()'. UBIFS does not allow "gaps" in
+ * znode's array of zbranches and keeps zbranches consolidated, so when a new
+ * zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th
+ * slot, zbranches starting from @n have to be moved right.
+ */
+static void insert_zbranch(struct ubifs_znode *znode,
+			   const struct ubifs_zbranch *zbr, int n)
+{
+	int i;
+
+	ubifs_assert(ubifs_zn_dirty(znode));
+
+	if (znode->level) {
+		for (i = znode->child_cnt; i > n; i--) {
+			znode->zbranch[i] = znode->zbranch[i - 1];
+			if (znode->zbranch[i].znode)
+				znode->zbranch[i].znode->iip = i;
+		}
+		if (zbr->znode)
+			zbr->znode->iip = n;
+	} else
+		for (i = znode->child_cnt; i > n; i--)
+			znode->zbranch[i] = znode->zbranch[i - 1];
+
+	znode->zbranch[n] = *zbr;
+	znode->child_cnt += 1;
+
+	/*
+	 * After inserting at slot zero, the lower bound of the key range of
+	 * this znode may have changed. If this znode is subsequently split
+	 * then the upper bound of the key range may change, and furthermore
+	 * it could change to be lower than the original lower bound. If that
+	 * happens, then it will no longer be possible to find this znode in the
+	 * TNC using the key from the index node on flash. That is bad because
+	 * if it is not found, we will assume it is obsolete and may overwrite
+	 * it. Then if there is an unclean unmount, we will start using the
+	 * old index which will be broken.
+	 *
+	 * So we first mark znodes that have insertions at slot zero, and then
+	 * if they are split we add their lnum/offs to the old_idx tree.
+	 */
+	if (n == 0)
+		znode->alt = 1;
+}
+
+/**
+ * tnc_insert - insert a node into TNC.
+ * @c: UBIFS file-system description object
+ * @znode: znode to insert into
+ * @zbr: branch to insert
+ * @n: slot number to insert new zbranch to
+ *
+ * This function inserts a new node described by @zbr into znode @znode. If
+ * znode does not have a free slot for new zbranch, it is split. Parent znodes
+ * are splat as well if needed. Returns zero in case of success or a negative
+ * error code in case of failure.
+ */
+static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
+		      struct ubifs_zbranch *zbr, int n)
+{
+	struct ubifs_znode *zn, *zi, *zp;
+	int i, keep, move, appending = 0;
+	union ubifs_key *key = &zbr->key, *key1;
+
+	ubifs_assert(n >= 0 && n <= c->fanout);
+
+	/* Implement naive insert for now */
+again:
+	zp = znode->parent;
+	if (znode->child_cnt < c->fanout) {
+		ubifs_assert(n != c->fanout);
+		dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
+			DBGKEY(key));
+
+		insert_zbranch(znode, zbr, n);
+
+		/* Ensure parent's key is correct */
+		if (n == 0 && zp && znode->iip == 0)
+			correct_parent_keys(c, znode);
+
+		return 0;
+	}
+
+	/*
+	 * Unfortunately, @znode does not have more empty slots and we have to
+	 * split it.
+	 */
+	dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
+
+	if (znode->alt)
+		/*
+		 * We can no longer be sure of finding this znode by key, so we
+		 * record it in the old_idx tree.
+		 */
+		ins_clr_old_idx_znode(c, znode);
+
+	zn = kzalloc(c->max_znode_sz, GFP_NOFS);
+	if (!zn)
+		return -ENOMEM;
+	zn->parent = zp;
+	zn->level = znode->level;
+
+	/* Decide where to split */
+	if (znode->level == 0 && key_type(c, key) == UBIFS_DATA_KEY) {
+		/* Try not to split consecutive data keys */
+		if (n == c->fanout) {
+			key1 = &znode->zbranch[n - 1].key;
+			if (key_inum(c, key1) == key_inum(c, key) &&
+			    key_type(c, key1) == UBIFS_DATA_KEY)
+				appending = 1;
+		} else
+			goto check_split;
+	} else if (appending && n != c->fanout) {
+		/* Try not to split consecutive data keys */
+		appending = 0;
+check_split:
+		if (n >= (c->fanout + 1) / 2) {
+			key1 = &znode->zbranch[0].key;
+			if (key_inum(c, key1) == key_inum(c, key) &&
+			    key_type(c, key1) == UBIFS_DATA_KEY) {
+				key1 = &znode->zbranch[n].key;
+				if (key_inum(c, key1) != key_inum(c, key) ||
+				    key_type(c, key1) != UBIFS_DATA_KEY) {
+					keep = n;
+					move = c->fanout - keep;
+					zi = znode;
+					goto do_split;
+				}
+			}
+		}
+	}
+
+	if (appending) {
+		keep = c->fanout;
+		move = 0;
+	} else {
+		keep = (c->fanout + 1) / 2;
+		move = c->fanout - keep;
+	}
+
+	/*
+	 * Although we don't at present, we could look at the neighbors and see
+	 * if we can move some zbranches there.
+	 */
+
+	if (n < keep) {
+		/* Insert into existing znode */
+		zi = znode;
+		move += 1;
+		keep -= 1;
+	} else {
+		/* Insert into new znode */
+		zi = zn;
+		n -= keep;
+		/* Re-parent */
+		if (zn->level != 0)
+			zbr->znode->parent = zn;
+	}
+
+do_split:
+
+	__set_bit(DIRTY_ZNODE, &zn->flags);
+	atomic_long_inc(&c->dirty_zn_cnt);
+
+	zn->child_cnt = move;
+	znode->child_cnt = keep;
+
+	dbg_tnc("moving %d, keeping %d", move, keep);
+
+	/* Move zbranch */
+	for (i = 0; i < move; i++) {
+		zn->zbranch[i] = znode->zbranch[keep + i];
+		/* Re-parent */
+		if (zn->level != 0)
+			if (zn->zbranch[i].znode) {
+				zn->zbranch[i].znode->parent = zn;
+				zn->zbranch[i].znode->iip = i;
+			}
+	}
+
+	/* Insert new key and branch */
+	dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
+
+	insert_zbranch(zi, zbr, n);
+
+	/* Insert new znode (produced by spitting) into the parent */
+	if (zp) {
+		if (n == 0 && zi == znode && znode->iip == 0)
+			correct_parent_keys(c, znode);
+
+		/* Locate insertion point */
+		n = znode->iip + 1;
+
+		/* Tail recursion */
+		zbr->key = zn->zbranch[0].key;
+		zbr->znode = zn;
+		zbr->lnum = 0;
+		zbr->offs = 0;
+		zbr->len = 0;
+		znode = zp;
+
+		goto again;
+	}
+
+	/* We have to split root znode */
+	dbg_tnc("creating new zroot at level %d", znode->level + 1);
+
+	zi = kzalloc(c->max_znode_sz, GFP_NOFS);
+	if (!zi)
+		return -ENOMEM;
+
+	zi->child_cnt = 2;
+	zi->level = znode->level + 1;
+
+	__set_bit(DIRTY_ZNODE, &zi->flags);
+	atomic_long_inc(&c->dirty_zn_cnt);
+
+	zi->zbranch[0].key = znode->zbranch[0].key;
+	zi->zbranch[0].znode = znode;
+	zi->zbranch[0].lnum = c->zroot.lnum;
+	zi->zbranch[0].offs = c->zroot.offs;
+	zi->zbranch[0].len = c->zroot.len;
+	zi->zbranch[1].key = zn->zbranch[0].key;
+	zi->zbranch[1].znode = zn;
+
+	c->zroot.lnum = 0;
+	c->zroot.offs = 0;
+	c->zroot.len = 0;
+	c->zroot.znode = zi;
+
+	zn->parent = zi;
+	zn->iip = 1;
+	znode->parent = zi;
+	znode->iip = 0;
+
+	return 0;
+}
+
+/**
+ * ubifs_tnc_add - add a node to TNC.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ *
+ * This function adds a node with key @key to TNC. The node may be new or it may
+ * obsolete some existing one. Returns %0 on success or negative error code on
+ * failure.
+ */
+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+		  int offs, int len)
+{
+	int found, n, err = 0;
+	struct ubifs_znode *znode;
+
+	mutex_lock(&c->tnc_mutex);
+	dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
+	found = lookup_level0_dirty(c, key, &znode, &n);
+	if (!found) {
+		struct ubifs_zbranch zbr;
+
+		zbr.znode = NULL;
+		zbr.lnum = lnum;
+		zbr.offs = offs;
+		zbr.len = len;
+		key_copy(c, key, &zbr.key);
+		err = tnc_insert(c, znode, &zbr, n + 1);
+	} else if (found == 1) {
+		struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+		lnc_free(zbr);
+		err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+		zbr->lnum = lnum;
+		zbr->offs = offs;
+		zbr->len = len;
+	} else
+		err = found;
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+	mutex_unlock(&c->tnc_mutex);
+
+	return err;
+}
+
+/**
+ * ubifs_tnc_replace - replace a node in the TNC only if the old node is found.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @old_lnum: LEB number of old node
+ * @old_offs: old node offset
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ *
+ * This function replaces a node with key @key in the TNC only if the old node
+ * is found.  This function is called by garbage collection when node are moved.
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+		      int old_lnum, int old_offs, int lnum, int offs, int len)
+{
+	int found, n, err = 0;
+	struct ubifs_znode *znode;
+
+	mutex_lock(&c->tnc_mutex);
+	dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
+		old_offs, lnum, offs, len, DBGKEY(key));
+	found = lookup_level0_dirty(c, key, &znode, &n);
+	if (found < 0) {
+		err = found;
+		goto out_unlock;
+	}
+
+	if (found == 1) {
+		struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+		found = 0;
+		if (zbr->lnum == old_lnum && zbr->offs == old_offs) {
+			lnc_free(zbr);
+			err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+			if (err)
+				goto out_unlock;
+			zbr->lnum = lnum;
+			zbr->offs = offs;
+			zbr->len = len;
+			found = 1;
+		} else if (is_hash_key(c, key)) {
+			found = resolve_collision_directly(c, key, &znode, &n,
+							   old_lnum, old_offs);
+			dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d",
+				found, znode, n, old_lnum, old_offs);
+			if (found < 0) {
+				err = found;
+				goto out_unlock;
+			}
+
+			if (found) {
+				/* Ensure the znode is dirtied */
+				if (znode->cnext || !ubifs_zn_dirty(znode)) {
+					znode = dirty_cow_bottom_up(c, znode);
+					if (IS_ERR(znode)) {
+						err = PTR_ERR(znode);
+						goto out_unlock;
+					}
+				}
+				zbr = &znode->zbranch[n];
+				lnc_free(zbr);
+				err = ubifs_add_dirt(c, zbr->lnum,
+						     zbr->len);
+				if (err)
+					goto out_unlock;
+				zbr->lnum = lnum;
+				zbr->offs = offs;
+				zbr->len = len;
+			}
+		}
+	}
+
+	if (!found)
+		err = ubifs_add_dirt(c, lnum, len);
+
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+
+out_unlock:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_add_nm - add a "hashed" node to TNC.
+ * @c: UBIFS file-system description object
+ * @key: key to add
+ * @lnum: LEB number of node
+ * @offs: node offset
+ * @len: node length
+ * @nm: node name
+ *
+ * This is the same as 'ubifs_tnc_add()' but it should be used with keys which
+ * may have collisions, like directory entry keys.
+ */
+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+		     int lnum, int offs, int len, const struct qstr *nm)
+{
+	int found, n, err = 0;
+	struct ubifs_znode *znode;
+
+	mutex_lock(&c->tnc_mutex);
+	dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
+		DBGKEY(key));
+	found = lookup_level0_dirty(c, key, &znode, &n);
+	if (found < 0) {
+		err = found;
+		goto out_unlock;
+	}
+
+	if (found == 1) {
+		if (c->replaying)
+			found = fallible_resolve_collision(c, key, &znode, &n,
+							   nm, 1);
+		else
+			found = resolve_collision(c, key, &znode, &n, nm);
+		dbg_tnc("rc returned %d, znode %p, n %d", found, znode, n);
+		if (found < 0) {
+			err = found;
+			goto out_unlock;
+		}
+
+		/* Ensure the znode is dirtied */
+		if (znode->cnext || !ubifs_zn_dirty(znode)) {
+			znode = dirty_cow_bottom_up(c, znode);
+			if (IS_ERR(znode)) {
+				err = PTR_ERR(znode);
+				goto out_unlock;
+			}
+		}
+
+		if (found == 1) {
+			struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+			lnc_free(zbr);
+			err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+			zbr->lnum = lnum;
+			zbr->offs = offs;
+			zbr->len = len;
+			goto out_unlock;
+		}
+	}
+
+	if (!found) {
+		struct ubifs_zbranch zbr;
+
+		zbr.znode = NULL;
+		zbr.lnum = lnum;
+		zbr.offs = offs;
+		zbr.len = len;
+		key_copy(c, key, &zbr.key);
+		err = tnc_insert(c, znode, &zbr, n + 1);
+		if (err)
+			goto out_unlock;
+		if (c->replaying) {
+			/*
+			 * We did not find it in the index so there may be a
+			 * dangling branch still in the index. So we remove it
+			 * by passing 'ubifs_tnc_remove_nm()' the same key but
+			 * an unmatchable name.
+			 */
+			struct qstr noname = { .len = 0, .name = "" };
+
+			err = dbg_check_tnc(c, 0);
+			mutex_unlock(&c->tnc_mutex);
+			if (err)
+				return err;
+			return ubifs_tnc_remove_nm(c, key, &noname);
+		}
+	}
+
+out_unlock:
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * tnc_delete - delete a znode form TNC.
+ * @c: UBIFS file-system description object
+ * @znode: znode to delete from
+ * @n: zbranch slot number to delete
+ *
+ * This function deletes a leaf node from @n-th slot of @znode. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+{
+	struct ubifs_zbranch *zbr;
+	struct ubifs_znode *zp;
+	int i, err;
+
+	/* Delete without merge for now */
+	ubifs_assert(znode->level == 0);
+	ubifs_assert(n >= 0 && n < c->fanout);
+	dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
+
+	zbr = &znode->zbranch[n];
+	lnc_free(zbr);
+
+	err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
+	if (err) {
+		dbg_dump_znode(c, znode);
+		return err;
+	}
+
+	/* We do not "gap" zbranch slots */
+	for (i = n; i < znode->child_cnt - 1; i++)
+		znode->zbranch[i] = znode->zbranch[i + 1];
+	znode->child_cnt -= 1;
+
+	if (znode->child_cnt > 0)
+		return 0;
+
+	/*
+	 * This was the last zbranch, we have to delete this znode from the
+	 * parent.
+	 */
+
+	do {
+		ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
+		ubifs_assert(ubifs_zn_dirty(znode));
+
+		zp = znode->parent;
+		n = znode->iip;
+
+		atomic_long_dec(&c->dirty_zn_cnt);
+
+		err = insert_old_idx_znode(c, znode);
+		if (err)
+			return err;
+
+		if (znode->cnext) {
+			__set_bit(OBSOLETE_ZNODE, &znode->flags);
+			atomic_long_inc(&c->clean_zn_cnt);
+			atomic_long_inc(&ubifs_clean_zn_cnt);
+		} else
+			kfree(znode);
+		znode = zp;
+	} while (znode->child_cnt == 1); /* while removing last child */
+
+	/* Remove from znode, entry n - 1 */
+	znode->child_cnt -= 1;
+	ubifs_assert(znode->level != 0);
+	for (i = n; i < znode->child_cnt; i++) {
+		znode->zbranch[i] = znode->zbranch[i + 1];
+		if (znode->zbranch[i].znode)
+			znode->zbranch[i].znode->iip = i;
+	}
+
+	/*
+	 * If this is the root and it has only 1 child then
+	 * collapse the tree.
+	 */
+	if (!znode->parent) {
+		while (znode->child_cnt == 1 && znode->level != 0) {
+			zp = znode;
+			zbr = &znode->zbranch[0];
+			znode = get_znode(c, znode, 0);
+			if (IS_ERR(znode))
+				return PTR_ERR(znode);
+			znode = dirty_cow_znode(c, zbr);
+			if (IS_ERR(znode))
+				return PTR_ERR(znode);
+			znode->parent = NULL;
+			znode->iip = 0;
+			if (c->zroot.len) {
+				err = insert_old_idx(c, c->zroot.lnum,
+						     c->zroot.offs);
+				if (err)
+					return err;
+			}
+			c->zroot.lnum = zbr->lnum;
+			c->zroot.offs = zbr->offs;
+			c->zroot.len = zbr->len;
+			c->zroot.znode = znode;
+			ubifs_assert(!test_bit(OBSOLETE_ZNODE,
+				     &zp->flags));
+			ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
+			atomic_long_dec(&c->dirty_zn_cnt);
+
+			if (zp->cnext) {
+				__set_bit(OBSOLETE_ZNODE, &zp->flags);
+				atomic_long_inc(&c->clean_zn_cnt);
+				atomic_long_inc(&ubifs_clean_zn_cnt);
+			} else
+				kfree(zp);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ubifs_tnc_remove - remove an index entry of a node.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
+{
+	int found, n, err = 0;
+	struct ubifs_znode *znode;
+
+	mutex_lock(&c->tnc_mutex);
+	dbg_tnc("key %s", DBGKEY(key));
+	found = lookup_level0_dirty(c, key, &znode, &n);
+	if (found < 0) {
+		err = found;
+		goto out_unlock;
+	}
+	if (found == 1)
+		err = tnc_delete(c, znode, n);
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+
+out_unlock:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_remove_nm - remove an index entry for a "hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: key of node
+ * @nm: directory entry name
+ *
+ * Returns %0 on success or negative error code on failure.
+ */
+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+			const struct qstr *nm)
+{
+	int n, err;
+	struct ubifs_znode *znode;
+
+	mutex_lock(&c->tnc_mutex);
+	dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
+	err = lookup_level0_dirty(c, key, &znode, &n);
+	if (err < 0)
+		goto out_unlock;
+
+	if (err) {
+		if (c->replaying)
+			err = fallible_resolve_collision(c, key, &znode, &n,
+							 nm, 0);
+		else
+			err = resolve_collision(c, key, &znode, &n, nm);
+		dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
+		if (err < 0)
+			goto out_unlock;
+		if (err) {
+			/* Ensure the znode is dirtied */
+			if (znode->cnext || !ubifs_zn_dirty(znode)) {
+				    znode = dirty_cow_bottom_up(c, znode);
+				    if (IS_ERR(znode)) {
+					    err = PTR_ERR(znode);
+					    goto out_unlock;
+				    }
+			}
+			err = tnc_delete(c, znode, n);
+		}
+	}
+
+out_unlock:
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * key_in_range - determine if a key falls within a range of keys.
+ * @c: UBIFS file-system description object
+ * @key: key to check
+ * @from_key: lowest key in range
+ * @to_key: highest key in range
+ *
+ * This function returns %1 if the key is in range and %0 otherwise.
+ */
+static int key_in_range(struct ubifs_info *c, union ubifs_key *key,
+			union ubifs_key *from_key, union ubifs_key *to_key)
+{
+	if (keys_cmp(c, key, from_key) < 0)
+		return 0;
+	if (keys_cmp(c, key, to_key) > 0)
+		return 0;
+	return 1;
+}
+
+/**
+ * ubifs_tnc_remove_range - remove index entries in range.
+ * @c: UBIFS file-system description object
+ * @from_key: lowest key to remove
+ * @to_key: highest key to remove
+ *
+ * This function removes index entries starting at @from_key and ending at
+ * @to_key.  This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+			   union ubifs_key *to_key)
+{
+	int i, n, k, err = 0;
+	struct ubifs_znode *znode;
+	union ubifs_key *key;
+
+	mutex_lock(&c->tnc_mutex);
+	while (1) {
+		/* Find first level 0 znode that contains keys to remove */
+		err = ubifs_lookup_level0(c, from_key, &znode, &n);
+		if (err < 0)
+			goto out_unlock;
+
+		if (err)
+			key = from_key;
+		else {
+			err = tnc_next(c, &znode, &n);
+			if (err == -ENOENT) {
+				err = 0;
+				goto out_unlock;
+			}
+			if (err < 0)
+				goto out_unlock;
+			key = &znode->zbranch[n].key;
+			if (!key_in_range(c, key, from_key, to_key)) {
+				err = 0;
+				goto out_unlock;
+			}
+		}
+
+		/* Ensure the znode is dirtied */
+		if (znode->cnext || !ubifs_zn_dirty(znode)) {
+			znode = dirty_cow_bottom_up(c, znode);
+			if (IS_ERR(znode)) {
+				err = PTR_ERR(znode);
+				goto out_unlock;
+			}
+		}
+
+		/* Remove all keys in range except the first */
+		for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) {
+			key = &znode->zbranch[i].key;
+			if (!key_in_range(c, key, from_key, to_key))
+				break;
+			lnc_free(&znode->zbranch[i]);
+			err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
+					     znode->zbranch[i].len);
+			if (err) {
+				dbg_dump_znode(c, znode);
+				goto out_unlock;
+			}
+			dbg_tnc("removing %s", DBGKEY(key));
+		}
+		if (k) {
+			for (i = n + 1 + k; i < znode->child_cnt; i++)
+				znode->zbranch[i - k] = znode->zbranch[i];
+			znode->child_cnt -= k;
+		}
+
+		/* Now delete the first */
+		err = tnc_delete(c, znode, n);
+		if (err)
+			goto out_unlock;
+	}
+
+out_unlock:
+	if (!err)
+		err = dbg_check_tnc(c, 0);
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * ubifs_tnc_remove_ino - remove an inode from TNC.
+ * @c: UBIFS file-system description object
+ * @inum: inode number to remove
+ *
+ * This function remove inode @inum and all the extended attributes associated
+ * with the anode from TNC and returns zero in case of success or a negative
+ * error code in case of failure.
+ */
+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
+{
+	union ubifs_key key1, key2;
+	struct ubifs_dent_node *xent, *pxent = NULL;
+	struct qstr nm = { .name = NULL };
+
+	dbg_tnc("ino %lu", (unsigned long)inum);
+
+	/*
+	 * Walk all extended attribute entries and remove them together with
+	 * corresponding extended attribute inodes.
+	 */
+	lowest_xent_key(c, &key1, inum);
+	while (1) {
+		ino_t xattr_inum;
+		int err;
+
+		xent = ubifs_tnc_next_ent(c, &key1, &nm);
+		if (IS_ERR(xent)) {
+			err = PTR_ERR(xent);
+			if (err == -ENOENT)
+				break;
+			return err;
+		}
+
+		xattr_inum = le64_to_cpu(xent->inum);
+		dbg_tnc("xent '%s', ino %lu", xent->name,
+			(unsigned long)xattr_inum);
+
+		nm.name = (char *)xent->name;
+		nm.len = le16_to_cpu(xent->nlen);
+		err = ubifs_tnc_remove_nm(c, &key1, &nm);
+		if (err) {
+			kfree(xent);
+			return err;
+		}
+
+		lowest_ino_key(c, &key1, xattr_inum);
+		highest_ino_key(c, &key2, xattr_inum);
+		err = ubifs_tnc_remove_range(c, &key1, &key2);
+		if (err) {
+			kfree(xent);
+			return err;
+		}
+
+		kfree(pxent);
+		pxent = xent;
+		key_read(c, &xent->key, &key1);
+	}
+
+	kfree(pxent);
+	lowest_ino_key(c, &key1, inum);
+	highest_ino_key(c, &key2, inum);
+
+	return ubifs_tnc_remove_range(c, &key1, &key2);
+}
+
+/**
+ * ubifs_tnc_next_ent - walk directory or extended attribute entries.
+ * @c: UBIFS file-system description object
+ * @key: key of last entry
+ * @nm: name of last entry found or %NULL
+ *
+ * This function finds and reads the next directory or extended attribute entry
+ * after the given key (@key) if there is one. @nm is used to resolve
+ * collisions.
+ *
+ * If the name of the current entry is not known and only the key is known,
+ * @nm->name has to be %NULL. In this case the semantics of this function is a
+ * little bit different and it returns the entry corresponding to this key, not
+ * the next one. If the key was not found, the closest "right" entry is
+ * returned.
+ *
+ * If the fist entry has to be found, @key has to contain the lowest possible
+ * key value for this inode and @name has to be %NULL.
+ *
+ * This function returns the found directory or extended attribute entry node
+ * in case of success, %-ENOENT is returned if no entry was found, and a
+ * negative error code is returned in case of failure.
+ */
+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+					   union ubifs_key *key,
+					   const struct qstr *nm)
+{
+	int n, err, type = key_type(c, key);
+	struct ubifs_znode *znode;
+	struct ubifs_dent_node *dent;
+	struct ubifs_zbranch *zbr;
+	union ubifs_key *dkey;
+
+	dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
+	ubifs_assert(is_hash_key(c, key));
+
+	mutex_lock(&c->tnc_mutex);
+	err = ubifs_lookup_level0(c, key, &znode, &n);
+	if (unlikely(err < 0))
+		goto out_unlock;
+
+	if (nm->name) {
+		if (err) {
+			/* Handle collisions */
+			err = resolve_collision(c, key, &znode, &n, nm);
+			dbg_tnc("rc returned %d, znode %p, n %d",
+				err, znode, n);
+			if (unlikely(err < 0))
+				goto out_unlock;
+		}
+
+		/* Now find next entry */
+		err = tnc_next(c, &znode, &n);
+		if (unlikely(err))
+			goto out_unlock;
+	} else {
+		/*
+		 * The full name of the entry was not given, in which case the
+		 * behavior of this function is a little different and it
+		 * returns current entry, not the next one.
+		 */
+		if (!err) {
+			/*
+			 * However, the given key does not exist in the TNC
+			 * tree and @znode/@n variables contain the closest
+			 * "preceding" element. Switch to the next one.
+			 */
+			err = tnc_next(c, &znode, &n);
+			if (err)
+				goto out_unlock;
+		}
+	}
+
+	zbr = &znode->zbranch[n];
+	dent = kmalloc(zbr->len, GFP_NOFS);
+	if (unlikely(!dent)) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	/*
+	 * The above 'tnc_next()' call could lead us to the next inode, check
+	 * this.
+	 */
+	dkey = &zbr->key;
+	if (key_inum(c, dkey) != key_inum(c, key) ||
+	    key_type(c, dkey) != type) {
+		err = -ENOENT;
+		goto out_free;
+	}
+
+	err = tnc_read_node_nm(c, zbr, dent);
+	if (unlikely(err))
+		goto out_free;
+
+	mutex_unlock(&c->tnc_mutex);
+	return dent;
+
+out_free:
+	kfree(dent);
+out_unlock:
+	mutex_unlock(&c->tnc_mutex);
+	return ERR_PTR(err);
+}
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
new file mode 100644
index 0000000..8ac76b1
--- /dev/null
+++ b/fs/ubifs/tnc_commit.c
@@ -0,0 +1,1102 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/* This file implements TNC functions for committing */
+
+#include "ubifs.h"
+
+/**
+ * make_idx_node - make an index node for fill-the-gaps method of TNC commit.
+ * @c: UBIFS file-system description object
+ * @idx: buffer in which to place new index node
+ * @znode: znode from which to make new index node
+ * @lnum: LEB number where new index node will be written
+ * @offs: offset where new index node will be written
+ * @len: length of new index node
+ */
+static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
+			 struct ubifs_znode *znode, int lnum, int offs, int len)
+{
+	struct ubifs_znode *zp;
+	int i, err;
+
+	/* Make index node */
+	idx->ch.node_type = UBIFS_IDX_NODE;
+	idx->child_cnt = cpu_to_le16(znode->child_cnt);
+	idx->level = cpu_to_le16(znode->level);
+	for (i = 0; i < znode->child_cnt; i++) {
+		struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+		struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+		key_write_idx(c, &zbr->key, &br->key);
+		br->lnum = cpu_to_le32(zbr->lnum);
+		br->offs = cpu_to_le32(zbr->offs);
+		br->len = cpu_to_le32(zbr->len);
+		if (!zbr->lnum || !zbr->len) {
+			ubifs_err("bad ref in znode");
+			dbg_dump_znode(c, znode);
+			if (zbr->znode)
+				dbg_dump_znode(c, zbr->znode);
+		}
+	}
+	ubifs_prepare_node(c, idx, len, 0);
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	znode->lnum = lnum;
+	znode->offs = offs;
+	znode->len = len;
+#endif
+
+	err = insert_old_idx_znode(c, znode);
+
+	/* Update the parent */
+	zp = znode->parent;
+	if (zp) {
+		struct ubifs_zbranch *zbr;
+
+		zbr = &zp->zbranch[znode->iip];
+		zbr->lnum = lnum;
+		zbr->offs = offs;
+		zbr->len = len;
+	} else {
+		c->zroot.lnum = lnum;
+		c->zroot.offs = offs;
+		c->zroot.len = len;
+	}
+	c->calc_idx_sz += ALIGN(len, 8);
+
+	atomic_long_dec(&c->dirty_zn_cnt);
+
+	ubifs_assert(ubifs_zn_dirty(znode));
+	ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
+
+	__clear_bit(DIRTY_ZNODE, &znode->flags);
+	__clear_bit(COW_ZNODE, &znode->flags);
+
+	return err;
+}
+
+/**
+ * fill_gap - make index nodes in gaps in dirty index LEBs.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number that gap appears in
+ * @gap_start: offset of start of gap
+ * @gap_end: offset of end of gap
+ * @dirt: adds dirty space to this
+ *
+ * This function returns the number of index nodes written into the gap.
+ */
+static int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end,
+		    int *dirt)
+{
+	int len, gap_remains, gap_pos, written, pad_len;
+
+	ubifs_assert((gap_start & 7) == 0);
+	ubifs_assert((gap_end & 7) == 0);
+	ubifs_assert(gap_end >= gap_start);
+
+	gap_remains = gap_end - gap_start;
+	if (!gap_remains)
+		return 0;
+	gap_pos = gap_start;
+	written = 0;
+	while (c->enext) {
+		len = ubifs_idx_node_sz(c, c->enext->child_cnt);
+		if (len < gap_remains) {
+			struct ubifs_znode *znode = c->enext;
+			const int alen = ALIGN(len, 8);
+			int err;
+
+			ubifs_assert(alen <= gap_remains);
+			err = make_idx_node(c, c->ileb_buf + gap_pos, znode,
+					    lnum, gap_pos, len);
+			if (err)
+				return err;
+			gap_remains -= alen;
+			gap_pos += alen;
+			c->enext = znode->cnext;
+			if (c->enext == c->cnext)
+				c->enext = NULL;
+			written += 1;
+		} else
+			break;
+	}
+	if (gap_end == c->leb_size) {
+		c->ileb_len = ALIGN(gap_pos, c->min_io_size);
+		/* Pad to end of min_io_size */
+		pad_len = c->ileb_len - gap_pos;
+	} else
+		/* Pad to end of gap */
+		pad_len = gap_remains;
+	dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d",
+	       lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len);
+	ubifs_pad(c, c->ileb_buf + gap_pos, pad_len);
+	*dirt += pad_len;
+	return written;
+}
+
+/**
+ * find_old_idx - find an index node obsoleted since the last commit start.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ *
+ * Returns %1 if found and %0 otherwise.
+ */
+static int find_old_idx(struct ubifs_info *c, int lnum, int offs)
+{
+	struct ubifs_old_idx *o;
+	struct rb_node *p;
+
+	p = c->old_idx.rb_node;
+	while (p) {
+		o = rb_entry(p, struct ubifs_old_idx, rb);
+		if (lnum < o->lnum)
+			p = p->rb_left;
+		else if (lnum > o->lnum)
+			p = p->rb_right;
+		else if (offs < o->offs)
+			p = p->rb_left;
+		else if (offs > o->offs)
+			p = p->rb_right;
+		else
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * is_idx_node_in_use - determine if an index node can be overwritten.
+ * @c: UBIFS file-system description object
+ * @key: key of index node
+ * @level: index node level
+ * @lnum: LEB number of index node
+ * @offs: offset of index node
+ *
+ * If @key / @lnum / @offs identify an index node that was not part of the old
+ * index, then this function returns %0 (obsolete).  Else if the index node was
+ * part of the old index but is now dirty %1 is returned, else if it is clean %2
+ * is returned. A negative error code is returned on failure.
+ */
+static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
+			      int level, int lnum, int offs)
+{
+	int ret;
+
+	ret = is_idx_node_in_tnc(c, key, level, lnum, offs);
+	if (ret < 0)
+		return ret; /* Error code */
+	if (ret == 0)
+		if (find_old_idx(c, lnum, offs))
+			return 1;
+	return ret;
+}
+
+/**
+ * layout_leb_in_gaps - layout index nodes using in-the-gaps method.
+ * @c: UBIFS file-system description object
+ * @p: return LEB number here
+ *
+ * This function lays out new index nodes for dirty znodes using in-the-gaps
+ * method of TNC commit.
+ * This function merely puts the next znode into the next gap, making no attempt
+ * to try to maximise the number of znodes that fit.
+ * This function returns the number of index nodes written into the gaps, or a
+ * negative error code on failure.
+ */
+static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
+{
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written;
+
+	tot_written = 0;
+	/* Get an index LEB with lots of obsolete index nodes */
+	lnum = ubifs_find_dirty_idx_leb(c);
+	if (lnum < 0)
+		/*
+		 * There also may be dirt in the index head that could be
+		 * filled, however we do not check there at present.
+		 */
+		return lnum; /* Error code */
+	*p = lnum;
+	dbg_gc("LEB %d", lnum);
+	/*
+	 * Scan the index LEB.  We use the generic scan for this even though
+	 * it is more comprehensive and less efficient than is needed for this
+	 * purpose.
+	 */
+	sleb = ubifs_scan(c, lnum, 0, c->ileb_buf);
+	c->ileb_len = 0;
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+	gap_start = 0;
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		struct ubifs_idx_node *idx;
+		int in_use, level;
+
+		ubifs_assert(snod->type == UBIFS_IDX_NODE);
+		idx = snod->node;
+		key_read(c, ubifs_idx_key(c, idx), &snod->key);
+		level = le16_to_cpu(idx->level);
+		/* Determine if the index node is in use (not obsolete) */
+		in_use = is_idx_node_in_use(c, &snod->key, level, lnum,
+					    snod->offs);
+		if (in_use < 0) {
+			ubifs_scan_destroy(sleb);
+			return in_use; /* Error code */
+		}
+		if (in_use) {
+			if (in_use == 1)
+				dirt += ALIGN(snod->len, 8);
+			/*
+			 * The obsolete index nodes form gaps that can be
+			 * overwritten.  This gap has ended because we have
+			 * found an index node that is still in use
+			 * i.e. not obsolete
+			 */
+			gap_end = snod->offs;
+			/* Try to fill gap */
+			written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
+			if (written < 0) {
+				ubifs_scan_destroy(sleb);
+				return written; /* Error code */
+			}
+			tot_written += written;
+			gap_start = ALIGN(snod->offs + snod->len, 8);
+		}
+	}
+	ubifs_scan_destroy(sleb);
+	c->ileb_len = c->leb_size;
+	gap_end = c->leb_size;
+	/* Try to fill gap */
+	written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
+	if (written < 0)
+		return written; /* Error code */
+	tot_written += written;
+	if (tot_written == 0) {
+		struct ubifs_lprops lp;
+
+		dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
+		err = ubifs_read_one_lp(c, lnum, &lp);
+		if (err)
+			return err;
+		if (lp.free == c->leb_size) {
+			/*
+			 * We must have snatched this LEB from the idx_gc list
+			 * so we need to correct the free and dirty space.
+			 */
+			err = ubifs_change_one_lp(c, lnum,
+						  c->leb_size - c->ileb_len,
+						  dirt, 0, 0, 0);
+			if (err)
+				return err;
+		}
+		return 0;
+	}
+	err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt,
+				  0, 0, 0);
+	if (err)
+		return err;
+	err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len,
+			       UBI_SHORTTERM);
+	if (err)
+		return err;
+	dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
+	return tot_written;
+}
+
+/**
+ * get_leb_cnt - calculate the number of empty LEBs needed to commit.
+ * @c: UBIFS file-system description object
+ * @cnt: number of znodes to commit
+ *
+ * This function returns the number of empty LEBs needed to commit @cnt znodes
+ * to the current index head.  The number is not exact and may be more than
+ * needed.
+ */
+static int get_leb_cnt(struct ubifs_info *c, int cnt)
+{
+	int d;
+
+	/* Assume maximum index node size (i.e. overestimate space needed) */
+	cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz;
+	if (cnt < 0)
+		cnt = 0;
+	d = c->leb_size / c->max_idx_node_sz;
+	return DIV_ROUND_UP(cnt, d);
+}
+
+/**
+ * layout_in_gaps - in-the-gaps method of committing TNC.
+ * @c: UBIFS file-system description object
+ * @cnt: number of dirty znodes to commit.
+ *
+ * This function lays out new index nodes for dirty znodes using in-the-gaps
+ * method of TNC commit.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int layout_in_gaps(struct ubifs_info *c, int cnt)
+{
+	int err, leb_needed_cnt, written, *p;
+
+	dbg_gc("%d znodes to write", cnt);
+
+	c->gap_lebs = kmalloc(sizeof(int) * (c->lst.idx_lebs + 1), GFP_NOFS);
+	if (!c->gap_lebs)
+		return -ENOMEM;
+
+	p = c->gap_lebs;
+	do {
+		ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs);
+		written = layout_leb_in_gaps(c, p);
+		if (written < 0) {
+			err = written;
+			if (err != -ENOSPC) {
+				kfree(c->gap_lebs);
+				c->gap_lebs = NULL;
+				return err;
+			}
+			if (!dbg_force_in_the_gaps_enabled) {
+				/*
+				 * Do not print scary warnings if the debugging
+				 * option which forces in-the-gaps is enabled.
+				 */
+				ubifs_err("out of space");
+				spin_lock(&c->space_lock);
+				dbg_dump_budg(c);
+				spin_unlock(&c->space_lock);
+				dbg_dump_lprops(c);
+			}
+			/* Try to commit anyway */
+			err = 0;
+			break;
+		}
+		p++;
+		cnt -= written;
+		leb_needed_cnt = get_leb_cnt(c, cnt);
+		dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
+		       leb_needed_cnt, c->ileb_cnt);
+	} while (leb_needed_cnt > c->ileb_cnt);
+
+	*p = -1;
+	return 0;
+}
+
+/**
+ * layout_in_empty_space - layout index nodes in empty space.
+ * @c: UBIFS file-system description object
+ *
+ * This function lays out new index nodes for dirty znodes using empty LEBs.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int layout_in_empty_space(struct ubifs_info *c)
+{
+	struct ubifs_znode *znode, *cnext, *zp;
+	int lnum, offs, len, next_len, buf_len, buf_offs, used, avail;
+	int wlen, blen, err;
+
+	cnext = c->enext;
+	if (!cnext)
+		return 0;
+
+	lnum = c->ihead_lnum;
+	buf_offs = c->ihead_offs;
+
+	buf_len = ubifs_idx_node_sz(c, c->fanout);
+	buf_len = ALIGN(buf_len, c->min_io_size);
+	used = 0;
+	avail = buf_len;
+
+	/* Ensure there is enough room for first write */
+	next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+	if (buf_offs + next_len > c->leb_size)
+		lnum = -1;
+
+	while (1) {
+		znode = cnext;
+
+		len = ubifs_idx_node_sz(c, znode->child_cnt);
+
+		/* Determine the index node position */
+		if (lnum == -1) {
+			if (c->ileb_nxt >= c->ileb_cnt) {
+				ubifs_err("out of space");
+				return -ENOSPC;
+			}
+			lnum = c->ilebs[c->ileb_nxt++];
+			buf_offs = 0;
+			used = 0;
+			avail = buf_len;
+		}
+
+		offs = buf_offs + used;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+		znode->lnum = lnum;
+		znode->offs = offs;
+		znode->len = len;
+#endif
+
+		/* Update the parent */
+		zp = znode->parent;
+		if (zp) {
+			struct ubifs_zbranch *zbr;
+			int i;
+
+			i = znode->iip;
+			zbr = &zp->zbranch[i];
+			zbr->lnum = lnum;
+			zbr->offs = offs;
+			zbr->len = len;
+		} else {
+			c->zroot.lnum = lnum;
+			c->zroot.offs = offs;
+			c->zroot.len = len;
+		}
+		c->calc_idx_sz += ALIGN(len, 8);
+
+		/*
+		 * Once lprops is updated, we can decrease the dirty znode count
+		 * but it is easier to just do it here.
+		 */
+		atomic_long_dec(&c->dirty_zn_cnt);
+
+		/*
+		 * Calculate the next index node length to see if there is
+		 * enough room for it
+		 */
+		cnext = znode->cnext;
+		if (cnext == c->cnext)
+			next_len = 0;
+		else
+			next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+
+		if (c->min_io_size == 1) {
+			buf_offs += ALIGN(len, 8);
+			if (next_len) {
+				if (buf_offs + next_len <= c->leb_size)
+					continue;
+				err = ubifs_update_one_lp(c, lnum, 0,
+						c->leb_size - buf_offs, 0, 0);
+				if (err)
+					return err;
+				lnum = -1;
+				continue;
+			}
+			err = ubifs_update_one_lp(c, lnum,
+					c->leb_size - buf_offs, 0, 0, 0);
+			if (err)
+				return err;
+			break;
+		}
+
+		/* Update buffer positions */
+		wlen = used + len;
+		used += ALIGN(len, 8);
+		avail -= ALIGN(len, 8);
+
+		if (next_len != 0 &&
+		    buf_offs + used + next_len <= c->leb_size &&
+		    avail > 0)
+			continue;
+
+		if (avail <= 0 && next_len &&
+		    buf_offs + used + next_len <= c->leb_size)
+			blen = buf_len;
+		else
+			blen = ALIGN(wlen, c->min_io_size);
+
+		/* The buffer is full or there are no more znodes to do */
+		buf_offs += blen;
+		if (next_len) {
+			if (buf_offs + next_len > c->leb_size) {
+				err = ubifs_update_one_lp(c, lnum,
+					c->leb_size - buf_offs, blen - used,
+					0, 0);
+				if (err)
+					return err;
+				lnum = -1;
+			}
+			used -= blen;
+			if (used < 0)
+				used = 0;
+			avail = buf_len - used;
+			continue;
+		}
+		err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs,
+					  blen - used, 0, 0);
+		if (err)
+			return err;
+		break;
+	}
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	c->new_ihead_lnum = lnum;
+	c->new_ihead_offs = buf_offs;
+#endif
+
+	return 0;
+}
+
+/**
+ * layout_commit - determine positions of index nodes to commit.
+ * @c: UBIFS file-system description object
+ * @no_space: indicates that insufficient empty LEBs were allocated
+ * @cnt: number of znodes to commit
+ *
+ * Calculate and update the positions of index nodes to commit.  If there were
+ * an insufficient number of empty LEBs allocated, then index nodes are placed
+ * into the gaps created by obsolete index nodes in non-empty index LEBs.  For
+ * this purpose, an obsolete index node is one that was not in the index as at
+ * the end of the last commit.  To write "in-the-gaps" requires that those index
+ * LEBs are updated atomically in-place.
+ */
+static int layout_commit(struct ubifs_info *c, int no_space, int cnt)
+{
+	int err;
+
+	if (no_space) {
+		err = layout_in_gaps(c, cnt);
+		if (err)
+			return err;
+	}
+	err = layout_in_empty_space(c);
+	return err;
+}
+
+/**
+ * find_first_dirty - find first dirty znode.
+ * @znode: znode to begin searching from
+ */
+static struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode)
+{
+	int i, cont;
+
+	if (!znode)
+		return NULL;
+
+	while (1) {
+		if (znode->level == 0) {
+			if (ubifs_zn_dirty(znode))
+				return znode;
+			return NULL;
+		}
+		cont = 0;
+		for (i = 0; i < znode->child_cnt; i++) {
+			struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+			if (zbr->znode && ubifs_zn_dirty(zbr->znode)) {
+				znode = zbr->znode;
+				cont = 1;
+				break;
+			}
+		}
+		if (!cont) {
+			if (ubifs_zn_dirty(znode))
+				return znode;
+			return NULL;
+		}
+	}
+}
+
+/**
+ * find_next_dirty - find next dirty znode.
+ * @znode: znode to begin searching from
+ */
+static struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode)
+{
+	int n = znode->iip + 1;
+
+	znode = znode->parent;
+	if (!znode)
+		return NULL;
+	for (; n < znode->child_cnt; n++) {
+		struct ubifs_zbranch *zbr = &znode->zbranch[n];
+
+		if (zbr->znode && ubifs_zn_dirty(zbr->znode))
+			return find_first_dirty(zbr->znode);
+	}
+	return znode;
+}
+
+/**
+ * get_znodes_to_commit - create list of dirty znodes to commit.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns the number of znodes to commit.
+ */
+static int get_znodes_to_commit(struct ubifs_info *c)
+{
+	struct ubifs_znode *znode, *cnext;
+	int cnt = 0;
+
+	c->cnext = find_first_dirty(c->zroot.znode);
+	znode = c->enext = c->cnext;
+	if (!znode) {
+		dbg_cmt("no znodes to commit");
+		return 0;
+	}
+	cnt += 1;
+	while (1) {
+		ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
+		__set_bit(COW_ZNODE, &znode->flags);
+		znode->alt = 0;
+		cnext = find_next_dirty(znode);
+		if (!cnext) {
+			znode->cnext = c->cnext;
+			break;
+		}
+		znode->cnext = cnext;
+		znode = cnext;
+		cnt += 1;
+	}
+	dbg_cmt("committing %d znodes", cnt);
+	ubifs_assert(cnt == atomic_long_read(&c->dirty_zn_cnt));
+	return cnt;
+}
+
+/**
+ * alloc_idx_lebs - allocate empty LEBs to be used to commit.
+ * @c: UBIFS file-system description object
+ * @cnt: number of znodes to commit
+ *
+ * This function returns %-ENOSPC if it cannot allocate a sufficient number of
+ * empty LEBs.  %0 is returned on success, otherwise a negative error code
+ * is returned.
+ */
+static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
+{
+	int i, leb_cnt, lnum;
+
+	c->ileb_cnt = 0;
+	c->ileb_nxt = 0;
+	leb_cnt = get_leb_cnt(c, cnt);
+	dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt);
+	if (!leb_cnt)
+		return 0;
+	c->ilebs = kmalloc(leb_cnt * sizeof(int), GFP_NOFS);
+	if (!c->ilebs)
+		return -ENOMEM;
+	for (i = 0; i < leb_cnt; i++) {
+		lnum = ubifs_find_free_leb_for_idx(c);
+		if (lnum < 0)
+			return lnum;
+		c->ilebs[c->ileb_cnt++] = lnum;
+		dbg_cmt("LEB %d", lnum);
+	}
+	if (dbg_force_in_the_gaps())
+		return -ENOSPC;
+	return 0;
+}
+
+/**
+ * free_unused_idx_lebs - free unused LEBs that were allocated for the commit.
+ * @c: UBIFS file-system description object
+ *
+ * It is possible that we allocate more empty LEBs for the commit than we need.
+ * This functions frees the surplus.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int free_unused_idx_lebs(struct ubifs_info *c)
+{
+	int i, err = 0, lnum, er;
+
+	for (i = c->ileb_nxt; i < c->ileb_cnt; i++) {
+		lnum = c->ilebs[i];
+		dbg_cmt("LEB %d", lnum);
+		er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+					 LPROPS_INDEX | LPROPS_TAKEN, 0);
+		if (!err)
+			err = er;
+	}
+	return err;
+}
+
+/**
+ * free_idx_lebs - free unused LEBs after commit end.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+static int free_idx_lebs(struct ubifs_info *c)
+{
+	int err;
+
+	err = free_unused_idx_lebs(c);
+	kfree(c->ilebs);
+	c->ilebs = NULL;
+	return err;
+}
+
+/**
+ * ubifs_tnc_start_commit - start TNC commit.
+ * @c: UBIFS file-system description object
+ * @zroot: new index root position is returned here
+ *
+ * This function prepares the list of indexing nodes to commit and lays out
+ * their positions on flash. If there is not enough free space it uses the
+ * in-gap commit method. Returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+{
+	int err = 0, cnt;
+
+	mutex_lock(&c->tnc_mutex);
+	err = dbg_check_tnc(c, 1);
+	if (err)
+		goto out;
+	cnt = get_znodes_to_commit(c);
+	if (cnt != 0) {
+		int no_space = 0;
+
+		err = alloc_idx_lebs(c, cnt);
+		if (err == -ENOSPC)
+			no_space = 1;
+		else if (err)
+			goto out_free;
+		err = layout_commit(c, no_space, cnt);
+		if (err)
+			goto out_free;
+		ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
+		err = free_unused_idx_lebs(c);
+		if (err)
+			goto out;
+	}
+	destroy_old_idx(c);
+	memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch));
+
+	err = ubifs_save_dirty_idx_lnums(c);
+	if (err)
+		goto out;
+
+	spin_lock(&c->space_lock);
+	/*
+	 * Although we have not finished committing yet, update size of the
+	 * committed index ('c->old_idx_sz') and zero out the index growth
+	 * budget. It is OK to do this now, because we've reserved all the
+	 * space which is needed to commit the index, and it is save for the
+	 * budgeting subsystem to assume the index is already committed,
+	 * even though it is not.
+	 */
+	c->old_idx_sz = c->calc_idx_sz;
+	c->budg_uncommitted_idx = 0;
+	spin_unlock(&c->space_lock);
+	mutex_unlock(&c->tnc_mutex);
+
+	dbg_cmt("number of index LEBs %d", c->lst.idx_lebs);
+	dbg_cmt("size of index %llu", c->calc_idx_sz);
+	return err;
+
+out_free:
+	free_idx_lebs(c);
+out:
+	mutex_unlock(&c->tnc_mutex);
+	return err;
+}
+
+/**
+ * write_index - write index nodes.
+ * @c: UBIFS file-system description object
+ *
+ * This function writes the index nodes whose positions were laid out in the
+ * layout_in_empty_space function.
+ */
+static int write_index(struct ubifs_info *c)
+{
+	struct ubifs_idx_node *idx;
+	struct ubifs_znode *znode, *cnext;
+	int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
+	int avail, wlen, err, lnum_pos = 0;
+
+	cnext = c->enext;
+	if (!cnext)
+		return 0;
+
+	/*
+	 * Always write index nodes to the index head so that index nodes and
+	 * other types of nodes are never mixed in the same erase block.
+	 */
+	lnum = c->ihead_lnum;
+	buf_offs = c->ihead_offs;
+
+	/* Allocate commit buffer */
+	buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size);
+	used = 0;
+	avail = buf_len;
+
+	/* Ensure there is enough room for first write */
+	next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+	if (buf_offs + next_len > c->leb_size) {
+		err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0,
+					  LPROPS_TAKEN);
+		if (err)
+			return err;
+		lnum = -1;
+	}
+
+	while (1) {
+		cond_resched();
+
+		znode = cnext;
+		idx = c->cbuf + used;
+
+		/* Make index node */
+		idx->ch.node_type = UBIFS_IDX_NODE;
+		idx->child_cnt = cpu_to_le16(znode->child_cnt);
+		idx->level = cpu_to_le16(znode->level);
+		for (i = 0; i < znode->child_cnt; i++) {
+			struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+			struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+			key_write_idx(c, &zbr->key, &br->key);
+			br->lnum = cpu_to_le32(zbr->lnum);
+			br->offs = cpu_to_le32(zbr->offs);
+			br->len = cpu_to_le32(zbr->len);
+			if (!zbr->lnum || !zbr->len) {
+				ubifs_err("bad ref in znode");
+				dbg_dump_znode(c, znode);
+				if (zbr->znode)
+					dbg_dump_znode(c, zbr->znode);
+			}
+		}
+		len = ubifs_idx_node_sz(c, znode->child_cnt);
+		ubifs_prepare_node(c, idx, len, 0);
+
+		/* Determine the index node position */
+		if (lnum == -1) {
+			lnum = c->ilebs[lnum_pos++];
+			buf_offs = 0;
+			used = 0;
+			avail = buf_len;
+		}
+		offs = buf_offs + used;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+		if (lnum != znode->lnum || offs != znode->offs ||
+		    len != znode->len) {
+			ubifs_err("inconsistent znode posn");
+			return -EINVAL;
+		}
+#endif
+
+		/* Grab some stuff from znode while we still can */
+		cnext = znode->cnext;
+
+		ubifs_assert(ubifs_zn_dirty(znode));
+		ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
+
+		/*
+		 * It is important that other threads should see %DIRTY_ZNODE
+		 * flag cleared before %COW_ZNODE. Specifically, it matters in
+		 * the 'dirty_cow_znode()' function. This is the reason for the
+		 * first barrier. Also, we want the bit changes to be seen to
+		 * other threads ASAP, to avoid unnecesarry copying, which is
+		 * the reason for the second barrier.
+		 */
+		clear_bit(DIRTY_ZNODE, &znode->flags);
+		smp_mb__before_clear_bit();
+		clear_bit(COW_ZNODE, &znode->flags);
+		smp_mb__after_clear_bit();
+
+		/* Do not access znode from this point on */
+
+		/* Update buffer positions */
+		wlen = used + len;
+		used += ALIGN(len, 8);
+		avail -= ALIGN(len, 8);
+
+		/*
+		 * Calculate the next index node length to see if there is
+		 * enough room for it
+		 */
+		if (cnext == c->cnext)
+			next_len = 0;
+		else
+			next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+
+		if (c->min_io_size == 1) {
+			/*
+			 * Write the prepared index node immediately if there is
+			 * no minimum IO size
+			 */
+			err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+					      wlen, UBI_SHORTTERM);
+			if (err)
+				return err;
+			buf_offs += ALIGN(wlen, 8);
+			if (next_len) {
+				used = 0;
+				avail = buf_len;
+				if (buf_offs + next_len > c->leb_size) {
+					err = ubifs_update_one_lp(c, lnum,
+						LPROPS_NC, 0, 0, LPROPS_TAKEN);
+					if (err)
+						return err;
+					lnum = -1;
+				}
+				continue;
+			}
+		} else {
+			int blen, nxt_offs = buf_offs + used + next_len;
+
+			if (next_len && nxt_offs <= c->leb_size) {
+				if (avail > 0)
+					continue;
+				else
+					blen = buf_len;
+			} else {
+				wlen = ALIGN(wlen, 8);
+				blen = ALIGN(wlen, c->min_io_size);
+				ubifs_pad(c, c->cbuf + wlen, blen - wlen);
+			}
+			/*
+			 * The buffer is full or there are no more znodes
+			 * to do
+			 */
+			err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+					      blen, UBI_SHORTTERM);
+			if (err)
+				return err;
+			buf_offs += blen;
+			if (next_len) {
+				if (nxt_offs > c->leb_size) {
+					err = ubifs_update_one_lp(c, lnum,
+						LPROPS_NC, 0, 0, LPROPS_TAKEN);
+					if (err)
+						return err;
+					lnum = -1;
+				}
+				used -= blen;
+				if (used < 0)
+					used = 0;
+				avail = buf_len - used;
+				memmove(c->cbuf, c->cbuf + blen, used);
+				continue;
+			}
+		}
+		break;
+	}
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) {
+		ubifs_err("inconsistent ihead");
+		return -EINVAL;
+	}
+#endif
+
+	c->ihead_lnum = lnum;
+	c->ihead_offs = buf_offs;
+
+	return 0;
+}
+
+/**
+ * free_obsolete_znodes - free obsolete znodes.
+ * @c: UBIFS file-system description object
+ *
+ * At the end of commit end, obsolete znodes are freed.
+ */
+static void free_obsolete_znodes(struct ubifs_info *c)
+{
+	struct ubifs_znode *znode, *cnext;
+
+	cnext = c->cnext;
+	do {
+		znode = cnext;
+		cnext = znode->cnext;
+		if (test_bit(OBSOLETE_ZNODE, &znode->flags))
+			kfree(znode);
+		else {
+			znode->cnext = NULL;
+			atomic_long_inc(&c->clean_zn_cnt);
+			atomic_long_inc(&ubifs_clean_zn_cnt);
+		}
+	} while (cnext != c->cnext);
+}
+
+/**
+ * return_gap_lebs - return LEBs used by the in-gap commit method.
+ * @c: UBIFS file-system description object
+ *
+ * This function clears the "taken" flag for the LEBs which were used by the
+ * "commit in-the-gaps" method.
+ */
+static int return_gap_lebs(struct ubifs_info *c)
+{
+	int *p, err;
+
+	if (!c->gap_lebs)
+		return 0;
+
+	dbg_cmt("");
+	for (p = c->gap_lebs; *p != -1; p++) {
+		err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0,
+					  LPROPS_TAKEN, 0);
+		if (err)
+			return err;
+	}
+
+	kfree(c->gap_lebs);
+	c->gap_lebs = NULL;
+	return 0;
+}
+
+/**
+ * ubifs_tnc_end_commit - update the TNC for commit end.
+ * @c: UBIFS file-system description object
+ *
+ * Write the dirty znodes.
+ */
+int ubifs_tnc_end_commit(struct ubifs_info *c)
+{
+	int err;
+
+	if (!c->cnext)
+		return 0;
+
+	err = return_gap_lebs(c);
+	if (err)
+		return err;
+
+	err = write_index(c);
+	if (err)
+		return err;
+
+	mutex_lock(&c->tnc_mutex);
+
+	dbg_cmt("TNC height is %d", c->zroot.znode->level + 1);
+
+	free_obsolete_znodes(c);
+
+	c->cnext = NULL;
+	kfree(c->ilebs);
+	c->ilebs = NULL;
+
+	mutex_unlock(&c->tnc_mutex);
+
+	return 0;
+}
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
new file mode 100644
index 0000000..955219f
--- /dev/null
+++ b/fs/ubifs/tnc_misc.c
@@ -0,0 +1,435 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+
+/*
+ * This file contains miscelanious TNC-related functions shared betweend
+ * different files. This file does not form any logically separate TNC
+ * sub-system. The file was created because there is a lot of TNC code and
+ * putting it all in one file would make that file too big and unreadable.
+ */
+
+#include "ubifs.h"
+
+/**
+ * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal.
+ * @zr: root of the subtree to traverse
+ * @znode: previous znode
+ *
+ * This function implements levelorder TNC traversal. The LNC is ignored.
+ * Returns the next element or %NULL if @znode is already the last one.
+ */
+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+					      struct ubifs_znode *znode)
+{
+	int level, iip, level_search = 0;
+	struct ubifs_znode *zn;
+
+	ubifs_assert(zr);
+
+	if (unlikely(!znode))
+		return zr;
+
+	if (unlikely(znode == zr)) {
+		if (znode->level == 0)
+			return NULL;
+		return ubifs_tnc_find_child(zr, 0);
+	}
+
+	level = znode->level;
+
+	iip = znode->iip;
+	while (1) {
+		ubifs_assert(znode->level <= zr->level);
+
+		/*
+		 * First walk up until there is a znode with next branch to
+		 * look at.
+		 */
+		while (znode->parent != zr && iip >= znode->parent->child_cnt) {
+			znode = znode->parent;
+			iip = znode->iip;
+		}
+
+		if (unlikely(znode->parent == zr &&
+			     iip >= znode->parent->child_cnt)) {
+			/* This level is done, switch to the lower one */
+			level -= 1;
+			if (level_search || level < 0)
+				/*
+				 * We were already looking for znode at lower
+				 * level ('level_search'). As we are here
+				 * again, it just does not exist. Or all levels
+				 * were finished ('level < 0').
+				 */
+				return NULL;
+
+			level_search = 1;
+			iip = -1;
+			znode = ubifs_tnc_find_child(zr, 0);
+			ubifs_assert(znode);
+		}
+
+		/* Switch to the next index */
+		zn = ubifs_tnc_find_child(znode->parent, iip + 1);
+		if (!zn) {
+			/* No more children to look at, we have walk up */
+			iip = znode->parent->child_cnt;
+			continue;
+		}
+
+		/* Walk back down to the level we came from ('level') */
+		while (zn->level != level) {
+			znode = zn;
+			zn = ubifs_tnc_find_child(zn, 0);
+			if (!zn) {
+				/*
+				 * This path is not too deep so it does not
+				 * reach 'level'. Try next path.
+				 */
+				iip = znode->iip;
+				break;
+			}
+		}
+
+		if (zn) {
+			ubifs_assert(zn->level >= 0);
+			return zn;
+		}
+	}
+}
+
+/**
+ * ubifs_search_zbranch - search znode branch.
+ * @c: UBIFS file-system description object
+ * @znode: znode to search in
+ * @key: key to search for
+ * @n: znode branch slot number is returned here
+ *
+ * This is a helper function which search branch with key @key in @znode using
+ * binary search. The result of the search may be:
+ *   o exact match, then %1 is returned, and the slot number of the branch is
+ *     stored in @n;
+ *   o no exact match, then %0 is returned and the slot number of the left
+ *     closest branch is returned in @n; the slot if all keys in this znode are
+ *     greater than @key, then %-1 is returned in @n.
+ */
+int ubifs_search_zbranch(const struct ubifs_info *c,
+			 const struct ubifs_znode *znode,
+			 const union ubifs_key *key, int *n)
+{
+	int beg = 0, end = znode->child_cnt, uninitialized_var(mid);
+	int uninitialized_var(cmp);
+	const struct ubifs_zbranch *zbr = &znode->zbranch[0];
+
+	ubifs_assert(end > beg);
+
+	while (end > beg) {
+		mid = (beg + end) >> 1;
+		cmp = keys_cmp(c, key, &zbr[mid].key);
+		if (cmp > 0)
+			beg = mid + 1;
+		else if (cmp < 0)
+			end = mid;
+		else {
+			*n = mid;
+			return 1;
+		}
+	}
+
+	*n = end - 1;
+
+	/* The insert point is after *n */
+	ubifs_assert(*n >= -1 && *n < znode->child_cnt);
+	if (*n == -1)
+		ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0);
+	else
+		ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0);
+	if (*n + 1 < znode->child_cnt)
+		ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0);
+
+	return 0;
+}
+
+/**
+ * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal.
+ * @znode: znode to start at (root of the sub-tree to traverse)
+ *
+ * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is
+ * ignored.
+ */
+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode)
+{
+	if (unlikely(!znode))
+		return NULL;
+
+	while (znode->level > 0) {
+		struct ubifs_znode *child;
+
+		child = ubifs_tnc_find_child(znode, 0);
+		if (!child)
+			return znode;
+		znode = child;
+	}
+
+	return znode;
+}
+
+/**
+ * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal.
+ * @znode: previous znode
+ *
+ * This function implements postorder TNC traversal. The LNC is ignored.
+ * Returns the next element or %NULL if @znode is already the last one.
+ */
+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
+{
+	struct ubifs_znode *zn;
+
+	ubifs_assert(znode);
+	if (unlikely(!znode->parent))
+		return NULL;
+
+	/* Switch to the next index in the parent */
+	zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1);
+	if (!zn)
+		/* This is in fact the last child, return parent */
+		return znode->parent;
+
+	/* Go to the first znode in this new subtree */
+	return ubifs_tnc_postorder_first(zn);
+}
+
+/**
+ * read_znode - read an indexing node from flash and fill znode.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB of the indexing node to read
+ * @offs: node offset
+ * @len: node length
+ * @znode: znode to read to
+ *
+ * This function reads an indexing node from the flash media and fills znode
+ * with the read data. Returns zero in case of success and a negative error
+ * code in case of failure. The read indexing node is validated and if anything
+ * is wrong with it, this function prints complaint messages and returns
+ * %-EINVAL.
+ */
+static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+		      struct ubifs_znode *znode)
+{
+	int i, err, type, cmp;
+	struct ubifs_idx_node *idx;
+
+	idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
+	if (!idx)
+		return -ENOMEM;
+
+	err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
+	if (err < 0) {
+		kfree(idx);
+		return err;
+	}
+
+	znode->child_cnt = le16_to_cpu(idx->child_cnt);
+	znode->level = le16_to_cpu(idx->level);
+
+	dbg_tnc("LEB %d:%d, level %d, %d branch",
+		lnum, offs, znode->level, znode->child_cnt);
+
+	if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
+		dbg_err("current fanout %d, branch count %d",
+			c->fanout, znode->child_cnt);
+		dbg_err("max levels %d, znode level %d",
+			UBIFS_MAX_LEVELS, znode->level);
+		err = 1;
+		goto out_dump;
+	}
+
+	for (i = 0; i < znode->child_cnt; i++) {
+		const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+		struct ubifs_zbranch *zbr = &znode->zbranch[i];
+
+		key_read(c, &br->key, &zbr->key);
+		zbr->lnum = le32_to_cpu(br->lnum);
+		zbr->offs = le32_to_cpu(br->offs);
+		zbr->len  = le32_to_cpu(br->len);
+		zbr->znode = NULL;
+
+		/* Validate branch */
+
+		if (zbr->lnum < c->main_first ||
+		    zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
+		    zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
+			dbg_err("bad branch %d", i);
+			err = 2;
+			goto out_dump;
+		}
+
+		switch (key_type(c, &zbr->key)) {
+		case UBIFS_INO_KEY:
+		case UBIFS_DATA_KEY:
+		case UBIFS_DENT_KEY:
+		case UBIFS_XENT_KEY:
+			break;
+		default:
+			dbg_msg("bad key type at slot %d: %s", i,
+				DBGKEY(&zbr->key));
+			err = 3;
+			goto out_dump;
+		}
+
+		if (znode->level)
+			continue;
+
+		type = key_type(c, &zbr->key);
+		if (c->ranges[type].max_len == 0) {
+			if (zbr->len != c->ranges[type].len) {
+				dbg_err("bad target node (type %d) length (%d)",
+					type, zbr->len);
+				dbg_err("have to be %d", c->ranges[type].len);
+				err = 4;
+				goto out_dump;
+			}
+		} else if (zbr->len < c->ranges[type].min_len ||
+			   zbr->len > c->ranges[type].max_len) {
+			dbg_err("bad target node (type %d) length (%d)",
+				type, zbr->len);
+			dbg_err("have to be in range of %d-%d",
+				c->ranges[type].min_len,
+				c->ranges[type].max_len);
+			err = 5;
+			goto out_dump;
+		}
+	}
+
+	/*
+	 * Ensure that the next key is greater or equivalent to the
+	 * previous one.
+	 */
+	for (i = 0; i < znode->child_cnt - 1; i++) {
+		const union ubifs_key *key1, *key2;
+
+		key1 = &znode->zbranch[i].key;
+		key2 = &znode->zbranch[i + 1].key;
+
+		cmp = keys_cmp(c, key1, key2);
+		if (cmp > 0) {
+			dbg_err("bad key order (keys %d and %d)", i, i + 1);
+			err = 6;
+			goto out_dump;
+		} else if (cmp == 0 && !is_hash_key(c, key1)) {
+			/* These can only be keys with colliding hash */
+			dbg_err("keys %d and %d are not hashed but equivalent",
+				i, i + 1);
+			err = 7;
+			goto out_dump;
+		}
+	}
+
+	kfree(idx);
+	return 0;
+
+out_dump:
+	ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
+	dbg_dump_node(c, idx);
+	kfree(idx);
+	return -EINVAL;
+}
+
+/**
+ * ubifs_load_znode - load znode to TNC cache.
+ * @c: UBIFS file-system description object
+ * @zbr: znode branch
+ * @parent: znode's parent
+ * @iip: index in parent
+ *
+ * This function loads znode pointed to by @zbr into the TNC cache and
+ * returns pointer to it in case of success and a negative error code in case
+ * of failure.
+ */
+struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
+				     struct ubifs_zbranch *zbr,
+				     struct ubifs_znode *parent, int iip)
+{
+	int err;
+	struct ubifs_znode *znode;
+
+	ubifs_assert(!zbr->znode);
+	/*
+	 * A slab cache is not presently used for znodes because the znode size
+	 * depends on the fanout which is stored in the superblock.
+	 */
+	znode = kzalloc(c->max_znode_sz, GFP_NOFS);
+	if (!znode)
+		return ERR_PTR(-ENOMEM);
+
+	err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);
+	if (err)
+		goto out;
+
+	zbr->znode = znode;
+	znode->parent = parent;
+	znode->time = get_seconds();
+	znode->iip = iip;
+
+	return znode;
+
+out:
+	kfree(znode);
+	return ERR_PTR(err);
+}
+
+/**
+ * ubifs_tnc_read_node - read a leaf node from the flash media.
+ * @c: UBIFS file-system description object
+ * @zbr: key and position of the node
+ * @node: node is returned here
+ *
+ * This function reads a node defined by @zbr from the flash media. Returns
+ * zero in case of success or a negative negative error code in case of
+ * failure.
+ */
+int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+			void *node)
+{
+	union ubifs_key key1, *key = &zbr->key;
+	int err, type = key_type(c, key);
+
+	err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum, zbr->offs);
+
+	if (err) {
+		dbg_tnc("key %s", DBGKEY(key));
+		return err;
+	}
+
+	/* Make sure the key of the read node is correct */
+	key_read(c, node + UBIFS_KEY_OFFSET, &key1);
+	if (!keys_eq(c, key, &key1)) {
+		ubifs_err("bad key in node at LEB %d:%d",
+			  zbr->lnum, zbr->offs);
+		dbg_tnc("looked for key %s found node's key %s",
+			DBGKEY(key), DBGKEY1(&key1));
+		dbg_dump_node(c, node);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
new file mode 100644
index 0000000..b25fc36
--- /dev/null
+++ b/fs/ubifs/ubifs-media.h
@@ -0,0 +1,751 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file describes UBIFS on-flash format and contains definitions of all the
+ * relevant data structures and constants.
+ *
+ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start
+ * with the UBIFS node magic number and have the same common header. Nodes
+ * always sit at 8-byte aligned positions on the media and node header sizes are
+ * also 8-byte aligned (except for the indexing node and the padding node).
+ */
+
+#ifndef __UBIFS_MEDIA_H__
+#define __UBIFS_MEDIA_H__
+
+/* UBIFS node magic number (must not have the padding byte first or last) */
+#define UBIFS_NODE_MAGIC  0x06101831
+
+/* UBIFS on-flash format version */
+#define UBIFS_FORMAT_VERSION 4
+
+/* Minimum logical eraseblock size in bytes */
+#define UBIFS_MIN_LEB_SZ (15*1024)
+
+/* Initial CRC32 value used when calculating CRC checksums */
+#define UBIFS_CRC32_INIT 0xFFFFFFFFU
+
+/*
+ * UBIFS does not try to compress data if its length is less than the below
+ * constant.
+ */
+#define UBIFS_MIN_COMPR_LEN 128
+
+/*
+ * If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
+ * shorter than uncompressed data length, UBIFS preferes to leave this data
+ * node uncompress, because it'll be read faster.
+ */
+#define UBIFS_MIN_COMPRESS_DIFF 64
+
+/* Root inode number */
+#define UBIFS_ROOT_INO 1
+
+/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */
+#define UBIFS_FIRST_INO 64
+
+/*
+ * Maximum file name and extended attribute length (must be a multiple of 8,
+ * minus 1).
+ */
+#define UBIFS_MAX_NLEN 255
+
+/* Maximum number of data journal heads */
+#define UBIFS_MAX_JHEADS 1
+
+/*
+ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system,
+ * which means that it does not treat the underlying media as consisting of
+ * blocks like in case of hard drives. Do not be confused. UBIFS block is just
+ * the maximum amount of data which one data node can have or which can be
+ * attached to an inode node.
+ */
+#define UBIFS_BLOCK_SIZE  4096
+#define UBIFS_BLOCK_SHIFT 12
+
+/* UBIFS padding byte pattern (must not be first or last byte of node magic) */
+#define UBIFS_PADDING_BYTE 0xCE
+
+/* Maximum possible key length */
+#define UBIFS_MAX_KEY_LEN 16
+
+/* Key length ("simple" format) */
+#define UBIFS_SK_LEN 8
+
+/* Minimum index tree fanout */
+#define UBIFS_MIN_FANOUT 3
+
+/* Maximum number of levels in UBIFS indexing B-tree */
+#define UBIFS_MAX_LEVELS 512
+
+/* Maximum amount of data attached to an inode in bytes */
+#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE
+
+/* LEB Properties Tree fanout (must be power of 2) and fanout shift */
+#define UBIFS_LPT_FANOUT 4
+#define UBIFS_LPT_FANOUT_SHIFT 2
+
+/* LEB Properties Tree bit field sizes */
+#define UBIFS_LPT_CRC_BITS 16
+#define UBIFS_LPT_CRC_BYTES 2
+#define UBIFS_LPT_TYPE_BITS 4
+
+/* The key is always at the same position in all keyed nodes */
+#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key)
+
+/*
+ * LEB Properties Tree node types.
+ *
+ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties)
+ * UBIFS_LPT_NNODE: LPT internal node
+ * UBIFS_LPT_LTAB: LPT's own lprops table
+ * UBIFS_LPT_LSAVE: LPT's save table (big model only)
+ * UBIFS_LPT_NODE_CNT: count of LPT node types
+ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type
+ */
+enum {
+	UBIFS_LPT_PNODE,
+	UBIFS_LPT_NNODE,
+	UBIFS_LPT_LTAB,
+	UBIFS_LPT_LSAVE,
+	UBIFS_LPT_NODE_CNT,
+	UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1,
+};
+
+/*
+ * UBIFS inode types.
+ *
+ * UBIFS_ITYPE_REG: regular file
+ * UBIFS_ITYPE_DIR: directory
+ * UBIFS_ITYPE_LNK: soft link
+ * UBIFS_ITYPE_BLK: block device node
+ * UBIFS_ITYPE_CHR: character device node
+ * UBIFS_ITYPE_FIFO: fifo
+ * UBIFS_ITYPE_SOCK: socket
+ * UBIFS_ITYPES_CNT: count of supported file types
+ */
+enum {
+	UBIFS_ITYPE_REG,
+	UBIFS_ITYPE_DIR,
+	UBIFS_ITYPE_LNK,
+	UBIFS_ITYPE_BLK,
+	UBIFS_ITYPE_CHR,
+	UBIFS_ITYPE_FIFO,
+	UBIFS_ITYPE_SOCK,
+	UBIFS_ITYPES_CNT,
+};
+
+/*
+ * Supported key hash functions.
+ *
+ * UBIFS_KEY_HASH_R5: R5 hash
+ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name
+ */
+enum {
+	UBIFS_KEY_HASH_R5,
+	UBIFS_KEY_HASH_TEST,
+};
+
+/*
+ * Supported key formats.
+ *
+ * UBIFS_SIMPLE_KEY_FMT: simple key format
+ */
+enum {
+	UBIFS_SIMPLE_KEY_FMT,
+};
+
+/*
+ * The simple key format uses 29 bits for storing UBIFS block number and hash
+ * value.
+ */
+#define UBIFS_S_KEY_BLOCK_BITS 29
+#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF
+#define UBIFS_S_KEY_HASH_BITS  UBIFS_S_KEY_BLOCK_BITS
+#define UBIFS_S_KEY_HASH_MASK  UBIFS_S_KEY_BLOCK_MASK
+
+/*
+ * Key types.
+ *
+ * UBIFS_INO_KEY: inode node key
+ * UBIFS_DATA_KEY: data node key
+ * UBIFS_DENT_KEY: directory entry node key
+ * UBIFS_XENT_KEY: extended attribute entry key
+ * UBIFS_KEY_TYPES_CNT: number of supported key types
+ */
+enum {
+	UBIFS_INO_KEY,
+	UBIFS_DATA_KEY,
+	UBIFS_DENT_KEY,
+	UBIFS_XENT_KEY,
+	UBIFS_KEY_TYPES_CNT,
+};
+
+/* Count of LEBs reserved for the superblock area */
+#define UBIFS_SB_LEBS 1
+/* Count of LEBs reserved for the master area */
+#define UBIFS_MST_LEBS 2
+
+/* First LEB of the superblock area */
+#define UBIFS_SB_LNUM 0
+/* First LEB of the master area */
+#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS)
+/* First LEB of the log area */
+#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS)
+
+/*
+ * The below constants define the absolute minimum values for various UBIFS
+ * media areas. Many of them actually depend of flash geometry and the FS
+ * configuration (number of journal heads, orphan LEBs, etc). This means that
+ * the smallest volume size which can be used for UBIFS cannot be pre-defined
+ * by these constants. The file-system that meets the below limitation will not
+ * necessarily mount. UBIFS does run-time calculations and validates the FS
+ * size.
+ */
+
+/* Minimum number of logical eraseblocks in the log */
+#define UBIFS_MIN_LOG_LEBS 2
+/* Minimum number of bud logical eraseblocks (one for each head) */
+#define UBIFS_MIN_BUD_LEBS 3
+/* Minimum number of journal logical eraseblocks */
+#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS)
+/* Minimum number of LPT area logical eraseblocks */
+#define UBIFS_MIN_LPT_LEBS 2
+/* Minimum number of orphan area logical eraseblocks */
+#define UBIFS_MIN_ORPH_LEBS 1
+/*
+ * Minimum number of main area logical eraseblocks (buds, 3 for the index, 1
+ * for GC, 1 for deletions, and at least 1 for committed data).
+ */
+#define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 6)
+
+/* Minimum number of logical eraseblocks */
+#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \
+			   UBIFS_MIN_LOG_LEBS + UBIFS_MIN_LPT_LEBS + \
+			   UBIFS_MIN_ORPH_LEBS + UBIFS_MIN_MAIN_LEBS)
+
+/* Node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_CH_SZ        sizeof(struct ubifs_ch)
+#define UBIFS_INO_NODE_SZ  sizeof(struct ubifs_ino_node)
+#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node)
+#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node)
+#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node)
+#define UBIFS_PAD_NODE_SZ  sizeof(struct ubifs_pad_node)
+#define UBIFS_SB_NODE_SZ   sizeof(struct ubifs_sb_node)
+#define UBIFS_MST_NODE_SZ  sizeof(struct ubifs_mst_node)
+#define UBIFS_REF_NODE_SZ  sizeof(struct ubifs_ref_node)
+#define UBIFS_IDX_NODE_SZ  sizeof(struct ubifs_idx_node)
+#define UBIFS_CS_NODE_SZ   sizeof(struct ubifs_cs_node)
+#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
+/* Extended attribute entry nodes are identical to directory entry nodes */
+#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
+/* Only this does not have to be multiple of 8 bytes */
+#define UBIFS_BRANCH_SZ    sizeof(struct ubifs_branch)
+
+/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_MAX_DATA_NODE_SZ  (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
+#define UBIFS_MAX_INO_NODE_SZ   (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA)
+#define UBIFS_MAX_DENT_NODE_SZ  (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1)
+#define UBIFS_MAX_XENT_NODE_SZ  UBIFS_MAX_DENT_NODE_SZ
+
+/* The largest UBIFS node */
+#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
+
+/*
+ * On-flash inode flags.
+ *
+ * UBIFS_COMPR_FL: use compression for this inode
+ * UBIFS_SYNC_FL:  I/O on this inode has to be synchronous
+ * UBIFS_IMMUTABLE_FL: inode is immutable
+ * UBIFS_APPEND_FL: writes to the inode may only append data
+ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
+ * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
+ *
+ * Note, these are on-flash flags which correspond to ioctl flags
+ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
+ * have to be the same.
+ */
+enum {
+	UBIFS_COMPR_FL     = 0x01,
+	UBIFS_SYNC_FL      = 0x02,
+	UBIFS_IMMUTABLE_FL = 0x04,
+	UBIFS_APPEND_FL    = 0x08,
+	UBIFS_DIRSYNC_FL   = 0x10,
+	UBIFS_XATTR_FL     = 0x20,
+};
+
+/* Inode flag bits used by UBIFS */
+#define UBIFS_FL_MASK 0x0000001F
+
+/*
+ * UBIFS compression algorithms.
+ *
+ * UBIFS_COMPR_NONE: no compression
+ * UBIFS_COMPR_LZO: LZO compression
+ * UBIFS_COMPR_ZLIB: ZLIB compression
+ * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+ */
+enum {
+	UBIFS_COMPR_NONE,
+	UBIFS_COMPR_LZO,
+	UBIFS_COMPR_ZLIB,
+	UBIFS_COMPR_TYPES_CNT,
+};
+
+/*
+ * UBIFS node types.
+ *
+ * UBIFS_INO_NODE: inode node
+ * UBIFS_DATA_NODE: data node
+ * UBIFS_DENT_NODE: directory entry node
+ * UBIFS_XENT_NODE: extended attribute node
+ * UBIFS_TRUN_NODE: truncation node
+ * UBIFS_PAD_NODE: padding node
+ * UBIFS_SB_NODE: superblock node
+ * UBIFS_MST_NODE: master node
+ * UBIFS_REF_NODE: LEB reference node
+ * UBIFS_IDX_NODE: index node
+ * UBIFS_CS_NODE: commit start node
+ * UBIFS_ORPH_NODE: orphan node
+ * UBIFS_NODE_TYPES_CNT: count of supported node types
+ *
+ * Note, we index arrays by these numbers, so keep them low and contiguous.
+ * Node type constants for inodes, direntries and so on have to be the same as
+ * corresponding key type constants.
+ */
+enum {
+	UBIFS_INO_NODE,
+	UBIFS_DATA_NODE,
+	UBIFS_DENT_NODE,
+	UBIFS_XENT_NODE,
+	UBIFS_TRUN_NODE,
+	UBIFS_PAD_NODE,
+	UBIFS_SB_NODE,
+	UBIFS_MST_NODE,
+	UBIFS_REF_NODE,
+	UBIFS_IDX_NODE,
+	UBIFS_CS_NODE,
+	UBIFS_ORPH_NODE,
+	UBIFS_NODE_TYPES_CNT,
+};
+
+/*
+ * Master node flags.
+ *
+ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty
+ * UBIFS_MST_NO_ORPHS: no orphan inodes present
+ * UBIFS_MST_RCVRY: written by recovery
+ */
+enum {
+	UBIFS_MST_DIRTY = 1,
+	UBIFS_MST_NO_ORPHS = 2,
+	UBIFS_MST_RCVRY = 4,
+};
+
+/*
+ * Node group type (used by recovery to recover whole group or none).
+ *
+ * UBIFS_NO_NODE_GROUP: this node is not part of a group
+ * UBIFS_IN_NODE_GROUP: this node is a part of a group
+ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group
+ */
+enum {
+	UBIFS_NO_NODE_GROUP = 0,
+	UBIFS_IN_NODE_GROUP,
+	UBIFS_LAST_OF_NODE_GROUP,
+};
+
+/*
+ * Superblock flags.
+ *
+ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ */
+enum {
+	UBIFS_FLG_BIGLPT = 0x02,
+};
+
+/**
+ * struct ubifs_ch - common header node.
+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
+ * @crc: CRC-32 checksum of the node header
+ * @sqnum: sequence number
+ * @len: full node length
+ * @node_type: node type
+ * @group_type: node group type
+ * @padding: reserved for future, zeroes
+ *
+ * Every UBIFS node starts with this common part. If the node has a key, the
+ * key always goes next.
+ */
+struct ubifs_ch {
+	__le32 magic;
+	__le32 crc;
+	__le64 sqnum;
+	__le32 len;
+	__u8 node_type;
+	__u8 group_type;
+	__u8 padding[2];
+} __attribute__ ((packed));
+
+/**
+ * union ubifs_dev_desc - device node descriptor.
+ * @new: new type device descriptor
+ * @huge: huge type device descriptor
+ *
+ * This data structure describes major/minor numbers of a device node. In an
+ * inode is a device node then its data contains an object of this type. UBIFS
+ * uses standard Linux "new" and "huge" device node encodings.
+ */
+union ubifs_dev_desc {
+	__le32 new;
+	__le64 huge;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ino_node - inode node.
+ * @ch: common header
+ * @key: node key
+ * @creat_sqnum: sequence number at time of creation
+ * @size: inode size in bytes (amount of uncompressed data)
+ * @atime_sec: access time seconds
+ * @ctime_sec: creation time seconds
+ * @mtime_sec: modification time seconds
+ * @atime_nsec: access time nanoseconds
+ * @ctime_nsec: creation time nanoseconds
+ * @mtime_nsec: modification time nanoseconds
+ * @nlink: number of hard links
+ * @uid: owner ID
+ * @gid: group ID
+ * @mode: access flags
+ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc)
+ * @data_len: inode data length
+ * @xattr_cnt: count of extended attributes this inode has
+ * @xattr_size: summarized size of all extended attributes in bytes
+ * @padding1: reserved for future, zeroes
+ * @xattr_names: sum of lengths of all extended attribute names belonging to
+ *               this inode
+ * @compr_type: compression type used for this inode
+ * @padding2: reserved for future, zeroes
+ * @data: data attached to the inode
+ *
+ * Note, even though inode compression type is defined by @compr_type, some
+ * nodes of this inode may be compressed with different compressor - this
+ * happens if compression type is changed while the inode already has data
+ * nodes. But @compr_type will be use for further writes to the inode.
+ *
+ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing
+ * the padding fields.
+ */
+struct ubifs_ino_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le64 creat_sqnum;
+	__le64 size;
+	__le64 atime_sec;
+	__le64 ctime_sec;
+	__le64 mtime_sec;
+	__le32 atime_nsec;
+	__le32 ctime_nsec;
+	__le32 mtime_nsec;
+	__le32 nlink;
+	__le32 uid;
+	__le32 gid;
+	__le32 mode;
+	__le32 flags;
+	__le32 data_len;
+	__le32 xattr_cnt;
+	__le32 xattr_size;
+	__u8 padding1[4]; /* Watch 'zero_ino_node_unused()' if changing! */
+	__le32 xattr_names;
+	__le16 compr_type;
+	__u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+	__u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_dent_node - directory entry node.
+ * @ch: common header
+ * @key: node key
+ * @inum: target inode number
+ * @padding1: reserved for future, zeroes
+ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
+ * @nlen: name length
+ * @padding2: reserved for future, zeroes
+ * @name: zero-terminated name
+ *
+ * Note, do not forget to amend 'zero_dent_node_unused()' function when
+ * changing the padding fields.
+ */
+struct ubifs_dent_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le64 inum;
+	__u8 padding1;
+	__u8 type;
+	__le16 nlen;
+	__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+	__u8 name[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_data_node - data node.
+ * @ch: common header
+ * @key: node key
+ * @size: uncompressed data size in bytes
+ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
+ * @padding: reserved for future, zeroes
+ * @data: data
+ *
+ * Note, do not forget to amend 'zero_data_node_unused()' function when
+ * changing the padding fields.
+ */
+struct ubifs_data_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le32 size;
+	__le16 compr_type;
+	__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+	__u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_trun_node - truncation node.
+ * @ch: common header
+ * @inum: truncated inode number
+ * @padding: reserved for future, zeroes
+ * @old_size: size before truncation
+ * @new_size: size after truncation
+ *
+ * This node exists only in the journal and never goes to the main area. Note,
+ * do not forget to amend 'zero_trun_node_unused()' function when changing the
+ * padding fields.
+ */
+struct ubifs_trun_node {
+	struct ubifs_ch ch;
+	__le32 inum;
+	__u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+	__le64 old_size;
+	__le64 new_size;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_pad_node - padding node.
+ * @ch: common header
+ * @pad_len: how many bytes after this node are unused (because padded)
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_pad_node {
+	struct ubifs_ch ch;
+	__le32 pad_len;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_sb_node - superblock node.
+ * @ch: common header
+ * @padding: reserved for future, zeroes
+ * @key_hash: type of hash function used in keys
+ * @key_fmt: format of the key
+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of LEBs used by file-system
+ * @max_leb_cnt: maximum count of LEBs used by file-system
+ * @max_bud_bytes: maximum amount of data stored in buds
+ * @log_lebs: log size in logical eraseblocks
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @orph_lebs: number of LEBs used for recording orphans
+ * @jhead_cnt: count of journal heads
+ * @fanout: tree fanout (max. number of links per indexing node)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @fmt_version: UBIFS on-flash format version
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @padding1: reserved for future, zeroes
+ * @rp_uid: reserve pool UID
+ * @rp_gid: reserve pool GID
+ * @rp_size: size of the reserved pool in bytes
+ * @padding2: reserved for future, zeroes
+ * @time_gran: time granularity in nanoseconds
+ * @uuid: UUID generated when the file system image was created
+ */
+struct ubifs_sb_node {
+	struct ubifs_ch ch;
+	__u8 padding[2];
+	__u8 key_hash;
+	__u8 key_fmt;
+	__le32 flags;
+	__le32 min_io_size;
+	__le32 leb_size;
+	__le32 leb_cnt;
+	__le32 max_leb_cnt;
+	__le64 max_bud_bytes;
+	__le32 log_lebs;
+	__le32 lpt_lebs;
+	__le32 orph_lebs;
+	__le32 jhead_cnt;
+	__le32 fanout;
+	__le32 lsave_cnt;
+	__le32 fmt_version;
+	__le16 default_compr;
+	__u8 padding1[2];
+	__le32 rp_uid;
+	__le32 rp_gid;
+	__le64 rp_size;
+	__le32 time_gran;
+	__u8 uuid[16];
+	__u8 padding2[3972];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_mst_node - master node.
+ * @ch: common header
+ * @highest_inum: highest inode number in the committed index
+ * @cmt_no: commit number
+ * @flags: various flags (%UBIFS_MST_DIRTY, etc)
+ * @log_lnum: start of the log
+ * @root_lnum: LEB number of the root indexing node
+ * @root_offs: offset within @root_lnum
+ * @root_len: root indexing node length
+ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was
+ * not reserved and should be reserved on mount)
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ * @index_size: size of index on flash
+ * @total_free: total free space in bytes
+ * @total_dirty: total dirty space in bytes
+ * @total_used: total used space in bytes (includes only data LEBs)
+ * @total_dead: total dead space in bytes (includes only data LEBs)
+ * @total_dark: total dark space in bytes (includes only data LEBs)
+ * @lpt_lnum: LEB number of LPT root nnode
+ * @lpt_offs: offset of LPT root nnode
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @lsave_lnum: LEB number of LPT's save table (big model only)
+ * @lsave_offs: offset of LPT's save table (big model only)
+ * @lscan_lnum: LEB number of last LPT scan
+ * @empty_lebs: number of empty logical eraseblocks
+ * @idx_lebs: number of indexing logical eraseblocks
+ * @leb_cnt: count of LEBs used by file-system
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_mst_node {
+	struct ubifs_ch ch;
+	__le64 highest_inum;
+	__le64 cmt_no;
+	__le32 flags;
+	__le32 log_lnum;
+	__le32 root_lnum;
+	__le32 root_offs;
+	__le32 root_len;
+	__le32 gc_lnum;
+	__le32 ihead_lnum;
+	__le32 ihead_offs;
+	__le64 index_size;
+	__le64 total_free;
+	__le64 total_dirty;
+	__le64 total_used;
+	__le64 total_dead;
+	__le64 total_dark;
+	__le32 lpt_lnum;
+	__le32 lpt_offs;
+	__le32 nhead_lnum;
+	__le32 nhead_offs;
+	__le32 ltab_lnum;
+	__le32 ltab_offs;
+	__le32 lsave_lnum;
+	__le32 lsave_offs;
+	__le32 lscan_lnum;
+	__le32 empty_lebs;
+	__le32 idx_lebs;
+	__le32 leb_cnt;
+	__u8 padding[344];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ref_node - logical eraseblock reference node.
+ * @ch: common header
+ * @lnum: the referred logical eraseblock number
+ * @offs: start offset in the referred LEB
+ * @jhead: journal head number
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_ref_node {
+	struct ubifs_ch ch;
+	__le32 lnum;
+	__le32 offs;
+	__le32 jhead;
+	__u8 padding[28];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_branch - key/reference/length branch
+ * @lnum: LEB number of the target node
+ * @offs: offset within @lnum
+ * @len: target node length
+ * @key: key
+ */
+struct ubifs_branch {
+	__le32 lnum;
+	__le32 offs;
+	__le32 len;
+	__u8 key[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_idx_node - indexing node.
+ * @ch: common header
+ * @child_cnt: number of child index nodes
+ * @level: tree level
+ * @branches: LEB number / offset / length / key branches
+ */
+struct ubifs_idx_node {
+	struct ubifs_ch ch;
+	__le16 child_cnt;
+	__le16 level;
+	__u8 branches[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_cs_node - commit start node.
+ * @ch: common header
+ * @cmt_no: commit number
+ */
+struct ubifs_cs_node {
+	struct ubifs_ch ch;
+	__le64 cmt_no;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_orph_node - orphan node.
+ * @ch: common header
+ * @cmt_no: commit number (also top bit is set on the last node of the commit)
+ * @inos: inode numbers of orphans
+ */
+struct ubifs_orph_node {
+	struct ubifs_ch ch;
+	__le64 cmt_no;
+	__le64 inos[];
+} __attribute__ ((packed));
+
+#endif /* __UBIFS_MEDIA_H__ */
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
new file mode 100644
index 0000000..32f9ff8
--- /dev/null
+++ b/fs/ubifs/ubifs.c
@@ -0,0 +1,687 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+#include "ubifs.h"
+
+#if !defined(CONFIG_SYS_64BIT_VSPRINTF)
+#warning Please define CONFIG_SYS_64BIT_VSPRINTF for correct output!
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* compress.c */
+
+/*
+ * We need a wrapper for gunzip() because the parameters are
+ * incompatible with the lzo decompressor.
+ */
+static int gzip_decompress(const unsigned char *in, size_t in_len,
+			   unsigned char *out, size_t *out_len)
+{
+	unsigned long len = in_len;
+	return gunzip(out, *out_len, (unsigned char *)in, &len);
+}
+
+/* Fake description object for the "none" compressor */
+static struct ubifs_compressor none_compr = {
+	.compr_type = UBIFS_COMPR_NONE,
+	.name = "no compression",
+	.capi_name = "",
+	.decompress = NULL,
+};
+
+static struct ubifs_compressor lzo_compr = {
+	.compr_type = UBIFS_COMPR_LZO,
+	.name = "LZO",
+	.capi_name = "lzo",
+	.decompress = lzo1x_decompress_safe,
+};
+
+static struct ubifs_compressor zlib_compr = {
+	.compr_type = UBIFS_COMPR_ZLIB,
+	.name = "zlib",
+	.capi_name = "deflate",
+	.decompress = gzip_decompress,
+};
+
+/* All UBIFS compressors */
+struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+
+/**
+ * ubifs_decompress - decompress data.
+ * @in_buf: data to decompress
+ * @in_len: length of the data to decompress
+ * @out_buf: output buffer where decompressed data should
+ * @out_len: output length is returned here
+ * @compr_type: type of compression
+ *
+ * This function decompresses data from buffer @in_buf into buffer @out_buf.
+ * The length of the uncompressed data is returned in @out_len. This functions
+ * returns %0 on success or a negative error code on failure.
+ */
+int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
+		     int *out_len, int compr_type)
+{
+	int err;
+	struct ubifs_compressor *compr;
+
+	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
+		ubifs_err("invalid compression type %d", compr_type);
+		return -EINVAL;
+	}
+
+	compr = ubifs_compressors[compr_type];
+
+	if (unlikely(!compr->capi_name)) {
+		ubifs_err("%s compression is not compiled in", compr->name);
+		return -EINVAL;
+	}
+
+	if (compr_type == UBIFS_COMPR_NONE) {
+		memcpy(out_buf, in_buf, in_len);
+		*out_len = in_len;
+		return 0;
+	}
+
+	err = compr->decompress(in_buf, in_len, out_buf, (size_t *)out_len);
+	if (err)
+		ubifs_err("cannot decompress %d bytes, compressor %s, "
+			  "error %d", in_len, compr->name, err);
+
+	return err;
+}
+
+/**
+ * compr_init - initialize a compressor.
+ * @compr: compressor description object
+ *
+ * This function initializes the requested compressor and returns zero in case
+ * of success or a negative error code in case of failure.
+ */
+static int __init compr_init(struct ubifs_compressor *compr)
+{
+	ubifs_compressors[compr->compr_type] = compr;
+	ubifs_compressors[compr->compr_type]->name += gd->reloc_off;
+	ubifs_compressors[compr->compr_type]->capi_name += gd->reloc_off;
+	ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off;
+	return 0;
+}
+
+/**
+ * ubifs_compressors_init - initialize UBIFS compressors.
+ *
+ * This function initializes the compressor which were compiled in. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+int __init ubifs_compressors_init(void)
+{
+	int err;
+
+	err = compr_init(&lzo_compr);
+	if (err)
+		return err;
+
+	err = compr_init(&zlib_compr);
+	if (err)
+		return err;
+
+	err = compr_init(&none_compr);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/*
+ * ubifsls...
+ */
+
+static int filldir(struct ubifs_info *c, const char *name, int namlen,
+		   u64 ino, unsigned int d_type)
+{
+	struct inode *inode;
+	char filetime[32];
+
+	switch (d_type) {
+	case UBIFS_ITYPE_REG:
+		printf("\t");
+		break;
+	case UBIFS_ITYPE_DIR:
+		printf("<DIR>\t");
+		break;
+	case UBIFS_ITYPE_LNK:
+		printf("<LNK>\t");
+		break;
+	default:
+		printf("other\t");
+		break;
+	}
+
+	inode = ubifs_iget(c->vfs_sb, ino);
+	if (IS_ERR(inode)) {
+		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
+		       __func__, ino, inode);
+		return -1;
+	}
+	ctime_r((time_t *)&inode->i_mtime, filetime);
+	printf("%9lld  %24.24s  ", inode->i_size, filetime);
+	ubifs_iput(inode);
+
+	printf("%s\n", name);
+
+	return 0;
+}
+
+static int ubifs_printdir(struct file *file, void *dirent)
+{
+	int err, over = 0;
+	struct qstr nm;
+	union ubifs_key key;
+	struct ubifs_dent_node *dent;
+	struct inode *dir = file->f_path.dentry->d_inode;
+	struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+
+	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
+		/*
+		 * The directory was seek'ed to a senseless position or there
+		 * are no more entries.
+		 */
+		return 0;
+
+	if (file->f_pos == 1) {
+		/* Find the first entry in TNC and save it */
+		lowest_dent_key(c, &key, dir->i_ino);
+		nm.name = NULL;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+
+		file->f_pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+	}
+
+	dent = file->private_data;
+	if (!dent) {
+		/*
+		 * The directory was seek'ed to and is now readdir'ed.
+		 * Find the entry corresponding to @file->f_pos or the
+		 * closest one.
+		 */
+		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
+		nm.name = NULL;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+		file->f_pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+	}
+
+	while (1) {
+		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+			key_hash_flash(c, &dent->key));
+		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
+
+		nm.len = le16_to_cpu(dent->nlen);
+		over = filldir(c, (char *)dent->name, nm.len,
+			       le64_to_cpu(dent->inum), dent->type);
+		if (over)
+			return 0;
+
+		/* Switch to the next entry */
+		key_read(c, &dent->key, &key);
+		nm.name = (char *)dent->name;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+
+		kfree(file->private_data);
+		file->f_pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+		cond_resched();
+	}
+
+out:
+	if (err != -ENOENT) {
+		ubifs_err("cannot find next direntry, error %d", err);
+		return err;
+	}
+
+	kfree(file->private_data);
+	file->private_data = NULL;
+	file->f_pos = 2;
+	return 0;
+}
+
+static int ubifs_finddir(struct super_block *sb, char *dirname,
+			 unsigned long root_inum, unsigned long *inum)
+{
+	int err;
+	struct qstr nm;
+	union ubifs_key key;
+	struct ubifs_dent_node *dent;
+	struct ubifs_info *c;
+	struct file *file;
+	struct dentry *dentry;
+	struct inode *dir;
+
+	file = kzalloc(sizeof(struct file), 0);
+	dentry = kzalloc(sizeof(struct dentry), 0);
+	dir = kzalloc(sizeof(struct inode), 0);
+	if (!file || !dentry || !dir) {
+		printf("%s: Error, no memory for malloc!\n", __func__);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dir->i_sb = sb;
+	file->f_path.dentry = dentry;
+	file->f_path.dentry->d_parent = dentry;
+	file->f_path.dentry->d_inode = dir;
+	file->f_path.dentry->d_inode->i_ino = root_inum;
+	c = sb->s_fs_info;
+
+	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+
+	/* Find the first entry in TNC and save it */
+	lowest_dent_key(c, &key, dir->i_ino);
+	nm.name = NULL;
+	dent = ubifs_tnc_next_ent(c, &key, &nm);
+	if (IS_ERR(dent)) {
+		err = PTR_ERR(dent);
+		goto out;
+	}
+
+	file->f_pos = key_hash_flash(c, &dent->key);
+	file->private_data = dent;
+
+	while (1) {
+		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+			key_hash_flash(c, &dent->key));
+		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
+
+		nm.len = le16_to_cpu(dent->nlen);
+		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
+		    (strlen(dirname) == nm.len)) {
+			*inum = le64_to_cpu(dent->inum);
+			return 1;
+		}
+
+		/* Switch to the next entry */
+		key_read(c, &dent->key, &key);
+		nm.name = (char *)dent->name;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+
+		kfree(file->private_data);
+		file->f_pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+		cond_resched();
+	}
+
+out:
+	if (err != -ENOENT) {
+		ubifs_err("cannot find next direntry, error %d", err);
+		return err;
+	}
+
+	if (file)
+		free(file);
+	if (dentry)
+		free(dentry);
+	if (dir)
+		free(dir);
+
+	if (file->private_data)
+		kfree(file->private_data);
+	file->private_data = NULL;
+	file->f_pos = 2;
+	return 0;
+}
+
+static unsigned long ubifs_findfile(struct super_block *sb, char *filename)
+{
+	int ret;
+	char *next;
+	char fpath[128];
+	char *name = fpath;
+	unsigned long root_inum = 1;
+	unsigned long inum;
+
+	strcpy(fpath, filename);
+
+	/* Remove all leading slashes */
+	while (*name == '/')
+		name++;
+
+	/*
+	 * Handle root-direcoty ('/')
+	 */
+	inum = root_inum;
+	if (!name || *name == '\0')
+		return inum;
+
+	for (;;) {
+		/* Extract the actual part from the pathname.  */
+		next = strchr(name, '/');
+		if (next) {
+			/* Remove all leading slashes.  */
+			while (*next == '/')
+				*(next++) = '\0';
+		}
+
+		ret = ubifs_finddir(sb, name, root_inum, &inum);
+
+		/*
+		 * Check if directory with this name exists
+		 */
+
+		/* Found the node!  */
+		if (!next || *next == '\0') {
+			if (ret)
+				return inum;
+
+			break;
+		}
+
+		root_inum = inum;
+		name = next;
+	}
+
+	return 0;
+}
+
+int ubifs_ls(char *filename)
+{
+	struct ubifs_info *c = ubifs_sb->s_fs_info;
+	struct file *file;
+	struct dentry *dentry;
+	struct inode *dir;
+	void *dirent = NULL;
+	unsigned long inum;
+	int ret = 0;
+
+	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+	inum = ubifs_findfile(ubifs_sb, filename);
+	if (!inum) {
+		ret = -1;
+		goto out;
+	}
+
+	file = kzalloc(sizeof(struct file), 0);
+	dentry = kzalloc(sizeof(struct dentry), 0);
+	dir = kzalloc(sizeof(struct inode), 0);
+	if (!file || !dentry || !dir) {
+		printf("%s: Error, no memory for malloc!\n", __func__);
+		ret = -ENOMEM;
+		goto out_mem;
+	}
+
+	dir->i_sb = ubifs_sb;
+	file->f_path.dentry = dentry;
+	file->f_path.dentry->d_parent = dentry;
+	file->f_path.dentry->d_inode = dir;
+	file->f_path.dentry->d_inode->i_ino = inum;
+	file->f_pos = 1;
+	file->private_data = NULL;
+	ubifs_printdir(file, dirent);
+
+out_mem:
+	if (file)
+		free(file);
+	if (dentry)
+		free(dentry);
+	if (dir)
+		free(dir);
+
+out:
+	ubi_close_volume(c->ubi);
+	return ret;
+}
+
+/*
+ * ubifsload...
+ */
+
+/* file.c */
+
+static inline void *kmap(struct page *page)
+{
+	return page->addr;
+}
+
+static int read_block(struct inode *inode, void *addr, unsigned int block,
+		      struct ubifs_data_node *dn)
+{
+	struct ubifs_info *c = inode->i_sb->s_fs_info;
+	int err, len, out_len;
+	union ubifs_key key;
+	unsigned int dlen;
+
+	data_key_init(c, &key, inode->i_ino, block);
+	err = ubifs_tnc_lookup(c, &key, dn);
+	if (err) {
+		if (err == -ENOENT)
+			/* Not found, so it must be a hole */
+			memset(addr, 0, UBIFS_BLOCK_SIZE);
+		return err;
+	}
+
+	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
+
+	len = le32_to_cpu(dn->size);
+	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
+		goto dump;
+
+	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+	out_len = UBIFS_BLOCK_SIZE;
+	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
+			       le16_to_cpu(dn->compr_type));
+	if (err || len != out_len)
+		goto dump;
+
+	/*
+	 * Data length can be less than a full block, even for blocks that are
+	 * not the last in the file (e.g., as a result of making a hole and
+	 * appending data). Ensure that the remainder is zeroed out.
+	 */
+	if (len < UBIFS_BLOCK_SIZE)
+		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
+
+	return 0;
+
+dump:
+	ubifs_err("bad data node (block %u, inode %lu)",
+		  block, inode->i_ino);
+	dbg_dump_node(c, dn);
+	return -EINVAL;
+}
+
+static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *page)
+{
+	void *addr;
+	int err = 0, i;
+	unsigned int block, beyond;
+	struct ubifs_data_node *dn;
+	loff_t i_size = inode->i_size;
+
+	dbg_gen("ino %lu, pg %lu, i_size %lld",
+		inode->i_ino, page->index, i_size);
+
+	addr = kmap(page);
+
+	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+	if (block >= beyond) {
+		/* Reading beyond inode */
+		memset(addr, 0, PAGE_CACHE_SIZE);
+		goto out;
+	}
+
+	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
+	if (!dn) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	i = 0;
+	while (1) {
+		int ret;
+
+		if (block >= beyond) {
+			/* Reading beyond inode */
+			err = -ENOENT;
+			memset(addr, 0, UBIFS_BLOCK_SIZE);
+		} else {
+			ret = read_block(inode, addr, block, dn);
+			if (ret) {
+				err = ret;
+				if (err != -ENOENT)
+					break;
+			} else if (block + 1 == beyond) {
+				int dlen = le32_to_cpu(dn->size);
+				int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);
+
+				if (ilen && ilen < dlen)
+					memset(addr + ilen, 0, dlen - ilen);
+			}
+		}
+		if (++i >= UBIFS_BLOCKS_PER_PAGE)
+			break;
+		block += 1;
+		addr += UBIFS_BLOCK_SIZE;
+	}
+	if (err) {
+		if (err == -ENOENT) {
+			/* Not found, so it must be a hole */
+			dbg_gen("hole");
+			goto out_free;
+		}
+		ubifs_err("cannot read page %lu of inode %lu, error %d",
+			  page->index, inode->i_ino, err);
+		goto error;
+	}
+
+out_free:
+	kfree(dn);
+out:
+	return 0;
+
+error:
+	kfree(dn);
+	return err;
+}
+
+int ubifs_load(char *filename, u32 addr, u32 size)
+{
+	struct ubifs_info *c = ubifs_sb->s_fs_info;
+	unsigned long inum;
+	struct inode *inode;
+	struct page page;
+	int err = 0;
+	int i;
+	int count;
+	char link_name[64];
+	struct ubifs_inode *ui;
+
+	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+	inum = ubifs_findfile(ubifs_sb, filename);
+	if (!inum) {
+		err = -1;
+		goto out;
+	}
+
+	/*
+	 * Read file inode
+	 */
+	inode = ubifs_iget(ubifs_sb, inum);
+	if (IS_ERR(inode)) {
+		printf("%s: Error reading inode %ld!\n", __func__, inum);
+		err = PTR_ERR(inode);
+		goto out;
+	}
+
+	/*
+	 * Check for symbolic link
+	 */
+	ui = ubifs_inode(inode);
+	if (((inode->i_mode & S_IFMT) == S_IFLNK) && ui->data_len) {
+		memcpy(link_name, ui->data, ui->data_len);
+		printf("%s is linked to %s!\n", filename, link_name);
+		ubifs_iput(inode);
+
+		/*
+		 * Now we have the "real" filename, call ubifs_load()
+		 * again (recursive call) to load this file instead
+		 */
+		return ubifs_load(link_name, addr, size);
+	}
+
+	/*
+	 * If no size was specified or if size bigger than filesize
+	 * set size to filesize
+	 */
+	if ((size == 0) || (size > inode->i_size))
+		size = inode->i_size;
+
+	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+	printf("Loading file '%s' to addr 0x%08x with size %d (0x%08x)...\n",
+	       filename, addr, size, size);
+
+	page.addr = (void *)addr;
+	page.index = 0;
+	page.inode = inode;
+	for (i = 0; i < count; i++) {
+		err = do_readpage(c, inode, &page);
+		if (err)
+			break;
+
+		page.addr += PAGE_SIZE;
+		page.index++;
+	}
+
+	if (err)
+		printf("Error reading file '%s'\n", filename);
+	else
+		printf("Done\n");
+
+	ubifs_iput(inode);
+
+out:
+	ubi_close_volume(c->ubi);
+	return err;
+}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
new file mode 100644
index 0000000..f342dd8
--- /dev/null
+++ b/fs/ubifs/ubifs.h
@@ -0,0 +1,2173 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+#ifndef __UBIFS_H__
+#define __UBIFS_H__
+
+#if 0	/* Enable for debugging output */
+#define CONFIG_UBIFS_FS_DEBUG
+#define CONFIG_UBIFS_FS_DEBUG_MSG_LVL	3
+#endif
+
+#include <ubi_uboot.h>
+#include <linux/ctype.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include "ubifs-media.h"
+
+struct dentry;
+struct file;
+struct iattr;
+struct kstat;
+struct vfsmount;
+
+extern struct super_block *ubifs_sb;
+
+extern unsigned int ubifs_msg_flags;
+extern unsigned int ubifs_chk_flags;
+extern unsigned int ubifs_tst_flags;
+
+#define pgoff_t		unsigned long
+
+/*
+ * We "simulate" the Linux page struct much simpler here
+ */
+struct page {
+	pgoff_t index;
+	void *addr;
+	struct inode *inode;
+};
+
+void iput(struct inode *inode);
+
+/*
+ * The atomic operations are used for budgeting etc which is not
+ * needed for the read-only U-Boot implementation:
+ */
+#define atomic_long_inc(a)
+#define atomic_long_dec(a)
+#define	atomic_long_sub(a, b)
+
+/* linux/include/time.h */
+
+struct timespec {
+	time_t	tv_sec;		/* seconds */
+	long	tv_nsec;	/* nanoseconds */
+};
+
+/* linux/include/dcache.h */
+
+/*
+ * "quick string" -- eases parameter passing, but more importantly
+ * saves "metadata" about the string (ie length and the hash).
+ *
+ * hash comes first so it snuggles against d_parent in the
+ * dentry.
+ */
+struct qstr {
+	unsigned int hash;
+	unsigned int len;
+	const char *name;
+};
+
+struct inode {
+	struct hlist_node	i_hash;
+	struct list_head	i_list;
+	struct list_head	i_sb_list;
+	struct list_head	i_dentry;
+	unsigned long		i_ino;
+	unsigned int		i_nlink;
+	uid_t			i_uid;
+	gid_t			i_gid;
+	dev_t			i_rdev;
+	u64			i_version;
+	loff_t			i_size;
+#ifdef __NEED_I_SIZE_ORDERED
+	seqcount_t		i_size_seqcount;
+#endif
+	struct timespec		i_atime;
+	struct timespec		i_mtime;
+	struct timespec		i_ctime;
+	unsigned int		i_blkbits;
+	unsigned short          i_bytes;
+	umode_t			i_mode;
+	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
+	struct mutex		i_mutex;
+	struct rw_semaphore	i_alloc_sem;
+	const struct inode_operations	*i_op;
+	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
+	struct super_block	*i_sb;
+	struct file_lock	*i_flock;
+#ifdef CONFIG_QUOTA
+	struct dquot		*i_dquot[MAXQUOTAS];
+#endif
+	struct list_head	i_devices;
+	int			i_cindex;
+
+	__u32			i_generation;
+
+#ifdef CONFIG_DNOTIFY
+	unsigned long		i_dnotify_mask; /* Directory notify events */
+	struct dnotify_struct	*i_dnotify; /* for directory notifications */
+#endif
+
+#ifdef CONFIG_INOTIFY
+	struct list_head	inotify_watches; /* watches on this inode */
+	struct mutex		inotify_mutex;	/* protects the watches list */
+#endif
+
+	unsigned long		i_state;
+	unsigned long		dirtied_when;	/* jiffies of first dirtying */
+
+	unsigned int		i_flags;
+
+#ifdef CONFIG_SECURITY
+	void			*i_security;
+#endif
+	void			*i_private; /* fs or device private pointer */
+};
+
+struct super_block {
+	struct list_head	s_list;		/* Keep this first */
+	dev_t			s_dev;		/* search index; _not_ kdev_t */
+	unsigned long		s_blocksize;
+	unsigned char		s_blocksize_bits;
+	unsigned char		s_dirt;
+	unsigned long long	s_maxbytes;	/* Max file size */
+	struct file_system_type	*s_type;
+	const struct super_operations	*s_op;
+	struct dquot_operations	*dq_op;
+	struct quotactl_ops	*s_qcop;
+	const struct export_operations *s_export_op;
+	unsigned long		s_flags;
+	unsigned long		s_magic;
+	struct dentry		*s_root;
+	struct rw_semaphore	s_umount;
+	struct mutex		s_lock;
+	int			s_count;
+	int			s_syncing;
+	int			s_need_sync_fs;
+#ifdef CONFIG_SECURITY
+	void                    *s_security;
+#endif
+	struct xattr_handler	**s_xattr;
+
+	struct list_head	s_inodes;	/* all inodes */
+	struct list_head	s_dirty;	/* dirty inodes */
+	struct list_head	s_io;		/* parked for writeback */
+	struct list_head	s_more_io;	/* parked for more writeback */
+	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
+	struct list_head	s_files;
+	/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
+	struct list_head	s_dentry_lru;	/* unused dentry lru */
+	int			s_nr_dentry_unused;	/* # of dentry on lru */
+
+	struct block_device	*s_bdev;
+	struct mtd_info		*s_mtd;
+	struct list_head	s_instances;
+
+	int			s_frozen;
+	wait_queue_head_t	s_wait_unfrozen;
+
+	char s_id[32];				/* Informational name */
+
+	void 			*s_fs_info;	/* Filesystem private info */
+
+	/*
+	 * The next field is for VFS *only*. No filesystems have any business
+	 * even looking at it. You had been warned.
+	 */
+	struct mutex s_vfs_rename_mutex;	/* Kludge */
+
+	/* Granularity of c/m/atime in ns.
+	   Cannot be worse than a second */
+	u32		   s_time_gran;
+
+	/*
+	 * Filesystem subtype.  If non-empty the filesystem type field
+	 * in /proc/mounts will be "type.subtype"
+	 */
+	char *s_subtype;
+
+	/*
+	 * Saved mount options for lazy filesystems using
+	 * generic_show_options()
+	 */
+	char *s_options;
+};
+
+struct file_system_type {
+	const char *name;
+	int fs_flags;
+	int (*get_sb) (struct file_system_type *, int,
+		       const char *, void *, struct vfsmount *);
+	void (*kill_sb) (struct super_block *);
+	struct module *owner;
+	struct file_system_type * next;
+	struct list_head fs_supers;
+};
+
+struct vfsmount {
+	struct list_head mnt_hash;
+	struct vfsmount *mnt_parent;	/* fs we are mounted on */
+	struct dentry *mnt_mountpoint;	/* dentry of mountpoint */
+	struct dentry *mnt_root;	/* root of the mounted tree */
+	struct super_block *mnt_sb;	/* pointer to superblock */
+	struct list_head mnt_mounts;	/* list of children, anchored here */
+	struct list_head mnt_child;	/* and going through their mnt_child */
+	int mnt_flags;
+	/* 4 bytes hole on 64bits arches */
+	const char *mnt_devname;	/* Name of device e.g. /dev/dsk/hda1 */
+	struct list_head mnt_list;
+	struct list_head mnt_expire;	/* link in fs-specific expiry list */
+	struct list_head mnt_share;	/* circular list of shared mounts */
+	struct list_head mnt_slave_list;/* list of slave mounts */
+	struct list_head mnt_slave;	/* slave list entry */
+	struct vfsmount *mnt_master;	/* slave is on master->mnt_slave_list */
+	struct mnt_namespace *mnt_ns;	/* containing namespace */
+	int mnt_id;			/* mount identifier */
+	int mnt_group_id;		/* peer group identifier */
+	/*
+	 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
+	 * to let these frequently modified fields in a separate cache line
+	 * (so that reads of mnt_flags wont ping-pong on SMP machines)
+	 */
+	int mnt_expiry_mark;		/* true if marked for expiry */
+	int mnt_pinned;
+	int mnt_ghosts;
+	/*
+	 * This value is not stable unless all of the mnt_writers[] spinlocks
+	 * are held, and all mnt_writer[]s on this mount have 0 as their ->count
+	 */
+};
+
+struct path {
+	struct vfsmount *mnt;
+	struct dentry *dentry;
+};
+
+struct file {
+	struct path		f_path;
+#define f_dentry	f_path.dentry
+#define f_vfsmnt	f_path.mnt
+	const struct file_operations	*f_op;
+	unsigned int 		f_flags;
+	loff_t			f_pos;
+	unsigned int		f_uid, f_gid;
+
+	u64			f_version;
+#ifdef CONFIG_SECURITY
+	void			*f_security;
+#endif
+	/* needed for tty driver, and maybe others */
+	void			*private_data;
+
+#ifdef CONFIG_EPOLL
+	/* Used by fs/eventpoll.c to link all the hooks to this file */
+	struct list_head	f_ep_links;
+	spinlock_t		f_ep_lock;
+#endif /* #ifdef CONFIG_EPOLL */
+#ifdef CONFIG_DEBUG_WRITECOUNT
+	unsigned long f_mnt_write_state;
+#endif
+};
+
+/*
+ * get_seconds() not really needed in the read-only implmentation
+ */
+#define get_seconds()		0
+
+/* 4k page size */
+#define PAGE_CACHE_SHIFT	12
+#define PAGE_CACHE_SIZE		(1 << PAGE_CACHE_SHIFT)
+
+/* Page cache limit. The filesystems should put that into their s_maxbytes
+   limits, otherwise bad things can happen in VM. */
+#if BITS_PER_LONG==32
+#define MAX_LFS_FILESIZE	(((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
+#elif BITS_PER_LONG==64
+#define MAX_LFS_FILESIZE 	0x7fffffffffffffffUL
+#endif
+
+#define INT_MAX		((int)(~0U>>1))
+#define INT_MIN		(-INT_MAX - 1)
+#define LLONG_MAX	((long long)(~0ULL>>1))
+
+/*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+#define MS_RDONLY	 1	/* Mount read-only */
+#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
+#define MS_NODEV	 4	/* Disallow access to device special files */
+#define MS_NOEXEC	 8	/* Disallow program execution */
+#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
+#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
+#define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
+#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
+#define MS_NOATIME	1024	/* Do not update access times. */
+#define MS_NODIRATIME	2048	/* Do not update directory access times */
+#define MS_BIND		4096
+#define MS_MOVE		8192
+#define MS_REC		16384
+#define MS_VERBOSE	32768	/* War is peace. Verbosity is silence.
+				   MS_VERBOSE is deprecated. */
+#define MS_SILENT	32768
+#define MS_POSIXACL	(1<<16)	/* VFS does not apply the umask */
+#define MS_UNBINDABLE	(1<<17)	/* change to unbindable */
+#define MS_PRIVATE	(1<<18)	/* change to private */
+#define MS_SLAVE	(1<<19)	/* change to slave */
+#define MS_SHARED	(1<<20)	/* change to shared */
+#define MS_RELATIME	(1<<21)	/* Update atime relative to mtime/ctime. */
+#define MS_KERNMOUNT	(1<<22) /* this is a kern_mount call */
+#define MS_I_VERSION	(1<<23) /* Update inode I_version field */
+#define MS_ACTIVE	(1<<30)
+#define MS_NOUSER	(1<<31)
+
+#define I_NEW			8
+
+/* Inode flags - they have nothing to superblock flags now */
+
+#define S_SYNC		1	/* Writes are synced at once */
+#define S_NOATIME	2	/* Do not update access times */
+#define S_APPEND	4	/* Append-only file */
+#define S_IMMUTABLE	8	/* Immutable file */
+#define S_DEAD		16	/* removed, but still open directory */
+#define S_NOQUOTA	32	/* Inode is not counted to quota */
+#define S_DIRSYNC	64	/* Directory modifications are synchronous */
+#define S_NOCMTIME	128	/* Do not update file c/mtime */
+#define S_SWAPFILE	256	/* Do not truncate: swapon got its bmaps */
+#define S_PRIVATE	512	/* Inode is fs-internal */
+
+/* include/linux/stat.h */
+
+#define S_IFMT  00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK	 0120000
+#define S_IFREG  0100000
+#define S_IFBLK  0060000
+#define S_IFDIR  0040000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+#define S_ISUID  0004000
+#define S_ISGID  0002000
+#define S_ISVTX  0001000
+
+/* include/linux/fs.h */
+
+/*
+ * File types
+ *
+ * NOTE! These match bits 12..15 of stat.st_mode
+ * (ie "(i_mode >> 12) & 15").
+ */
+#define DT_UNKNOWN	0
+#define DT_FIFO		1
+#define DT_CHR		2
+#define DT_DIR		4
+#define DT_BLK		6
+#define DT_REG		8
+#define DT_LNK		10
+#define DT_SOCK		12
+#define DT_WHT		14
+
+#define I_DIRTY_SYNC		1
+#define I_DIRTY_DATASYNC	2
+#define I_DIRTY_PAGES		4
+#define I_NEW			8
+#define I_WILL_FREE		16
+#define I_FREEING		32
+#define I_CLEAR			64
+#define __I_LOCK		7
+#define I_LOCK			(1 << __I_LOCK)
+#define __I_SYNC		8
+#define I_SYNC			(1 << __I_SYNC)
+
+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
+
+/* linux/include/dcache.h */
+
+#define DNAME_INLINE_LEN_MIN 36
+
+struct dentry {
+	unsigned int d_flags;		/* protected by d_lock */
+	spinlock_t d_lock;		/* per dentry lock */
+	struct inode *d_inode;		/* Where the name belongs to - NULL is
+					 * negative */
+	/*
+	 * The next three fields are touched by __d_lookup.  Place them here
+	 * so they all fit in a cache line.
+	 */
+	struct hlist_node d_hash;	/* lookup hash list */
+	struct dentry *d_parent;	/* parent directory */
+	struct qstr d_name;
+
+	struct list_head d_lru;		/* LRU list */
+	/*
+	 * d_child and d_rcu can share memory
+	 */
+	struct list_head d_subdirs;	/* our children */
+	struct list_head d_alias;	/* inode alias list */
+	unsigned long d_time;		/* used by d_revalidate */
+	struct super_block *d_sb;	/* The root of the dentry tree */
+	void *d_fsdata;			/* fs-specific data */
+#ifdef CONFIG_PROFILING
+	struct dcookie_struct *d_cookie; /* cookie, if any */
+#endif
+	int d_mounted;
+	unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* small names */
+};
+
+static inline ino_t parent_ino(struct dentry *dentry)
+{
+	ino_t res;
+
+	spin_lock(&dentry->d_lock);
+	res = dentry->d_parent->d_inode->i_ino;
+	spin_unlock(&dentry->d_lock);
+	return res;
+}
+
+/* linux/include/linux/bitops.h */
+
+#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
+
+/* linux/include/asm-generic/bitops/non-atomic.h */
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p  |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p &= ~mask;
+}
+
+/* debug.c */
+
+#define DEFINE_SPINLOCK(...)
+#define module_param_named(...)
+
+/* misc.h */
+#define mutex_lock_nested(...)
+#define mutex_unlock_nested(...)
+#define mutex_is_locked(...)	0
+
+/* Version of this UBIFS implementation */
+#define UBIFS_VERSION 1
+
+/* Normal UBIFS messages */
+#define ubifs_msg(fmt, ...) \
+		printk(KERN_NOTICE "UBIFS: " fmt "\n", ##__VA_ARGS__)
+/* UBIFS error messages */
+#define ubifs_err(fmt, ...)                                                  \
+	printk(KERN_ERR "UBIFS error (pid %d): %s: " fmt "\n", 0, \
+	       __func__, ##__VA_ARGS__)
+/* UBIFS warning messages */
+#define ubifs_warn(fmt, ...)                                         \
+	printk(KERN_WARNING "UBIFS warning (pid %d): %s: " fmt "\n", \
+	       0, __func__, ##__VA_ARGS__)
+
+/* UBIFS file system VFS magic number */
+#define UBIFS_SUPER_MAGIC 0x24051905
+
+/* Number of UBIFS blocks per VFS page */
+#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE)
+#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT)
+
+/* "File system end of life" sequence number watermark */
+#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
+#define SQNUM_WATERMARK      0xFFFFFFFFFF000000ULL
+
+/*
+ * Minimum amount of LEBs reserved for the index. At present the index needs at
+ * least 2 LEBs: one for the index head and one for in-the-gaps method (which
+ * currently does not cater for the index head and so excludes it from
+ * consideration).
+ */
+#define MIN_INDEX_LEBS 2
+
+/* Minimum amount of data UBIFS writes to the flash */
+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
+
+/*
+ * Currently we do not support inode number overlapping and re-using, so this
+ * watermark defines dangerous inode number level. This should be fixed later,
+ * although it is difficult to exceed current limit. Another option is to use
+ * 64-bit inode numbers, but this means more overhead.
+ */
+#define INUM_WARN_WATERMARK 0xFFF00000
+#define INUM_WATERMARK      0xFFFFFF00
+
+/* Largest key size supported in this implementation */
+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+
+/* Maximum number of entries in each LPT (LEB category) heap */
+#define LPT_HEAP_SZ 256
+
+/*
+ * Background thread name pattern. The numbers are UBI device and volume
+ * numbers.
+ */
+#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
+
+/* Default write-buffer synchronization timeout (5 secs) */
+#define DEFAULT_WBUF_TIMEOUT (5 * HZ)
+
+/* Maximum possible inode number (only 32-bit inodes are supported now) */
+#define MAX_INUM 0xFFFFFFFF
+
+/* Number of non-data journal heads */
+#define NONDATA_JHEADS_CNT 2
+
+/* Garbage collector head */
+#define GCHD   0
+/* Base journal head number */
+#define BASEHD 1
+/* First "general purpose" journal head */
+#define DATAHD 2
+
+/* 'No change' value for 'ubifs_change_lp()' */
+#define LPROPS_NC 0x80000001
+
+/*
+ * There is no notion of truncation key because truncation nodes do not exist
+ * in TNC. However, when replaying, it is handy to introduce fake "truncation"
+ * keys for truncation nodes because the code becomes simpler. So we define
+ * %UBIFS_TRUN_KEY type.
+ */
+#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+
+/*
+ * How much a directory entry/extended attribute entry adds to the parent/host
+ * inode.
+ */
+#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8)
+
+/* How much an extended attribute adds to the host inode */
+#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
+
+/*
+ * Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered
+ * "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are
+ * considered "young". This is used by shrinker when selecting znode to trim
+ * off.
+ */
+#define OLD_ZNODE_AGE 20
+#define YOUNG_ZNODE_AGE 5
+
+/*
+ * Some compressors, like LZO, may end up with more data then the input buffer.
+ * So UBIFS always allocates larger output buffer, to be sure the compressor
+ * will not corrupt memory in case of worst case compression.
+ */
+#define WORST_COMPR_FACTOR 2
+
+/* Maximum expected tree height for use by bottom_up_buf */
+#define BOTTOM_UP_HEIGHT 64
+
+/* Maximum number of data nodes to bulk-read */
+#define UBIFS_MAX_BULK_READ 32
+
+/*
+ * Lockdep classes for UBIFS inode @ui_mutex.
+ */
+enum {
+	WB_MUTEX_1 = 0,
+	WB_MUTEX_2 = 1,
+	WB_MUTEX_3 = 2,
+};
+
+/*
+ * Znode flags (actually, bit numbers which store the flags).
+ *
+ * DIRTY_ZNODE: znode is dirty
+ * COW_ZNODE: znode is being committed and a new instance of this znode has to
+ *            be created before changing this znode
+ * OBSOLETE_ZNODE: znode is obsolete, which means it was deleted, but it is
+ *                 still in the commit list and the ongoing commit operation
+ *                 will commit it, and delete this znode after it is done
+ */
+enum {
+	DIRTY_ZNODE    = 0,
+	COW_ZNODE      = 1,
+	OBSOLETE_ZNODE = 2,
+};
+
+/*
+ * Commit states.
+ *
+ * COMMIT_RESTING: commit is not wanted
+ * COMMIT_BACKGROUND: background commit has been requested
+ * COMMIT_REQUIRED: commit is required
+ * COMMIT_RUNNING_BACKGROUND: background commit is running
+ * COMMIT_RUNNING_REQUIRED: commit is running and it is required
+ * COMMIT_BROKEN: commit failed
+ */
+enum {
+	COMMIT_RESTING = 0,
+	COMMIT_BACKGROUND,
+	COMMIT_REQUIRED,
+	COMMIT_RUNNING_BACKGROUND,
+	COMMIT_RUNNING_REQUIRED,
+	COMMIT_BROKEN,
+};
+
+/*
+ * 'ubifs_scan_a_node()' return values.
+ *
+ * SCANNED_GARBAGE:  scanned garbage
+ * SCANNED_EMPTY_SPACE: scanned empty space
+ * SCANNED_A_NODE: scanned a valid node
+ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node
+ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length
+ *
+ * Greater than zero means: 'scanned that number of padding bytes'
+ */
+enum {
+	SCANNED_GARBAGE        = 0,
+	SCANNED_EMPTY_SPACE    = -1,
+	SCANNED_A_NODE         = -2,
+	SCANNED_A_CORRUPT_NODE = -3,
+	SCANNED_A_BAD_PAD_NODE = -4,
+};
+
+/*
+ * LPT cnode flag bits.
+ *
+ * DIRTY_CNODE: cnode is dirty
+ * COW_CNODE: cnode is being committed and must be copied before writing
+ * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
+ * so it can (and must) be freed when the commit is finished
+ */
+enum {
+	DIRTY_CNODE    = 0,
+	COW_CNODE      = 1,
+	OBSOLETE_CNODE = 2,
+};
+
+/*
+ * Dirty flag bits (lpt_drty_flgs) for LPT special nodes.
+ *
+ * LTAB_DIRTY: ltab node is dirty
+ * LSAVE_DIRTY: lsave node is dirty
+ */
+enum {
+	LTAB_DIRTY  = 1,
+	LSAVE_DIRTY = 2,
+};
+
+/*
+ * Return codes used by the garbage collector.
+ * @LEB_FREED: the logical eraseblock was freed and is ready to use
+ * @LEB_FREED_IDX: indexing LEB was freed and can be used only after the commit
+ * @LEB_RETAINED: the logical eraseblock was freed and retained for GC purposes
+ */
+enum {
+	LEB_FREED,
+	LEB_FREED_IDX,
+	LEB_RETAINED,
+};
+
+/**
+ * struct ubifs_old_idx - index node obsoleted since last commit start.
+ * @rb: rb-tree node
+ * @lnum: LEB number of obsoleted index node
+ * @offs: offset of obsoleted index node
+ */
+struct ubifs_old_idx {
+	struct rb_node rb;
+	int lnum;
+	int offs;
+};
+
+/* The below union makes it easier to deal with keys */
+union ubifs_key {
+	uint8_t u8[CUR_MAX_KEY_LEN];
+	uint32_t u32[CUR_MAX_KEY_LEN/4];
+	uint64_t u64[CUR_MAX_KEY_LEN/8];
+	__le32 j32[CUR_MAX_KEY_LEN/4];
+};
+
+/**
+ * struct ubifs_scan_node - UBIFS scanned node information.
+ * @list: list of scanned nodes
+ * @key: key of node scanned (if it has one)
+ * @sqnum: sequence number
+ * @type: type of node scanned
+ * @offs: offset with LEB of node scanned
+ * @len: length of node scanned
+ * @node: raw node
+ */
+struct ubifs_scan_node {
+	struct list_head list;
+	union ubifs_key key;
+	unsigned long long sqnum;
+	int type;
+	int offs;
+	int len;
+	void *node;
+};
+
+/**
+ * struct ubifs_scan_leb - UBIFS scanned LEB information.
+ * @lnum: logical eraseblock number
+ * @nodes_cnt: number of nodes scanned
+ * @nodes: list of struct ubifs_scan_node
+ * @endpt: end point (and therefore the start of empty space)
+ * @ecc: read returned -EBADMSG
+ * @buf: buffer containing entire LEB scanned
+ */
+struct ubifs_scan_leb {
+	int lnum;
+	int nodes_cnt;
+	struct list_head nodes;
+	int endpt;
+	int ecc;
+	void *buf;
+};
+
+/**
+ * struct ubifs_gced_idx_leb - garbage-collected indexing LEB.
+ * @list: list
+ * @lnum: LEB number
+ * @unmap: OK to unmap this LEB
+ *
+ * This data structure is used to temporary store garbage-collected indexing
+ * LEBs - they are not released immediately, but only after the next commit.
+ * This is needed to guarantee recoverability.
+ */
+struct ubifs_gced_idx_leb {
+	struct list_head list;
+	int lnum;
+	int unmap;
+};
+
+/**
+ * struct ubifs_inode - UBIFS in-memory inode description.
+ * @vfs_inode: VFS inode description object
+ * @creat_sqnum: sequence number at time of creation
+ * @del_cmtno: commit number corresponding to the time the inode was deleted,
+ *             protected by @c->commit_sem;
+ * @xattr_size: summarized size of all extended attributes in bytes
+ * @xattr_cnt: count of extended attributes this inode has
+ * @xattr_names: sum of lengths of all extended attribute names belonging to
+ *               this inode
+ * @dirty: non-zero if the inode is dirty
+ * @xattr: non-zero if this is an extended attribute inode
+ * @bulk_read: non-zero if bulk-read should be used
+ * @ui_mutex: serializes inode write-back with the rest of VFS operations,
+ *            serializes "clean <-> dirty" state changes, serializes bulk-read,
+ *            protects @dirty, @bulk_read, @ui_size, and @xattr_size
+ * @ui_lock: protects @synced_i_size
+ * @synced_i_size: synchronized size of inode, i.e. the value of inode size
+ *                 currently stored on the flash; used only for regular file
+ *                 inodes
+ * @ui_size: inode size used by UBIFS when writing to flash
+ * @flags: inode flags (@UBIFS_COMPR_FL, etc)
+ * @compr_type: default compression type used for this inode
+ * @last_page_read: page number of last page read (for bulk read)
+ * @read_in_a_row: number of consecutive pages read in a row (for bulk read)
+ * @data_len: length of the data attached to the inode
+ * @data: inode's data
+ *
+ * @ui_mutex exists for two main reasons. At first it prevents inodes from
+ * being written back while UBIFS changing them, being in the middle of an VFS
+ * operation. This way UBIFS makes sure the inode fields are consistent. For
+ * example, in 'ubifs_rename()' we change 3 inodes simultaneously, and
+ * write-back must not write any of them before we have finished.
+ *
+ * The second reason is budgeting - UBIFS has to budget all operations. If an
+ * operation is going to mark an inode dirty, it has to allocate budget for
+ * this. It cannot just mark it dirty because there is no guarantee there will
+ * be enough flash space to write the inode back later. This means UBIFS has
+ * to have full control over inode "clean <-> dirty" transitions (and pages
+ * actually). But unfortunately, VFS marks inodes dirty in many places, and it
+ * does not ask the file-system if it is allowed to do so (there is a notifier,
+ * but it is not enough), i.e., there is no mechanism to synchronize with this.
+ * So UBIFS has its own inode dirty flag and its own mutex to serialize
+ * "clean <-> dirty" transitions.
+ *
+ * The @synced_i_size field is used to make sure we never write pages which are
+ * beyond last synchronized inode size. See 'ubifs_writepage()' for more
+ * information.
+ *
+ * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
+ * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
+ * make sure @inode->i_size is always changed under @ui_mutex, because it
+ * cannot call 'vmtruncate()' with @ui_mutex locked, because it would deadlock
+ * with 'ubifs_writepage()' (see file.c). All the other inode fields are
+ * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+ * could consider to rework locking and base it on "shadow" fields.
+ */
+struct ubifs_inode {
+	struct inode vfs_inode;
+	unsigned long long creat_sqnum;
+	unsigned long long del_cmtno;
+	unsigned int xattr_size;
+	unsigned int xattr_cnt;
+	unsigned int xattr_names;
+	unsigned int dirty:1;
+	unsigned int xattr:1;
+	unsigned int bulk_read:1;
+	unsigned int compr_type:2;
+	struct mutex ui_mutex;
+	spinlock_t ui_lock;
+	loff_t synced_i_size;
+	loff_t ui_size;
+	int flags;
+	pgoff_t last_page_read;
+	pgoff_t read_in_a_row;
+	int data_len;
+	void *data;
+};
+
+/**
+ * struct ubifs_unclean_leb - records a LEB recovered under read-only mode.
+ * @list: list
+ * @lnum: LEB number of recovered LEB
+ * @endpt: offset where recovery ended
+ *
+ * This structure records a LEB identified during recovery that needs to be
+ * cleaned but was not because UBIFS was mounted read-only. The information
+ * is used to clean the LEB when remounting to read-write mode.
+ */
+struct ubifs_unclean_leb {
+	struct list_head list;
+	int lnum;
+	int endpt;
+};
+
+/*
+ * LEB properties flags.
+ *
+ * LPROPS_UNCAT: not categorized
+ * LPROPS_DIRTY: dirty > free, dirty >= @c->dead_wm, not index
+ * LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index
+ * LPROPS_FREE: free > 0, dirty < @c->dead_wm, not empty, not index
+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
+ * LPROPS_EMPTY: LEB is empty, not taken
+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken
+ * LPROPS_CAT_MASK: mask for the LEB categories above
+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media)
+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash)
+ */
+enum {
+	LPROPS_UNCAT     =  0,
+	LPROPS_DIRTY     =  1,
+	LPROPS_DIRTY_IDX =  2,
+	LPROPS_FREE      =  3,
+	LPROPS_HEAP_CNT  =  3,
+	LPROPS_EMPTY     =  4,
+	LPROPS_FREEABLE  =  5,
+	LPROPS_FRDI_IDX  =  6,
+	LPROPS_CAT_MASK  = 15,
+	LPROPS_TAKEN     = 16,
+	LPROPS_INDEX     = 32,
+};
+
+/**
+ * struct ubifs_lprops - logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @flags: LEB properties flags (see above)
+ * @lnum: LEB number
+ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE)
+ * @hpos: heap position in heap of same-category lprops (other categories)
+ */
+struct ubifs_lprops {
+	int free;
+	int dirty;
+	int flags;
+	int lnum;
+	union {
+		struct list_head list;
+		int hpos;
+	};
+};
+
+/**
+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties.
+ * @free: amount of free space in bytes
+ * @dirty: amount of dirty space in bytes
+ * @tgc: trivial GC flag (1 => unmap after commit end)
+ * @cmt: commit flag (1 => reserved for commit)
+ */
+struct ubifs_lpt_lprops {
+	int free;
+	int dirty;
+	unsigned tgc:1;
+	unsigned cmt:1;
+};
+
+/**
+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area.
+ * @empty_lebs: number of empty LEBs
+ * @taken_empty_lebs: number of taken LEBs
+ * @idx_lebs: number of indexing LEBs
+ * @total_free: total free space in bytes (includes all LEBs)
+ * @total_dirty: total dirty space in bytes (includes all LEBs)
+ * @total_used: total used space in bytes (does not include index LEBs)
+ * @total_dead: total dead space in bytes (does not include index LEBs)
+ * @total_dark: total dark space in bytes (does not include index LEBs)
+ *
+ * The @taken_empty_lebs field counts the LEBs that are in the transient state
+ * of having been "taken" for use but not yet written to. @taken_empty_lebs is
+ * needed to account correctly for @gc_lnum, otherwise @empty_lebs could be
+ * used by itself (in which case 'unused_lebs' would be a better name). In the
+ * case of @gc_lnum, it is "taken" at mount time or whenever a LEB is retained
+ * by GC, but unlike other empty LEBs that are "taken", it may not be written
+ * straight away (i.e. before the next commit start or unmount), so either
+ * @gc_lnum must be specially accounted for, or the current approach followed
+ * i.e. count it under @taken_empty_lebs.
+ *
+ * @empty_lebs includes @taken_empty_lebs.
+ *
+ * @total_used, @total_dead and @total_dark fields do not account indexing
+ * LEBs.
+ */
+struct ubifs_lp_stats {
+	int empty_lebs;
+	int taken_empty_lebs;
+	int idx_lebs;
+	long long total_free;
+	long long total_dirty;
+	long long total_used;
+	long long total_dead;
+	long long total_dark;
+};
+
+struct ubifs_nnode;
+
+/**
+ * struct ubifs_cnode - LEB Properties Tree common node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes)
+ * @num: node number
+ */
+struct ubifs_cnode {
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+};
+
+/**
+ * struct ubifs_pnode - LEB Properties Tree leaf node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always zero for pnodes)
+ * @num: node number
+ * @lprops: LEB properties array
+ */
+struct ubifs_pnode {
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_lprops lprops[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_nbranch - LEB Properties Tree internal node branch.
+ * @lnum: LEB number of child
+ * @offs: offset of child
+ * @nnode: nnode child
+ * @pnode: pnode child
+ * @cnode: cnode child
+ */
+struct ubifs_nbranch {
+	int lnum;
+	int offs;
+	union {
+		struct ubifs_nnode *nnode;
+		struct ubifs_pnode *pnode;
+		struct ubifs_cnode *cnode;
+	};
+};
+
+/**
+ * struct ubifs_nnode - LEB Properties Tree internal node.
+ * @parent: parent nnode
+ * @cnext: next cnode to commit
+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE)
+ * @iip: index in parent
+ * @level: level in the tree (always greater than zero for nnodes)
+ * @num: node number
+ * @nbranch: branches to child nodes
+ */
+struct ubifs_nnode {
+	struct ubifs_nnode *parent;
+	struct ubifs_cnode *cnext;
+	unsigned long flags;
+	int iip;
+	int level;
+	int num;
+	struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT];
+};
+
+/**
+ * struct ubifs_lpt_heap - heap of categorized lprops.
+ * @arr: heap array
+ * @cnt: number in heap
+ * @max_cnt: maximum number allowed in heap
+ *
+ * There are %LPROPS_HEAP_CNT heaps.
+ */
+struct ubifs_lpt_heap {
+	struct ubifs_lprops **arr;
+	int cnt;
+	int max_cnt;
+};
+
+/*
+ * Return codes for LPT scan callback function.
+ *
+ * LPT_SCAN_CONTINUE: continue scanning
+ * LPT_SCAN_ADD: add the LEB properties scanned to the tree in memory
+ * LPT_SCAN_STOP: stop scanning
+ */
+enum {
+	LPT_SCAN_CONTINUE = 0,
+	LPT_SCAN_ADD = 1,
+	LPT_SCAN_STOP = 2,
+};
+
+struct ubifs_info;
+
+/* Callback used by the 'ubifs_lpt_scan_nolock()' function */
+typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+				       const struct ubifs_lprops *lprops,
+				       int in_tree, void *data);
+
+/**
+ * struct ubifs_wbuf - UBIFS write-buffer.
+ * @c: UBIFS file-system description object
+ * @buf: write-buffer (of min. flash I/O unit size)
+ * @lnum: logical eraseblock number the write-buffer points to
+ * @offs: write-buffer offset in this logical eraseblock
+ * @avail: number of bytes available in the write-buffer
+ * @used:  number of used bytes in the write-buffer
+ * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
+ * %UBI_UNKNOWN)
+ * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
+ *         up by 'mutex_lock_nested()).
+ * @sync_callback: write-buffer synchronization callback
+ * @io_mutex: serializes write-buffer I/O
+ * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
+ *        fields
+ * @timer: write-buffer timer
+ * @timeout: timer expire interval in jiffies
+ * @need_sync: it is set if its timer expired and needs sync
+ * @next_ino: points to the next position of the following inode number
+ * @inodes: stores the inode numbers of the nodes which are in wbuf
+ *
+ * The write-buffer synchronization callback is called when the write-buffer is
+ * synchronized in order to notify how much space was wasted due to
+ * write-buffer padding and how much free space is left in the LEB.
+ *
+ * Note: the fields @buf, @lnum, @offs, @avail and @used can be read under
+ * spin-lock or mutex because they are written under both mutex and spin-lock.
+ * @buf is appended to under mutex but overwritten under both mutex and
+ * spin-lock. Thus the data between @buf and @buf + @used can be read under
+ * spinlock.
+ */
+struct ubifs_wbuf {
+	struct ubifs_info *c;
+	void *buf;
+	int lnum;
+	int offs;
+	int avail;
+	int used;
+	int dtype;
+	int jhead;
+	int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
+	struct mutex io_mutex;
+	spinlock_t lock;
+	int timeout;
+	int need_sync;
+	int next_ino;
+	ino_t *inodes;
+};
+
+/**
+ * struct ubifs_bud - bud logical eraseblock.
+ * @lnum: logical eraseblock number
+ * @start: where the (uncommitted) bud data starts
+ * @jhead: journal head number this bud belongs to
+ * @list: link in the list buds belonging to the same journal head
+ * @rb: link in the tree of all buds
+ */
+struct ubifs_bud {
+	int lnum;
+	int start;
+	int jhead;
+	struct list_head list;
+	struct rb_node rb;
+};
+
+/**
+ * struct ubifs_jhead - journal head.
+ * @wbuf: head's write-buffer
+ * @buds_list: list of bud LEBs belonging to this journal head
+ *
+ * Note, the @buds list is protected by the @c->buds_lock.
+ */
+struct ubifs_jhead {
+	struct ubifs_wbuf wbuf;
+	struct list_head buds_list;
+};
+
+/**
+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes.
+ * @key: key
+ * @znode: znode address in memory
+ * @lnum: LEB number of the target node (indexing node or data node)
+ * @offs: target node offset within @lnum
+ * @len: target node length
+ */
+struct ubifs_zbranch {
+	union ubifs_key key;
+	union {
+		struct ubifs_znode *znode;
+		void *leaf;
+	};
+	int lnum;
+	int offs;
+	int len;
+};
+
+/**
+ * struct ubifs_znode - in-memory representation of an indexing node.
+ * @parent: parent znode or NULL if it is the root
+ * @cnext: next znode to commit
+ * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
+ * @time: last access time (seconds)
+ * @level: level of the entry in the TNC tree
+ * @child_cnt: count of child znodes
+ * @iip: index in parent's zbranch array
+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0
+ * @lnum: LEB number of the corresponding indexing node
+ * @offs: offset of the corresponding indexing node
+ * @len: length  of the corresponding indexing node
+ * @zbranch: array of znode branches (@c->fanout elements)
+ */
+struct ubifs_znode {
+	struct ubifs_znode *parent;
+	struct ubifs_znode *cnext;
+	unsigned long flags;
+	unsigned long time;
+	int level;
+	int child_cnt;
+	int iip;
+	int alt;
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	int lnum, offs, len;
+#endif
+	struct ubifs_zbranch zbranch[];
+};
+
+/**
+ * struct bu_info - bulk-read information.
+ * @key: first data node key
+ * @zbranch: zbranches of data nodes to bulk read
+ * @buf: buffer to read into
+ * @buf_len: buffer length
+ * @gc_seq: GC sequence number to detect races with GC
+ * @cnt: number of data nodes for bulk read
+ * @blk_cnt: number of data blocks including holes
+ * @oef: end of file reached
+ */
+struct bu_info {
+	union ubifs_key key;
+	struct ubifs_zbranch zbranch[UBIFS_MAX_BULK_READ];
+	void *buf;
+	int buf_len;
+	int gc_seq;
+	int cnt;
+	int blk_cnt;
+	int eof;
+};
+
+/**
+ * struct ubifs_node_range - node length range description data structure.
+ * @len: fixed node length
+ * @min_len: minimum possible node length
+ * @max_len: maximum possible node length
+ *
+ * If @max_len is %0, the node has fixed length @len.
+ */
+struct ubifs_node_range {
+	union {
+		int len;
+		int min_len;
+	};
+	int max_len;
+};
+
+/**
+ * struct ubifs_compressor - UBIFS compressor description structure.
+ * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc)
+ * @cc: cryptoapi compressor handle
+ * @comp_mutex: mutex used during compression
+ * @decomp_mutex: mutex used during decompression
+ * @name: compressor name
+ * @capi_name: cryptoapi compressor name
+ */
+struct ubifs_compressor {
+	int compr_type;
+	char *name;
+	char *capi_name;
+	int (*decompress)(const unsigned char *in, size_t in_len,
+			  unsigned char *out, size_t *out_len);
+};
+
+/**
+ * struct ubifs_budget_req - budget requirements of an operation.
+ *
+ * @fast: non-zero if the budgeting should try to acquire budget quickly and
+ *        should not try to call write-back
+ * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields
+ *               have to be re-calculated
+ * @new_page: non-zero if the operation adds a new page
+ * @dirtied_page: non-zero if the operation makes a page dirty
+ * @new_dent: non-zero if the operation adds a new directory entry
+ * @mod_dent: non-zero if the operation removes or modifies an existing
+ *            directory entry
+ * @new_ino: non-zero if the operation adds a new inode
+ * @new_ino_d: now much data newly created inode contains
+ * @dirtied_ino: how many inodes the operation makes dirty
+ * @dirtied_ino_d: now much data dirtied inode contains
+ * @idx_growth: how much the index will supposedly grow
+ * @data_growth: how much new data the operation will supposedly add
+ * @dd_growth: how much data that makes other data dirty the operation will
+ *             supposedly add
+ *
+ * @idx_growth, @data_growth and @dd_growth are not used in budget request. The
+ * budgeting subsystem caches index and data growth values there to avoid
+ * re-calculating them when the budget is released. However, if @idx_growth is
+ * %-1, it is calculated by the release function using other fields.
+ *
+ * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d
+ * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made
+ * dirty by the re-name operation.
+ *
+ * Note, UBIFS aligns node lengths to 8-bytes boundary, so the requester has to
+ * make sure the amount of inode data which contribute to @new_ino_d and
+ * @dirtied_ino_d fields are aligned.
+ */
+struct ubifs_budget_req {
+	unsigned int fast:1;
+	unsigned int recalculate:1;
+#ifndef UBIFS_DEBUG
+	unsigned int new_page:1;
+	unsigned int dirtied_page:1;
+	unsigned int new_dent:1;
+	unsigned int mod_dent:1;
+	unsigned int new_ino:1;
+	unsigned int new_ino_d:13;
+	unsigned int dirtied_ino:4;
+	unsigned int dirtied_ino_d:15;
+#else
+	/* Not bit-fields to check for overflows */
+	unsigned int new_page;
+	unsigned int dirtied_page;
+	unsigned int new_dent;
+	unsigned int mod_dent;
+	unsigned int new_ino;
+	unsigned int new_ino_d;
+	unsigned int dirtied_ino;
+	unsigned int dirtied_ino_d;
+#endif
+	int idx_growth;
+	int data_growth;
+	int dd_growth;
+};
+
+/**
+ * struct ubifs_orphan - stores the inode number of an orphan.
+ * @rb: rb-tree node of rb-tree of orphans sorted by inode number
+ * @list: list head of list of orphans in order added
+ * @new_list: list head of list of orphans added since the last commit
+ * @cnext: next orphan to commit
+ * @dnext: next orphan to delete
+ * @inum: inode number
+ * @new: %1 => added since the last commit, otherwise %0
+ */
+struct ubifs_orphan {
+	struct rb_node rb;
+	struct list_head list;
+	struct list_head new_list;
+	struct ubifs_orphan *cnext;
+	struct ubifs_orphan *dnext;
+	ino_t inum;
+	int new;
+};
+
+/**
+ * struct ubifs_mount_opts - UBIFS-specific mount options information.
+ * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
+ * @bulk_read: enable/disable bulk-reads (%0 default, %1 disabe, %2 enable)
+ * @chk_data_crc: enable/disable CRC data checking when reading data nodes
+ *                (%0 default, %1 disabe, %2 enable)
+ * @override_compr: override default compressor (%0 - do not override and use
+ *                  superblock compressor, %1 - override and use compressor
+ *                  specified in @compr_type)
+ * @compr_type: compressor type to override the superblock compressor with
+ *              (%UBIFS_COMPR_NONE, etc)
+ */
+struct ubifs_mount_opts {
+	unsigned int unmount_mode:2;
+	unsigned int bulk_read:2;
+	unsigned int chk_data_crc:2;
+	unsigned int override_compr:1;
+	unsigned int compr_type:2;
+};
+
+struct ubifs_debug_info;
+
+/**
+ * struct ubifs_info - UBIFS file-system description data structure
+ * (per-superblock).
+ * @vfs_sb: VFS @struct super_block object
+ * @bdi: backing device info object to make VFS happy and disable read-ahead
+ *
+ * @highest_inum: highest used inode number
+ * @max_sqnum: current global sequence number
+ * @cmt_no: commit number of the last successfully completed commit, protected
+ *          by @commit_sem
+ * @cnt_lock: protects @highest_inum and @max_sqnum counters
+ * @fmt_version: UBIFS on-flash format version
+ * @uuid: UUID from super block
+ *
+ * @lhead_lnum: log head logical eraseblock number
+ * @lhead_offs: log head offset
+ * @ltail_lnum: log tail logical eraseblock number (offset is always 0)
+ * @log_mutex: protects the log, @lhead_lnum, @lhead_offs, @ltail_lnum, and
+ *             @bud_bytes
+ * @min_log_bytes: minimum required number of bytes in the log
+ * @cmt_bud_bytes: used during commit to temporarily amount of bytes in
+ *                 committed buds
+ *
+ * @buds: tree of all buds indexed by bud LEB number
+ * @bud_bytes: how many bytes of flash is used by buds
+ * @buds_lock: protects the @buds tree, @bud_bytes, and per-journal head bud
+ *             lists
+ * @jhead_cnt: count of journal heads
+ * @jheads: journal heads (head zero is base head)
+ * @max_bud_bytes: maximum number of bytes allowed in buds
+ * @bg_bud_bytes: number of bud bytes when background commit is initiated
+ * @old_buds: buds to be released after commit ends
+ * @max_bud_cnt: maximum number of buds
+ *
+ * @commit_sem: synchronizes committer with other processes
+ * @cmt_state: commit state
+ * @cs_lock: commit state lock
+ * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
+ *
+ * @big_lpt: flag that LPT is too big to write whole during commit
+ * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+ *                   recovery)
+ * @bulk_read: enable bulk-reads
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ *
+ * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
+ *             @calc_idx_sz
+ * @zroot: zbranch which points to the root index node and znode
+ * @cnext: next znode to commit
+ * @enext: next znode to commit to empty space
+ * @gap_lebs: array of LEBs used by the in-gaps commit method
+ * @cbuf: commit buffer
+ * @ileb_buf: buffer for commit in-the-gaps method
+ * @ileb_len: length of data in ileb_buf
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ * @ilebs: pre-allocated index LEBs
+ * @ileb_cnt: number of pre-allocated index LEBs
+ * @ileb_nxt: next pre-allocated index LEBs
+ * @old_idx: tree of index nodes obsoleted since the last commit start
+ * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c
+ *
+ * @mst_node: master node
+ * @mst_offs: offset of valid master node
+ * @mst_mutex: protects the master node area, @mst_node, and @mst_offs
+ *
+ * @max_bu_buf_len: maximum bulk-read buffer length
+ * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
+ * @bu: pre-allocated bulk-read information
+ *
+ * @log_lebs: number of logical eraseblocks in the log
+ * @log_bytes: log size in bytes
+ * @log_last: last LEB of the log
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @lpt_first: first LEB of the lprops table area
+ * @lpt_last: last LEB of the lprops table area
+ * @orph_lebs: number of LEBs used for the orphan area
+ * @orph_first: first LEB of the orphan area
+ * @orph_last: last LEB of the orphan area
+ * @main_lebs: count of LEBs in the main area
+ * @main_first: first LEB of the main area
+ * @main_bytes: main area size in bytes
+ *
+ * @key_hash_type: type of the key hash
+ * @key_hash: direntry key hash function
+ * @key_fmt: key format
+ * @key_len: key length
+ * @fanout: fanout of the index tree (number of links per indexing node)
+ *
+ * @min_io_size: minimal input/output unit size
+ * @min_io_shift: number of bits in @min_io_size minus one
+ * @leb_size: logical eraseblock size in bytes
+ * @half_leb_size: half LEB size
+ * @leb_cnt: count of logical eraseblocks
+ * @max_leb_cnt: maximum count of logical eraseblocks
+ * @old_leb_cnt: count of logical eraseblocks before re-size
+ * @ro_media: the underlying UBI volume is read-only
+ *
+ * @dirty_pg_cnt: number of dirty pages (not used)
+ * @dirty_zn_cnt: number of dirty znodes
+ * @clean_zn_cnt: number of clean znodes
+ *
+ * @budg_idx_growth: amount of bytes budgeted for index growth
+ * @budg_data_growth: amount of bytes budgeted for cached data
+ * @budg_dd_growth: amount of bytes budgeted for cached data that will make
+ *                  other data dirty
+ * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
+ *                        but which still have to be taken into account because
+ *                        the index has not been committed so far
+ * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
+ *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
+ *              @nospace, and @nospace_rp;
+ * @min_idx_lebs: minimum number of LEBs required for the index
+ * @old_idx_sz: size of index on flash
+ * @calc_idx_sz: temporary variable which is used to calculate new index size
+ *               (contains accurate new index size at end of TNC commit start)
+ * @lst: lprops statistics
+ * @nospace: non-zero if the file-system does not have flash space (used as
+ *           optimization)
+ * @nospace_rp: the same as @nospace, but additionally means that even reserved
+ *              pool is full
+ *
+ * @page_budget: budget for a page
+ * @inode_budget: budget for an inode
+ * @dent_budget: budget for a directory entry
+ *
+ * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
+ * I/O unit
+ * @mst_node_alsz: master node aligned size
+ * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
+ * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
+ * @max_inode_sz: maximum possible inode size in bytes
+ * @max_znode_sz: size of znode in bytes
+ *
+ * @leb_overhead: how many bytes are wasted in an LEB when it is filled with
+ *                data nodes of maximum size - used in free space reporting
+ * @dead_wm: LEB dead space watermark
+ * @dark_wm: LEB dark space watermark
+ * @block_cnt: count of 4KiB blocks on the FS
+ *
+ * @ranges: UBIFS node length ranges
+ * @ubi: UBI volume descriptor
+ * @di: UBI device information
+ * @vi: UBI volume information
+ *
+ * @orph_tree: rb-tree of orphan inode numbers
+ * @orph_list: list of orphan inode numbers in order added
+ * @orph_new: list of orphan inode numbers added since last commit
+ * @orph_cnext: next orphan to commit
+ * @orph_dnext: next orphan to delete
+ * @orphan_lock: lock for orph_tree and orph_new
+ * @orph_buf: buffer for orphan nodes
+ * @new_orphans: number of orphans since last commit
+ * @cmt_orphans: number of orphans being committed
+ * @tot_orphans: number of orphans in the rb_tree
+ * @max_orphans: maximum number of orphans allowed
+ * @ohead_lnum: orphan head LEB number
+ * @ohead_offs: orphan head offset
+ * @no_orphs: non-zero if there are no orphans
+ *
+ * @bgt: UBIFS background thread
+ * @bgt_name: background thread name
+ * @need_bgt: if background thread should run
+ * @need_wbuf_sync: if write-buffers have to be synchronized
+ *
+ * @gc_lnum: LEB number used for garbage collection
+ * @sbuf: a buffer of LEB size used by GC and replay for scanning
+ * @idx_gc: list of index LEBs that have been garbage collected
+ * @idx_gc_cnt: number of elements on the idx_gc list
+ * @gc_seq: incremented for every non-index LEB garbage collected
+ * @gced_lnum: last non-index LEB that was garbage collected
+ *
+ * @infos_list: links all 'ubifs_info' objects
+ * @umount_mutex: serializes shrinker and un-mount
+ * @shrinker_run_no: shrinker run number
+ *
+ * @space_bits: number of bits needed to record free or dirty space
+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT
+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT
+ * @lpt_spc_bits: number of bits needed to space in the LPT
+ * @pcnt_bits: number of bits needed to record pnode or nnode number
+ * @lnum_bits: number of bits needed to record LEB number
+ * @nnode_sz: size of on-flash nnode
+ * @pnode_sz: size of on-flash pnode
+ * @ltab_sz: size of on-flash LPT lprops table
+ * @lsave_sz: size of on-flash LPT save table
+ * @pnode_cnt: number of pnodes
+ * @nnode_cnt: number of nnodes
+ * @lpt_hght: height of the LPT
+ * @pnodes_have: number of pnodes in memory
+ *
+ * @lp_mutex: protects lprops table and all the other lprops-related fields
+ * @lpt_lnum: LEB number of the root nnode of the LPT
+ * @lpt_offs: offset of the root nnode of the LPT
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab
+ * @dirty_nn_cnt: number of dirty nnodes
+ * @dirty_pn_cnt: number of dirty pnodes
+ * @check_lpt_free: flag that indicates LPT GC may be needed
+ * @lpt_sz: LPT size
+ * @lpt_nod_buf: buffer for an on-flash nnode or pnode
+ * @lpt_buf: buffer of LEB size used by LPT
+ * @nroot: address in memory of the root nnode of the LPT
+ * @lpt_cnext: next LPT node to commit
+ * @lpt_heap: array of heaps of categorized lprops
+ * @dirty_idx: a (reverse sorted) copy of the LPROPS_DIRTY_IDX heap as at
+ *             previous commit start
+ * @uncat_list: list of un-categorized LEBs
+ * @empty_list: list of empty LEBs
+ * @freeable_list: list of freeable non-index LEBs (free + dirty == leb_size)
+ * @frdi_idx_list: list of freeable index LEBs (free + dirty == leb_size)
+ * @freeable_cnt: number of freeable LEBs in @freeable_list
+ *
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @ltab: LPT's own lprops table
+ * @ltab_cmt: LPT's own lprops table (commit copy)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @lsave_lnum: LEB number of LPT's save table
+ * @lsave_offs: offset of LPT's save table
+ * @lsave: LPT's save table
+ * @lscan_lnum: LEB number of last LPT scan
+ *
+ * @rp_size: size of the reserved pool in bytes
+ * @report_rp_size: size of the reserved pool reported to user-space
+ * @rp_uid: reserved pool user ID
+ * @rp_gid: reserved pool group ID
+ *
+ * @empty: if the UBI device is empty
+ * @replay_tree: temporary tree used during journal replay
+ * @replay_list: temporary list used during journal replay
+ * @replay_buds: list of buds to replay
+ * @cs_sqnum: sequence number of first node in the log (commit start node)
+ * @replay_sqnum: sequence number of node currently being replayed
+ * @need_recovery: file-system needs recovery
+ * @replaying: set to %1 during journal replay
+ * @unclean_leb_list: LEBs to recover when mounting ro to rw
+ * @rcvrd_mst_node: recovered master node to write when mounting ro to rw
+ * @size_tree: inode size information for recovery
+ * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
+ * @always_chk_crc: always check CRCs (while mounting and remounting rw)
+ * @mount_opts: UBIFS-specific mount options
+ *
+ * @dbg: debugging-related information
+ */
+struct ubifs_info {
+	struct super_block *vfs_sb;
+
+	ino_t highest_inum;
+	unsigned long long max_sqnum;
+	unsigned long long cmt_no;
+	spinlock_t cnt_lock;
+	int fmt_version;
+	unsigned char uuid[16];
+
+	int lhead_lnum;
+	int lhead_offs;
+	int ltail_lnum;
+	struct mutex log_mutex;
+	int min_log_bytes;
+	long long cmt_bud_bytes;
+
+	struct rb_root buds;
+	long long bud_bytes;
+	spinlock_t buds_lock;
+	int jhead_cnt;
+	struct ubifs_jhead *jheads;
+	long long max_bud_bytes;
+	long long bg_bud_bytes;
+	struct list_head old_buds;
+	int max_bud_cnt;
+
+	struct rw_semaphore commit_sem;
+	int cmt_state;
+	spinlock_t cs_lock;
+	wait_queue_head_t cmt_wq;
+
+	unsigned int big_lpt:1;
+	unsigned int no_chk_data_crc:1;
+	unsigned int bulk_read:1;
+	unsigned int default_compr:2;
+
+	struct mutex tnc_mutex;
+	struct ubifs_zbranch zroot;
+	struct ubifs_znode *cnext;
+	struct ubifs_znode *enext;
+	int *gap_lebs;
+	void *cbuf;
+	void *ileb_buf;
+	int ileb_len;
+	int ihead_lnum;
+	int ihead_offs;
+	int *ilebs;
+	int ileb_cnt;
+	int ileb_nxt;
+	struct rb_root old_idx;
+	int *bottom_up_buf;
+
+	struct ubifs_mst_node *mst_node;
+	int mst_offs;
+	struct mutex mst_mutex;
+
+	int max_bu_buf_len;
+	struct mutex bu_mutex;
+	struct bu_info bu;
+
+	int log_lebs;
+	long long log_bytes;
+	int log_last;
+	int lpt_lebs;
+	int lpt_first;
+	int lpt_last;
+	int orph_lebs;
+	int orph_first;
+	int orph_last;
+	int main_lebs;
+	int main_first;
+	long long main_bytes;
+
+	uint8_t key_hash_type;
+	uint32_t (*key_hash)(const char *str, int len);
+	int key_fmt;
+	int key_len;
+	int fanout;
+
+	int min_io_size;
+	int min_io_shift;
+	int leb_size;
+	int half_leb_size;
+	int leb_cnt;
+	int max_leb_cnt;
+	int old_leb_cnt;
+	int ro_media;
+
+	long long budg_idx_growth;
+	long long budg_data_growth;
+	long long budg_dd_growth;
+	long long budg_uncommitted_idx;
+	spinlock_t space_lock;
+	int min_idx_lebs;
+	unsigned long long old_idx_sz;
+	unsigned long long calc_idx_sz;
+	struct ubifs_lp_stats lst;
+	unsigned int nospace:1;
+	unsigned int nospace_rp:1;
+
+	int page_budget;
+	int inode_budget;
+	int dent_budget;
+
+	int ref_node_alsz;
+	int mst_node_alsz;
+	int min_idx_node_sz;
+	int max_idx_node_sz;
+	long long max_inode_sz;
+	int max_znode_sz;
+
+	int leb_overhead;
+	int dead_wm;
+	int dark_wm;
+	int block_cnt;
+
+	struct ubifs_node_range ranges[UBIFS_NODE_TYPES_CNT];
+	struct ubi_volume_desc *ubi;
+	struct ubi_device_info di;
+	struct ubi_volume_info vi;
+
+	struct rb_root orph_tree;
+	struct list_head orph_list;
+	struct list_head orph_new;
+	struct ubifs_orphan *orph_cnext;
+	struct ubifs_orphan *orph_dnext;
+	spinlock_t orphan_lock;
+	void *orph_buf;
+	int new_orphans;
+	int cmt_orphans;
+	int tot_orphans;
+	int max_orphans;
+	int ohead_lnum;
+	int ohead_offs;
+	int no_orphs;
+
+	struct task_struct *bgt;
+	char bgt_name[sizeof(BGT_NAME_PATTERN) + 9];
+	int need_bgt;
+	int need_wbuf_sync;
+
+	int gc_lnum;
+	void *sbuf;
+	struct list_head idx_gc;
+	int idx_gc_cnt;
+	int gc_seq;
+	int gced_lnum;
+
+	struct list_head infos_list;
+	struct mutex umount_mutex;
+	unsigned int shrinker_run_no;
+
+	int space_bits;
+	int lpt_lnum_bits;
+	int lpt_offs_bits;
+	int lpt_spc_bits;
+	int pcnt_bits;
+	int lnum_bits;
+	int nnode_sz;
+	int pnode_sz;
+	int ltab_sz;
+	int lsave_sz;
+	int pnode_cnt;
+	int nnode_cnt;
+	int lpt_hght;
+	int pnodes_have;
+
+	struct mutex lp_mutex;
+	int lpt_lnum;
+	int lpt_offs;
+	int nhead_lnum;
+	int nhead_offs;
+	int lpt_drty_flgs;
+	int dirty_nn_cnt;
+	int dirty_pn_cnt;
+	int check_lpt_free;
+	long long lpt_sz;
+	void *lpt_nod_buf;
+	void *lpt_buf;
+	struct ubifs_nnode *nroot;
+	struct ubifs_cnode *lpt_cnext;
+	struct ubifs_lpt_heap lpt_heap[LPROPS_HEAP_CNT];
+	struct ubifs_lpt_heap dirty_idx;
+	struct list_head uncat_list;
+	struct list_head empty_list;
+	struct list_head freeable_list;
+	struct list_head frdi_idx_list;
+	int freeable_cnt;
+
+	int ltab_lnum;
+	int ltab_offs;
+	struct ubifs_lpt_lprops *ltab;
+	struct ubifs_lpt_lprops *ltab_cmt;
+	int lsave_cnt;
+	int lsave_lnum;
+	int lsave_offs;
+	int *lsave;
+	int lscan_lnum;
+
+	long long rp_size;
+	long long report_rp_size;
+	uid_t rp_uid;
+	gid_t rp_gid;
+
+	/* The below fields are used only during mounting and re-mounting */
+	int empty;
+	struct rb_root replay_tree;
+	struct list_head replay_list;
+	struct list_head replay_buds;
+	unsigned long long cs_sqnum;
+	unsigned long long replay_sqnum;
+	int need_recovery;
+	int replaying;
+	struct list_head unclean_leb_list;
+	struct ubifs_mst_node *rcvrd_mst_node;
+	struct rb_root size_tree;
+	int remounting_rw;
+	int always_chk_crc;
+	struct ubifs_mount_opts mount_opts;
+
+#ifdef CONFIG_UBIFS_FS_DEBUG
+	struct ubifs_debug_info *dbg;
+#endif
+};
+
+extern spinlock_t ubifs_infos_lock;
+extern struct kmem_cache *ubifs_inode_slab;
+extern const struct super_operations ubifs_super_operations;
+extern const struct address_space_operations ubifs_file_address_operations;
+extern const struct file_operations ubifs_file_operations;
+extern const struct inode_operations ubifs_file_inode_operations;
+extern const struct file_operations ubifs_dir_operations;
+extern const struct inode_operations ubifs_dir_inode_operations;
+extern const struct inode_operations ubifs_symlink_inode_operations;
+extern struct backing_dev_info ubifs_backing_dev_info;
+extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+
+/* io.c */
+void ubifs_ro_mode(struct ubifs_info *c, int err);
+int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+			   int dtype);
+int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+		    int lnum, int offs);
+int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+			 int lnum, int offs);
+int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
+		     int offs, int dtype);
+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+		     int offs, int quiet, int must_chk_crc);
+void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
+void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
+int ubifs_io_init(struct ubifs_info *c);
+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad);
+int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf);
+int ubifs_bg_wbufs_sync(struct ubifs_info *c);
+void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum);
+int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode);
+
+/* scan.c */
+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+				  int offs, void *sbuf);
+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb);
+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
+		      int offs, int quiet);
+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+					int offs, void *sbuf);
+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		    int lnum, int offs);
+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+		   void *buf, int offs);
+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+			      void *buf);
+
+/* log.c */
+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud);
+void ubifs_create_buds_lists(struct ubifs_info *c);
+int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs);
+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum);
+struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum);
+int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum);
+int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum);
+int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum);
+int ubifs_consolidate_log(struct ubifs_info *c);
+
+/* journal.c */
+int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
+		     const struct qstr *nm, const struct inode *inode,
+		     int deletion, int xent);
+int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+			 const union ubifs_key *key, const void *buf, int len);
+int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
+int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
+int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
+		     const struct dentry *old_dentry,
+		     const struct inode *new_dir,
+		     const struct dentry *new_dentry, int sync);
+int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+		       loff_t old_size, loff_t new_size);
+int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
+			   const struct inode *inode, const struct qstr *nm);
+int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
+			   const struct inode *inode2);
+
+/* budget.c */
+int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req);
+void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req);
+void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
+				      struct ubifs_inode *ui);
+int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode,
+			  struct ubifs_budget_req *req);
+void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
+				struct ubifs_budget_req *req);
+void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
+			 struct ubifs_budget_req *req);
+long long ubifs_get_free_space(struct ubifs_info *c);
+long long ubifs_get_free_space_nolock(struct ubifs_info *c);
+int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
+void ubifs_convert_page_budget(struct ubifs_info *c);
+long long ubifs_reported_space(const struct ubifs_info *c, long long free);
+long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs);
+
+/* find.c */
+int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free,
+			  int squeeze);
+int ubifs_find_free_leb_for_idx(struct ubifs_info *c);
+int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+			 int min_space, int pick_free);
+int ubifs_find_dirty_idx_leb(struct ubifs_info *c);
+int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
+
+/* tnc.c */
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+			struct ubifs_znode **zn, int *n);
+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+			void *node, const struct qstr *nm);
+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
+		     void *node, int *lnum, int *offs);
+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+		  int offs, int len);
+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+		      int old_lnum, int old_offs, int lnum, int offs, int len);
+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+		     int lnum, int offs, int len, const struct qstr *nm);
+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+			const struct qstr *nm);
+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+			   union ubifs_key *to_key);
+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+					   union ubifs_key *key,
+					   const struct qstr *nm);
+void ubifs_tnc_close(struct ubifs_info *c);
+int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
+		       int lnum, int offs, int is_idx);
+int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
+			 int lnum, int offs);
+/* Shared by tnc.c for tnc_commit.c */
+void destroy_old_idx(struct ubifs_info *c);
+int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
+		       int lnum, int offs);
+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode);
+int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu);
+int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu);
+
+/* tnc_misc.c */
+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+					      struct ubifs_znode *znode);
+int ubifs_search_zbranch(const struct ubifs_info *c,
+			 const struct ubifs_znode *znode,
+			 const union ubifs_key *key, int *n);
+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode);
+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode);
+long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr);
+struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
+				     struct ubifs_zbranch *zbr,
+				     struct ubifs_znode *parent, int iip);
+int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+			void *node);
+
+/* tnc_commit.c */
+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
+int ubifs_tnc_end_commit(struct ubifs_info *c);
+
+/* shrinker.c */
+int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask);
+
+/* commit.c */
+int ubifs_bg_thread(void *info);
+void ubifs_commit_required(struct ubifs_info *c);
+void ubifs_request_bg_commit(struct ubifs_info *c);
+int ubifs_run_commit(struct ubifs_info *c);
+void ubifs_recovery_commit(struct ubifs_info *c);
+int ubifs_gc_should_commit(struct ubifs_info *c);
+void ubifs_wait_for_commit(struct ubifs_info *c);
+
+/* master.c */
+int ubifs_read_master(struct ubifs_info *c);
+int ubifs_write_master(struct ubifs_info *c);
+
+/* sb.c */
+int ubifs_read_superblock(struct ubifs_info *c);
+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
+int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
+
+/* replay.c */
+int ubifs_validate_entry(struct ubifs_info *c,
+			 const struct ubifs_dent_node *dent);
+int ubifs_replay_journal(struct ubifs_info *c);
+
+/* gc.c */
+int ubifs_garbage_collect(struct ubifs_info *c, int anyway);
+int ubifs_gc_start_commit(struct ubifs_info *c);
+int ubifs_gc_end_commit(struct ubifs_info *c);
+void ubifs_destroy_idx_gc(struct ubifs_info *c);
+int ubifs_get_idx_gc_leb(struct ubifs_info *c);
+int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp);
+
+/* orphan.c */
+int ubifs_add_orphan(struct ubifs_info *c, ino_t inum);
+void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum);
+int ubifs_orphan_start_commit(struct ubifs_info *c);
+int ubifs_orphan_end_commit(struct ubifs_info *c);
+int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only);
+int ubifs_clear_orphans(struct ubifs_info *c);
+
+/* lpt.c */
+int ubifs_calc_lpt_geom(struct ubifs_info *c);
+int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+			  int *lpt_lebs, int *big_lpt);
+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr);
+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum);
+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum);
+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
+			  ubifs_lpt_scan_callback scan_cb, void *data);
+
+/* Shared by lpt.c for lpt_commit.c */
+void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave);
+void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
+		     struct ubifs_lpt_lprops *ltab);
+void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
+		      struct ubifs_pnode *pnode);
+void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
+		      struct ubifs_nnode *nnode);
+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
+				    struct ubifs_nnode *parent, int iip);
+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
+				    struct ubifs_nnode *parent, int iip);
+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
+struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
+/* Needed only in debugging code in lpt_commit.c */
+int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
+		       struct ubifs_nnode *nnode);
+
+/* lpt_commit.c */
+int ubifs_lpt_start_commit(struct ubifs_info *c);
+int ubifs_lpt_end_commit(struct ubifs_info *c);
+int ubifs_lpt_post_commit(struct ubifs_info *c);
+void ubifs_lpt_free(struct ubifs_info *c, int wr_only);
+
+/* lprops.c */
+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
+					   const struct ubifs_lprops *lp,
+					   int free, int dirty, int flags,
+					   int idx_gc_cnt);
+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst);
+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
+		      int cat);
+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
+		       struct ubifs_lprops *new_lprops);
+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops);
+int ubifs_categorize_lprops(const struct ubifs_info *c,
+			    const struct ubifs_lprops *lprops);
+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+			int flags_set, int flags_clean, int idx_gc_cnt);
+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
+			int flags_set, int flags_clean);
+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp);
+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c);
+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
+
+/* file.c */
+int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync);
+int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
+
+/* dir.c */
+struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+			      int mode);
+int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		  struct kstat *stat);
+
+/* xattr.c */
+int ubifs_setxattr(struct dentry *dentry, const char *name,
+		   const void *value, size_t size, int flags);
+ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
+		       size_t size);
+ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int ubifs_removexattr(struct dentry *dentry, const char *name);
+
+/* super.c */
+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+int ubifs_iput(struct inode *inode);
+
+/* recovery.c */
+int ubifs_recover_master_node(struct ubifs_info *c);
+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+					 int offs, void *sbuf, int grouped);
+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+					     int offs, void *sbuf);
+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
+int ubifs_rcvry_gc_commit(struct ubifs_info *c);
+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+			     int deletion, loff_t new_size);
+int ubifs_recover_size(struct ubifs_info *c);
+void ubifs_destroy_size_tree(struct ubifs_info *c);
+
+/* ioctl.c */
+long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+void ubifs_set_inode_flags(struct inode *inode);
+#ifdef CONFIG_COMPAT
+long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
+/* compressor.c */
+int __init ubifs_compressors_init(void);
+void __exit ubifs_compressors_exit(void);
+void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
+		    int *compr_type);
+int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
+		     int compr_type);
+
+#include "debug.h"
+#include "misc.h"
+#include "key.h"
+
+/* todo: Move these to a common U-Boot header */
+int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
+			  unsigned char *out, size_t *out_len);
+int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp);
+
+#endif /* !__UBIFS_H__ */
diff --git a/include/asm-i386/ic/ali512x.h b/include/ali512x.h
similarity index 100%
rename from include/asm-i386/ic/ali512x.h
rename to include/ali512x.h
diff --git a/include/asm-arm/arch-mx31/mx31-regs.h b/include/asm-arm/arch-mx31/mx31-regs.h
index 3cdaa02..a8a05c8 100644
--- a/include/asm-arm/arch-mx31/mx31-regs.h
+++ b/include/asm-arm/arch-mx31/mx31-regs.h
@@ -134,7 +134,14 @@
 #define MUX_CTL_CSPI2_SS0	0x85
 #define MUX_CTL_CSPI2_SS1	0x86
 #define MUX_CTL_CSPI2_SS2	0x87
+#define MUX_CTL_CSPI1_SS2	0x88
+#define MUX_CTL_CSPI1_SCLK	0x89
+#define MUX_CTL_CSPI1_SPI_RDY	0x8a
 #define MUX_CTL_CSPI2_MOSI	0x8b
+#define MUX_CTL_CSPI1_MOSI	0x8c
+#define MUX_CTL_CSPI1_MISO	0x8d
+#define MUX_CTL_CSPI1_SS0	0x8e
+#define MUX_CTL_CSPI1_SS1	0x8f
 
 /*
  * Helper macros for the MUX_[contact name]__[pin function] macros
@@ -160,6 +167,15 @@
 	IOMUX_MODE(MUX_CTL_CSPI2_SPI_RDY, MUX_CTL_FUNC)
 #define MUX_CSPI2_SCLK__CSPI2_CLK IOMUX_MODE(MUX_CTL_CSPI2_SCLK, MUX_CTL_FUNC)
 
+#define MUX_CSPI1_SS0__CSPI1_SS0_B IOMUX_MODE(MUX_CTL_CSPI1_SS0, MUX_CTL_FUNC)
+#define MUX_CSPI1_SS1__CSPI1_SS1_B IOMUX_MODE(MUX_CTL_CSPI1_SS1, MUX_CTL_FUNC)
+#define MUX_CSPI1_SS2__CSPI1_SS2_B IOMUX_MODE(MUX_CTL_CSPI1_SS2, MUX_CTL_FUNC)
+#define MUX_CSPI1_MOSI__CSPI1_MOSI IOMUX_MODE(MUX_CTL_CSPI1_MOSI, MUX_CTL_FUNC)
+#define MUX_CSPI1_MISO__CSPI1_MISO IOMUX_MODE(MUX_CTL_CSPI1_MISO, MUX_CTL_FUNC)
+#define MUX_CSPI1_SPI_RDY__CSPI1_DATAREADY_B \
+	IOMUX_MODE(MUX_CTL_CSPI1_SPI_RDY, MUX_CTL_FUNC)
+#define MUX_CSPI1_SCLK__CSPI1_CLK IOMUX_MODE(MUX_CTL_CSPI1_SCLK, MUX_CTL_FUNC)
+
 #define MUX_CSPI2_MOSI__I2C2_SCL IOMUX_MODE(MUX_CTL_CSPI2_MOSI, MUX_CTL_ALT1)
 #define MUX_CSPI2_MISO__I2C2_SDA IOMUX_MODE(MUX_CTL_CSPI2_MISO, MUX_CTL_ALT1)
 
diff --git a/include/asm-arm/arch-mx31/mx31.h b/include/asm-arm/arch-mx31/mx31.h
index 0552c27..1d475dde 100644
--- a/include/asm-arm/arch-mx31/mx31.h
+++ b/include/asm-arm/arch-mx31/mx31.h
@@ -27,4 +27,24 @@
 extern u32 mx31_get_ipg_clk(void);
 extern void mx31_gpio_mux(unsigned long mode);
 
+enum mx31_gpio_direction {
+	MX31_GPIO_DIRECTION_IN,
+	MX31_GPIO_DIRECTION_OUT,
+};
+
+#ifdef CONFIG_MX31_GPIO
+extern int mx31_gpio_direction(unsigned int gpio,
+			       enum mx31_gpio_direction direction);
+extern void mx31_gpio_set(unsigned int gpio, unsigned int value);
+#else
+static inline int mx31_gpio_direction(unsigned int gpio,
+				      enum mx31_gpio_direction direction)
+{
+	return 1;
+}
+static inline void mx31_gpio_set(unsigned int gpio, unsigned int value)
+{
+}
+#endif
+
 #endif /* __ASM_ARCH_MX31_H */
diff --git a/include/asm-arm/arch-omap3/cpu.h b/include/asm-arm/arch-omap3/cpu.h
index 5b344f8..c544e0c 100644
--- a/include/asm-arm/arch-omap3/cpu.h
+++ b/include/asm-arm/arch-omap3/cpu.h
@@ -60,6 +60,19 @@
 #define OMAP3525		0x4c00
 #define OMAP3530		0x0c00
 
+#ifndef __ASSEMBLY__
+typedef struct ctrl_id {
+	unsigned char res1[0x4];
+	unsigned int idcode;		/* 0x04 */
+	unsigned int prod_id;		/* 0x08 */
+	unsigned char res2[0x0C];
+	unsigned int die_id_0;		/* 0x18 */
+	unsigned int die_id_1;		/* 0x1C */
+	unsigned int die_id_2;		/* 0x20 */
+	unsigned int die_id_3;		/* 0x24 */
+} ctrl_id_t;
+#endif /* __ASSEMBLY__ */
+
 /* device type */
 #define DEVICE_MASK		(0x7 << 8)
 #define SYSBOOT_MASK		0x1F
diff --git a/include/asm-arm/arch-omap3/omap3.h b/include/asm-arm/arch-omap3/omap3.h
index 02e36d7..8c9656f 100644
--- a/include/asm-arm/arch-omap3/omap3.h
+++ b/include/asm-arm/arch-omap3/omap3.h
@@ -43,6 +43,7 @@
  */
 #define OMAP34XX_CORE_L4_IO_BASE	0x48000000
 #define OMAP34XX_WAKEUP_L4_IO_BASE	0x48300000
+#define OMAP34XX_ID_L4_IO_BASE		0x4830A200
 #define OMAP34XX_L4_PER			0x49000000
 #define OMAP34XX_L4_IO_BASE		OMAP34XX_CORE_L4_IO_BASE
 
diff --git a/include/asm-arm/arch-omap3/sys_proto.h b/include/asm-arm/arch-omap3/sys_proto.h
index ab3e168..8b554bb 100644
--- a/include/asm-arm/arch-omap3/sys_proto.h
+++ b/include/asm-arm/arch-omap3/sys_proto.h
@@ -66,5 +66,6 @@
 void make_cs1_contiguous(void);
 void omap_nand_switch_ecc(int);
 void power_init_r(void);
+void dieid_num_r(void);
 
 #endif
diff --git a/include/asm-arm/u-boot.h b/include/asm-arm/u-boot.h
index b11d555..cfd5a9b 100644
--- a/include/asm-arm/u-boot.h
+++ b/include/asm-arm/u-boot.h
@@ -39,7 +39,6 @@
 typedef struct bd_info {
     int			bi_baudrate;	/* serial console baudrate */
     unsigned long	bi_ip_addr;	/* IP Address */
-    unsigned char	bi_enetaddr[6]; /* Ethernet adress */
     struct environment_s	       *bi_env;
     ulong	        bi_arch_number;	/* unique id for this board */
     ulong	        bi_boot_params;	/* where this board expects params */
@@ -48,10 +47,6 @@
 	ulong start;
 	ulong size;
     }			bi_dram[CONFIG_NR_DRAM_BANKS];
-#ifdef CONFIG_HAS_ETH1
-    /* second onboard ethernet port */
-    unsigned char   bi_enet1addr[6];
-#endif
 } bd_t;
 
 #define bi_env_data bi_env->data
diff --git a/include/asm-avr32/u-boot.h b/include/asm-avr32/u-boot.h
index 85ef008..7e4001f 100644
--- a/include/asm-avr32/u-boot.h
+++ b/include/asm-avr32/u-boot.h
@@ -25,7 +25,6 @@
 typedef struct bd_info {
 	unsigned long		bi_baudrate;
 	unsigned long		bi_ip_addr;
-	unsigned char		bi_enetaddr[6];
 	unsigned char		bi_phy_id[4];
 	struct environment_s	*bi_env;
 	unsigned long		bi_board_number;
diff --git a/include/asm-blackfin/u-boot.h b/include/asm-blackfin/u-boot.h
index 9d2903b..a6e6cf0f 100644
--- a/include/asm-blackfin/u-boot.h
+++ b/include/asm-blackfin/u-boot.h
@@ -31,7 +31,6 @@
 typedef struct bd_info {
 	int bi_baudrate;		/* serial console baudrate */
 	unsigned long bi_ip_addr;	/* IP Address */
-	unsigned char bi_enetaddr[6];	/* Ethernet adress */
 	unsigned long bi_boot_params;	/* where this board expects params */
 	unsigned long bi_memstart;	/* start of DRAM memory */
 	phys_size_t bi_memsize;		/* size  of DRAM memory in bytes */
diff --git a/include/asm-i386/interrupt.h b/include/asm-i386/interrupt.h
index 315b400..7f408cb 100644
--- a/include/asm-i386/interrupt.h
+++ b/include/asm-i386/interrupt.h
@@ -1,7 +1,10 @@
 /*
- * (C) Copyright 2008
+ * (C) Copyright 2009
  * Graeme Russ, graeme.russ@gmail.com
  *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,6 +27,47 @@
 #ifndef __ASM_INTERRUPT_H_
 #define __ASM_INTERRUPT_H_ 1
 
-void set_vector(int intnum, void *routine);
+/* cpu/i386/interrupts.c */
+void set_vector(u8 intnum, void *routine);
+
+/* lib_i386/interupts.c */
+void disable_irq(int irq);
+void enable_irq(int irq);
+
+/* Architecture specific functions */
+void mask_irq(int irq);
+void unmask_irq(int irq);
+void specific_eoi(int irq);
+
+extern char exception_stack[];
+
+#define __isr__ void __attribute__ ((regparm(0)))
+
+#define DECLARE_INTERRUPT(x) \
+	asm(".globl irq_"#x"\n" \
+		    "irq_"#x":\n" \
+		    "pusha \n" \
+		    "pushl $"#x"\n" \
+		    "pushl $irq_return\n" \
+		    "jmp   do_irq\n"); \
+	__isr__ irq_##x(void)
+
+#define DECLARE_EXCEPTION(x, f) \
+	asm(".globl exp_"#x"\n" \
+		    "exp_"#x":\n" \
+		    "pusha \n" \
+		    "movl     %esp, %ebx\n" \
+		    "movl     $exception_stack, %eax\n" \
+		    "movl     %eax, %esp \n" \
+		    "pushl    %ebx\n" \
+		    "movl     32(%esp), %ebx\n" \
+		    "xorl     %edx, %edx\n" \
+		    "movw     36(%esp), %dx\n" \
+		    "pushl    %edx\n" \
+		    "pushl    %ebx\n" \
+		    "pushl    $"#x"\n" \
+		    "pushl    $exp_return\n" \
+		    "jmp      "#f"\n"); \
+	__isr__ exp_##x(void)
 
 #endif
diff --git a/include/asm-i386/u-boot-i386.h b/include/asm-i386/u-boot-i386.h
index 12d10a7..3921e01 100644
--- a/include/asm-i386/u-boot-i386.h
+++ b/include/asm-i386/u-boot-i386.h
@@ -43,8 +43,21 @@
 
 /* cpu/.../cpu.c */
 int cpu_init(void);
+
+/* cpu/.../timer.c */
+void timer_isr(void *);
+typedef void (timer_fnc_t) (void);
+int register_timer_isr (timer_fnc_t *isr_func);
+
+/* Architecture specific - can be in cpu/i386/, lib_i386/, or $(BOARD)/ */
 int timer_init(void);
 
+/* cpu/.../interrupts.c */
+int cpu_init_interrupts(void);
+
+/* cpu/.../exceptions.c */
+int cpu_init_exceptions(void);
+
 /* board/.../... */
 int board_init(void);
 int dram_init(void);
diff --git a/include/asm-i386/u-boot.h b/include/asm-i386/u-boot.h
index fc5a2ae..9a1eec0 100644
--- a/include/asm-i386/u-boot.h
+++ b/include/asm-i386/u-boot.h
@@ -46,7 +46,6 @@
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6];	/* Ethernet adress */
 	unsigned short	bi_ethspeed;	/* Ethernet speed in Mbps */
 	unsigned long	bi_intfreq;	/* Internal Freq, in MHz */
 	unsigned long	bi_busfreq;	/* Bus Freq, in MHz */
diff --git a/include/asm-m68k/m5301x.h b/include/asm-m68k/m5301x.h
index 52bbb87..80cefc4 100644
--- a/include/asm-m68k/m5301x.h
+++ b/include/asm-m68k/m5301x.h
@@ -601,4 +601,8 @@
 #define RTC_OCEN_OSCBYP			(0x00000010)
 #define RTC_OCEN_CLKEN			(0x00000008)
 
+/* SDRAM */
+#define SDRAMC_SDCR_CKE			(0x40000000)
+#define SDRAMC_SDCR_REF			(0x10000000)
+
 #endif				/* m5301x_h */
diff --git a/include/asm-m68k/u-boot.h b/include/asm-m68k/u-boot.h
index 5a0d5fe..a0f2983 100644
--- a/include/asm-m68k/u-boot.h
+++ b/include/asm-m68k/u-boot.h
@@ -48,7 +48,6 @@
 	unsigned long bi_bootflags;	/* boot / reboot flag (for LynxOS) */
 	unsigned long bi_boot_params;	/* where this board expects params */
 	unsigned long bi_ip_addr;	/* IP Address */
-	unsigned char bi_enetaddr[6];	/* Ethernet adress */
 	unsigned short bi_ethspeed;	/* Ethernet speed in Mbps */
 	unsigned long bi_intfreq;	/* Internal Freq, in MHz */
 	unsigned long bi_busfreq;	/* Bus Freq, in MHz */
@@ -61,18 +60,6 @@
 	unsigned long bi_flbfreq;	/* Flexbus Freq in MHz */
 #endif
 	unsigned long bi_baudrate;	/* Console Baudrate */
-
-#ifdef CONFIG_HAS_ETH1
-	/* second onboard ethernet port */
-	unsigned char bi_enet1addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH2
-	/* third onboard ethernet port */
-	unsigned char bi_enet2addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH3
-	unsigned char bi_enet3addr[6];
-#endif
 } bd_t;
 
 #endif				/* __ASSEMBLY__ */
diff --git a/include/asm-microblaze/u-boot.h b/include/asm-microblaze/u-boot.h
index 9db491e..543a6b1 100644
--- a/include/asm-microblaze/u-boot.h
+++ b/include/asm-microblaze/u-boot.h
@@ -41,7 +41,6 @@
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6]; /* Ethernet adress */
 	unsigned long	bi_baudrate;	/* Console Baudrate */
 } bd_t;
 
diff --git a/include/asm-mips/u-boot.h b/include/asm-mips/u-boot.h
index 9ecb9ac..d9c14ca 100644
--- a/include/asm-mips/u-boot.h
+++ b/include/asm-mips/u-boot.h
@@ -34,7 +34,6 @@
 typedef struct bd_info {
 	int		bi_baudrate;	/* serial console baudrate */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6];	/* Ethernet adress */
 	unsigned long	bi_arch_number;	/* unique id for this board */
 	unsigned long	bi_boot_params;	/* where this board expects params */
 	unsigned long	bi_memstart;	/* start of DRAM memory */
diff --git a/include/asm-nios/u-boot.h b/include/asm-nios/u-boot.h
index 3436185..bdb6cf2 100644
--- a/include/asm-nios/u-boot.h
+++ b/include/asm-nios/u-boot.h
@@ -41,7 +41,6 @@
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6]; /* Ethernet adress */
 	unsigned long	bi_baudrate;	/* Console Baudrate */
 } bd_t;
 
diff --git a/include/asm-nios2/u-boot.h b/include/asm-nios2/u-boot.h
index de8c405..ec844d0 100644
--- a/include/asm-nios2/u-boot.h
+++ b/include/asm-nios2/u-boot.h
@@ -40,7 +40,6 @@
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6]; /* Ethernet adress */
 	unsigned long	bi_baudrate;	/* Console Baudrate */
 } bd_t;
 
diff --git a/include/asm-ppc/config.h b/include/asm-ppc/config.h
index 275a7c8..0900f65 100644
--- a/include/asm-ppc/config.h
+++ b/include/asm-ppc/config.h
@@ -22,7 +22,7 @@
 #define _ASM_CONFIG_H_
 
 #ifndef CONFIG_MAX_MEM_MAPPED
-#if defined(CONFIG_4xx) || defined(CONFIG_E500)
+#if defined(CONFIG_4xx) || defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
 #define CONFIG_MAX_MEM_MAPPED	((phys_size_t)2 << 30)
 #else
 #define CONFIG_MAX_MEM_MAPPED	(256 << 20)
diff --git a/include/asm-ppc/immap_85xx.h b/include/asm-ppc/immap_85xx.h
index 7b97fe0..094fb9c 100644
--- a/include/asm-ppc/immap_85xx.h
+++ b/include/asm-ppc/immap_85xx.h
@@ -1667,7 +1667,7 @@
 	uint	lbiuiplldcr0;	/* 0xe0f1c -- LBIU PLL Debug Reg 0 */
 	uint	lbiuiplldcr1;	/* 0xe0f20 -- LBIU PLL Debug Reg 1 */
 	uint	ddrioovcr;	/* 0xe0f24 - DDR IO Override Control */
-	uint	res14;		/* 0xe0f28 */
+	uint	tsec12ioovcr;	/* 0xe0f28 - eTSEC 1/2 IO override control */
 	uint	tsec34ioovcr;	/* 0xe0f2c - eTSEC 3/4 IO override control */
 	char	res15[61648];	/* 0xe0f30 to 0xefffff */
 } ccsr_gur_t;
diff --git a/include/asm-ppc/u-boot.h b/include/asm-ppc/u-boot.h
index 7451905..e6c56e9 100644
--- a/include/asm-ppc/u-boot.h
+++ b/include/asm-ppc/u-boot.h
@@ -64,7 +64,7 @@
 #endif
 	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
 	unsigned long	bi_ip_addr;	/* IP Address */
-	unsigned char	bi_enetaddr[6];	/* Ethernet adress */
+	unsigned char	bi_enetaddr[6];	/* OLD: see README.enetaddr */
 	unsigned short	bi_ethspeed;	/* Ethernet speed in Mbps */
 	unsigned long	bi_intfreq;	/* Internal Freq, in MHz */
 	unsigned long	bi_busfreq;	/* Bus Freq, in MHz */
@@ -101,21 +101,19 @@
 #endif
 
 #ifdef CONFIG_HAS_ETH1
-	/* second onboard ethernet port */
-	unsigned char   bi_enet1addr[6];
+	unsigned char   bi_enet1addr[6];	/* OLD: see README.enetaddr */
 #endif
 #ifdef CONFIG_HAS_ETH2
-	/* third onboard ethernet port */
-	unsigned char	bi_enet2addr[6];
+	unsigned char	bi_enet2addr[6];	/* OLD: see README.enetaddr */
 #endif
 #ifdef CONFIG_HAS_ETH3
-	unsigned char   bi_enet3addr[6];
+	unsigned char   bi_enet3addr[6];	/* OLD: see README.enetaddr */
 #endif
 #ifdef CONFIG_HAS_ETH4
-	unsigned char   bi_enet4addr[6];
+	unsigned char   bi_enet4addr[6];	/* OLD: see README.enetaddr */
 #endif
 #ifdef CONFIG_HAS_ETH5
-	unsigned char   bi_enet5addr[6];
+	unsigned char   bi_enet5addr[6];	/* OLD: see README.enetaddr */
 #endif
 
 #if defined(CONFIG_405GP) || defined(CONFIG_405EP) || \
diff --git a/include/asm-ppc/unaligned.h b/include/asm-ppc/unaligned.h
new file mode 100644
index 0000000..5f1b1e3
--- /dev/null
+++ b/include/asm-ppc/unaligned.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_POWERPC_UNALIGNED_H
+#define _ASM_POWERPC_UNALIGNED_H
+
+#ifdef __KERNEL__
+
+/*
+ * The PowerPC can do unaligned accesses itself in big endian mode.
+ */
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned	__get_unaligned_be
+#define put_unaligned	__put_unaligned_be
+
+#endif	/* __KERNEL__ */
+#endif	/* _ASM_POWERPC_UNALIGNED_H */
diff --git a/include/asm-sh/cpu_sh4.h b/include/asm-sh/cpu_sh4.h
index d2dbfcd..fdcebd6 100644
--- a/include/asm-sh/cpu_sh4.h
+++ b/include/asm-sh/cpu_sh4.h
@@ -54,4 +54,29 @@
 # error "Unknown SH4 variant"
 #endif
 
+#if defined(CONFIG_SH_32BIT)
+#define PMB_ADDR_ARRAY		0xf6100000
+#define PMB_ADDR_ENTRY		8
+#define PMB_VPN			24
+
+#define PMB_DATA_ARRAY		0xf7100000
+#define PMB_DATA_ENTRY		8
+#define PMB_PPN			24
+#define PMB_UB			9		/* Buffered write */
+#define PMB_V			8		/* Valid */
+#define PMB_SZ1			7		/* Page size (upper bit) */
+#define PMB_SZ0			4		/* Page size (lower bit) */
+#define PMB_C			3		/* Cacheability */
+#define PMB_WT			0		/* Write-through */
+
+#define PMB_ADDR_BASE(entry)	(PMB_ADDR_ARRAY + (entry << PMB_ADDR_ENTRY))
+#define PMB_DATA_BASE(entry)	(PMB_DATA_ARRAY + (entry << PMB_DATA_ENTRY))
+#define mk_pmb_addr_val(vpn)	((vpn << PMB_VPN))
+#define mk_pmb_data_val(ppn, ub, v, sz1, sz0, c, wt)	\
+				((ppn << PMB_PPN) | (ub << PMB_UB) | \
+				 (v << PMB_V) | (sz1 << PMB_SZ1) | \
+				 (sz0 << PMB_SZ0) | (c << PMB_C) | \
+				 (wt << PMB_WT))
+#endif
+
 #endif	/* _ASM_CPU_SH4_H_ */
diff --git a/include/asm-sh/u-boot.h b/include/asm-sh/u-boot.h
index e89c193..27d43b9 100644
--- a/include/asm-sh/u-boot.h
+++ b/include/asm-sh/u-boot.h
@@ -34,7 +34,6 @@
 	unsigned long   bi_sramstart;   /* start of SRAM memory */
 	unsigned long   bi_sramsize;    /* size  of SRAM memory */
 	unsigned long   bi_ip_addr;     /* IP Address */
-	unsigned char   bi_enetaddr[6]; /* Ethernet adress */
 	unsigned long   bi_baudrate;    /* Console Baudrate */
 	unsigned long	bi_boot_params; /* where this board expects params */
 } bd_t;
diff --git a/include/asm-sparc/u-boot.h b/include/asm-sparc/u-boot.h
index c42e93c..209873f 100644
--- a/include/asm-sparc/u-boot.h
+++ b/include/asm-sparc/u-boot.h
@@ -52,22 +52,10 @@
 	unsigned long bi_sramsize;	/* size  of SRAM memory */
 	unsigned long bi_bootflags;	/* boot / reboot flag (for LynxOS) */
 	unsigned long bi_ip_addr;	/* IP Address */
-	unsigned char bi_enetaddr[6];	/* Ethernet adress */
 	unsigned short bi_ethspeed;	/* Ethernet speed in Mbps */
 	unsigned long bi_intfreq;	/* Internal Freq, in MHz */
 	unsigned long bi_busfreq;	/* Bus Freq, in MHz */
 	unsigned long bi_baudrate;	/* Console Baudrate */
-#ifdef CONFIG_HAS_ETH1
-	/* second onboard ethernet port */
-	unsigned char bi_enet1addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH2
-	/* third onboard ethernet port */
-	unsigned char bi_enet2addr[6];
-#endif
-#ifdef CONFIG_HAS_ETH3
-	unsigned char bi_enet3addr[6];
-#endif
 } bd_t;
 
 #endif				/* __ASSEMBLY__ */
diff --git a/include/common.h b/include/common.h
index afee188..952ddff 100644
--- a/include/common.h
+++ b/include/common.h
@@ -269,6 +269,7 @@
 #ifdef CONFIG_AUTO_COMPLETE
 int env_complete(char *var, int maxv, char *cmdv[], int maxsz, char *buf);
 #endif
+int get_env_id (void);
 
 void	pci_init      (void);
 void	pci_init_board(void);
@@ -351,13 +352,6 @@
 void	board_ether_init (void);
 #endif
 
-#if defined(CONFIG_RPXCLASSIC)	|| defined(CONFIG_MBX) || \
-    defined(CONFIG_IAD210)	|| defined(CONFIG_XPEDITE1K) || \
-    defined(CONFIG_METROBOX)    || defined(CONFIG_KAREF) || \
-    defined(CONFIG_V38B)
-void	board_get_enetaddr (uchar *addr);
-#endif
-
 #ifdef CONFIG_HERMES
 /* $(BOARD)/hermes.c */
 void hermes_start_lxt980 (int speed);
@@ -370,8 +364,6 @@
 void  perform_soft_reset(void);
 #endif
 
-void	load_sernum_ethaddr (void);
-
 /* $(BOARD)/$(BOARD).c */
 int board_early_init_f (void);
 int board_late_init (void);
diff --git a/include/commproc.h b/include/commproc.h
index 12decfe..9d28abc 100644
--- a/include/commproc.h
+++ b/include/commproc.h
@@ -1122,11 +1122,11 @@
 #define SICR_ENET_CLKRT	((uint)0x0000003d)
 #endif	/* CONFIG_MBX */
 
-/***  MGSUVD  *********************************************************/
+/***  KM8XX  *********************************************************/
 
-/* The MGSUVD Service Module uses SCC3 for Ethernet */
+/* The KM8XX Service Module uses SCC3 for Ethernet */
 
-#ifdef CONFIG_MGSUVD
+#ifdef CONFIG_KM8XX
 #define PROFF_ENET	PROFF_SCC3		/* Ethernet on SCC3 */
 #define CPM_CR_ENET	CPM_CR_CH_SCC3
 #define SCC_ENET	2
@@ -1145,7 +1145,7 @@
  */
 #define SICR_ENET_MASK	((uint)0x00FF0000)
 #define SICR_ENET_CLKRT	((uint)0x00250000)
-#endif	/* CONFIG_MGSUVD */
+#endif	/* CONFIG_KM8XX */
 
 
 /***  MHPC  ********************************************************/
diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
index 205dd1f..db1f55c 100644
--- a/include/config_cmd_all.h
+++ b/include/config_cmd_all.h
@@ -58,6 +58,7 @@
 #define CONFIG_CMD_MII		/* MII support			*/
 #define CONFIG_CMD_MISC		/* Misc functions like sleep etc*/
 #define CONFIG_CMD_MMC		/* MMC support			*/
+#define CONFIG_CMD_MTDPARTS	/* mtd parts support		*/
 #define CONFIG_CMD_NAND		/* NAND support			*/
 #define CONFIG_CMD_NET		/* bootp, tftpboot, rarpboot	*/
 #define CONFIG_CMD_NFS		/* NFS support			*/
diff --git a/include/configs/ADNPESC1.h b/include/configs/ADNPESC1.h
index e61a3e1..0977bee 100644
--- a/include/configs/ADNPESC1.h
+++ b/include/configs/ADNPESC1.h
@@ -673,14 +673,14 @@
  *
  */
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/Alaska8220.h b/include/configs/Alaska8220.h
index 2581fdf..576aa74 100644
--- a/include/configs/Alaska8220.h
+++ b/include/configs/Alaska8220.h
@@ -320,7 +320,7 @@
 
 /* No command line, one static partition */
 /*
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0x00400000
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -328,7 +328,7 @@
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=alaska-0"
 #define MTDPARTS_DEFAULT	"mtdparts=alaska-0:4m(user)"
 */
diff --git a/include/configs/BAB7xx.h b/include/configs/BAB7xx.h
index 1910b34..40a1c40 100644
--- a/include/configs/BAB7xx.h
+++ b/include/configs/BAB7xx.h
@@ -219,7 +219,7 @@
  *
  */
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -229,7 +229,7 @@
  * Note: fake mtd_id used, no linux mtd map file
  */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=bab7xx-0"
 #define MTDPARTS_DEFAULT	"mtdparts=bab7xx-0:-(jffs2)"
 */
diff --git a/include/configs/BC3450.h b/include/configs/BC3450.h
index bced118..9934f29 100644
--- a/include/configs/BC3450.h
+++ b/include/configs/BC3450.h
@@ -346,7 +346,7 @@
 #define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* Flash Write Timeout (in ms)	*/
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM5200-0"
 #define MTDPARTS_DEFAULT	"mtdparts=TQM5200-0:640k(firmware),"	\
 						"1408k(kernel),"	\
diff --git a/include/configs/CATcenter.h b/include/configs/CATcenter.h
index fa9fc23..39f41e6 100644
--- a/include/configs/CATcenter.h
+++ b/include/configs/CATcenter.h
@@ -781,7 +781,7 @@
  *
  */
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nand"
 #define CONFIG_JFFS2_PART_SIZE		0x00200000
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -791,7 +791,7 @@
  * Note: fake mtd_id used, no linux mtd map file
  */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nand0=catcenter"
 #define MTDPARTS_DEFAULT	"mtdparts=catcenter:2m(nand)"
 */
diff --git a/include/configs/CPCI4052.h b/include/configs/CPCI4052.h
index 2677cfb..daa3c19 100644
--- a/include/configs/CPCI4052.h
+++ b/include/configs/CPCI4052.h
@@ -154,6 +154,12 @@
 
 #define CONFIG_VERSION_VARIABLE 1	/* include version env variable */
 
+#define CONFIG_AUTOBOOT_KEYED	1
+#define CONFIG_AUTOBOOT_PROMPT	\
+	"Press SPACE to abort autoboot in %d seconds\n", bootdelay
+#undef CONFIG_AUTOBOOT_DELAY_STR
+#define CONFIG_AUTOBOOT_STOP_STR " "
+
 #define CONFIG_SYS_RX_ETH_BUFFER	16	/* use 16 rx buffer on 405 emac */
 
 /*-----------------------------------------------------------------------
diff --git a/include/configs/CPCI405AB.h b/include/configs/CPCI405AB.h
index aae0d73..41795a7 100644
--- a/include/configs/CPCI405AB.h
+++ b/include/configs/CPCI405AB.h
@@ -151,6 +151,12 @@
 
 #define CONFIG_VERSION_VARIABLE 1	/* include version env variable */
 
+#define CONFIG_AUTOBOOT_KEYED	1
+#define CONFIG_AUTOBOOT_PROMPT	\
+	"Press SPACE to abort autoboot in %d seconds\n", bootdelay
+#undef CONFIG_AUTOBOOT_DELAY_STR
+#define CONFIG_AUTOBOOT_STOP_STR " "
+
 #define CONFIG_SYS_RX_ETH_BUFFER	16	/* use 16 rx buffer on 405 emac */
 
 /*-----------------------------------------------------------------------
diff --git a/include/configs/DASA_SIM.h b/include/configs/DASA_SIM.h
index 61704d0..21230e1 100644
--- a/include/configs/DASA_SIM.h
+++ b/include/configs/DASA_SIM.h
@@ -124,9 +124,9 @@
  * Please note that CONFIG_SYS_SDRAM_BASE _must_ start at 0
  */
 #define CONFIG_SYS_SDRAM_BASE		0x00000000
-#define CONFIG_SYS_FLASH_BASE		0xFFFD0000
+#define CONFIG_SYS_FLASH_BASE		0xFFFC0000
 #define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_FLASH_BASE
-#define CONFIG_SYS_MONITOR_LEN		(192 << 10)	/* Reserve 128 kB for Monitor	*/
+#define CONFIG_SYS_MONITOR_LEN		(256 << 10)	/* Reserve 128 kB for Monitor	*/
 #define CONFIG_SYS_MALLOC_LEN		(128 << 10)	/* Reserve 128 kB for malloc()	*/
 
 /*
diff --git a/include/configs/DB64360.h b/include/configs/DB64360.h
index daed934..160871b 100644
--- a/include/configs/DB64360.h
+++ b/include/configs/DB64360.h
@@ -230,7 +230,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor1"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -242,7 +242,7 @@
  * Note: fake mtd_id's used, no linux mtd map file.
  */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor1=db64360-1"
 #define MTDPARTS_DEFAULT	"mtdparts=db64360-1:-(jffs2)"
 */
diff --git a/include/configs/DB64460.h b/include/configs/DB64460.h
index 604fd45..06fd157 100644
--- a/include/configs/DB64460.h
+++ b/include/configs/DB64460.h
@@ -168,7 +168,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor1"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -180,7 +180,7 @@
  * Note: fake mtd_id's used, no linux mtd map file.
  */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor1=db64460-1"
 #define MTDPARTS_DEFAULT	"mtdparts=db64460-1:-(jffs2)"
 */
diff --git a/include/configs/DK1C20.h b/include/configs/DK1C20.h
index 6fdc566..db9c17d 100644
--- a/include/configs/DK1C20.h
+++ b/include/configs/DK1C20.h
@@ -539,14 +539,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/DK1S10.h b/include/configs/DK1S10.h
index 1d031f1..3bd270c 100644
--- a/include/configs/DK1S10.h
+++ b/include/configs/DK1S10.h
@@ -545,14 +545,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/DU405.h b/include/configs/DU405.h
index 1d20efe..d1edd24 100644
--- a/include/configs/DU405.h
+++ b/include/configs/DU405.h
@@ -32,8 +32,6 @@
  * High Level Configuration Options
  * (easy to change)
  */
-#define CONFIG_IDENT_STRING     " $Name:  $"
-
 #define CONFIG_405GP		1	/* This is a PPC405 CPU		*/
 #define CONFIG_4xx		1	/* ...member of PPC4xx family	*/
 #define CONFIG_DU405		1	/* ...on a DU405 board		*/
@@ -49,8 +47,6 @@
 #undef	CONFIG_BOOTARGS
 #define CONFIG_BOOTCOMMAND	"bootm fff00000"
 
-#define CONFIG_PREBOOT                  /* enable preboot variable      */
-
 #define CONFIG_LOADS_ECHO	1	/* echo on for serial download	*/
 #define CONFIG_SYS_LOADS_BAUD_CHANGE	1	/* allow baudrate change	*/
 
@@ -58,7 +54,9 @@
 #define CONFIG_MII		1	/* MII PHY management		*/
 #define CONFIG_PHY_ADDR		0	/* PHY address			*/
 #define CONFIG_LXT971_NO_SLEEP  1       /* disable sleep mode in LXT971 */
-
+#define CONFIG_RESET_PHY_R      1       /* use reset_phy() to disable phy sleep mode */
+#define CONFIG_NET_MULTI	1
+#undef  CONFIG_HAS_ETH1
 
 /*
  * BOOTP options
@@ -74,14 +72,13 @@
  */
 #include <config_cmd_default.h>
 
-#define CONFIG_CMD_PCI
-#define CONFIG_CMD_IRQ
+#undef CONFIG_CMD_NFS
 #define CONFIG_CMD_IDE
 #define CONFIG_CMD_ELF
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_DATE
 #define CONFIG_CMD_EEPROM
-
+#define CONFIG_CMD_I2C
 
 #define CONFIG_MAC_PARTITION
 #define CONFIG_DOS_PARTITION
@@ -214,6 +211,7 @@
 /*-----------------------------------------------------------------------
  * I2C EEPROM (CAT24WC08) for environment
  */
+#define CONFIG_I2C_CMD_TREE     1
 #define CONFIG_HARD_I2C			/* I2c with hardware support */
 #define CONFIG_SYS_I2C_SPEED		400000	/* I2C speed and slave address */
 #define CONFIG_SYS_I2C_SLAVE		0x7F
diff --git a/include/configs/ELPPC.h b/include/configs/ELPPC.h
index 7939266..d2aa8b9 100644
--- a/include/configs/ELPPC.h
+++ b/include/configs/ELPPC.h
@@ -196,7 +196,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -204,7 +204,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=elppc-0,nor1=elppc-1"
 #define MTDPARTS_DEFAULT	"mtdparts=elppc-0:-(jffs2),elppc-1:-(user)"
 */
diff --git a/include/configs/FLAGADM.h b/include/configs/FLAGADM.h
index d831238..0f4277c 100644
--- a/include/configs/FLAGADM.h
+++ b/include/configs/FLAGADM.h
@@ -173,6 +173,9 @@
 #if defined(CONFIG_CMD_KGDB)
 #define CONFIG_SYS_CACHELINE_SHIFT	4	/* log base 2 of the above value	*/
 #endif
+#define CONFIG_SYS_DELAYED_ICACHE	1	/* enable ICache not before
+						 * running in RAM.
+						 */
 
 /*-----------------------------------------------------------------------
  * SYPCR - System Protection Control				11-9
diff --git a/include/configs/FPS850L.h b/include/configs/FPS850L.h
index 08408e2..f152230 100644
--- a/include/configs/FPS850L.h
+++ b/include/configs/FPS850L.h
@@ -216,7 +216,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/FPS860L.h b/include/configs/FPS860L.h
index e5f3b60..5eaed84 100644
--- a/include/configs/FPS860L.h
+++ b/include/configs/FPS860L.h
@@ -216,7 +216,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/HH405.h b/include/configs/HH405.h
index ed9a235..9233523 100644
--- a/include/configs/HH405.h
+++ b/include/configs/HH405.h
@@ -413,23 +413,6 @@
 
 #define CONFIG_SYS_FPGA_BASE_ADDR 0xF0100100       /* FPGA internal Base Address       */
 
-/* FPGA internal regs */
-#define CONFIG_SYS_FPGA_CTRL           0x000
-
-/* FPGA Control Reg */
-#define CONFIG_SYS_FPGA_CTRL_REV0      0x0001
-#define CONFIG_SYS_FPGA_CTRL_REV1      0x0002
-#define CONFIG_SYS_FPGA_CTRL_VGA0_BL   0x0004
-#define CONFIG_SYS_FPGA_CTRL_VGA0_BL_MODE 0x0008
-#define CONFIG_SYS_FPGA_CTRL_CF_RESET  0x0040
-#define CONFIG_SYS_FPGA_CTRL_PS2_PWR   0x0080
-#define CONFIG_SYS_FPGA_CTRL_CF_PWRN   0x0100      /* low active                    */
-#define CONFIG_SYS_FPGA_CTRL_CF_BUS_EN 0x0200
-#define CONFIG_SYS_FPGA_CTRL_LCD_CLK   0x7000      /* Mask for lcd clock            */
-#define CONFIG_SYS_FPGA_CTRL_OW_ENABLE 0x8000
-
-#define CONFIG_SYS_FPGA_STATUS_CF_DETECT 0x8000
-
 #define LCD_CLK_OFF             0x0000      /* Off                           */
 #define LCD_CLK_02083           0x1000      /* 2.083 MHz                     */
 #define LCD_CLK_03135           0x2000      /* 3.135 MHz                     */
diff --git a/include/configs/IAD210.h b/include/configs/IAD210.h
index ca488c6..ea1e706 100644
--- a/include/configs/IAD210.h
+++ b/include/configs/IAD210.h
@@ -67,6 +67,7 @@
 
 /* using this define saves us updating another source file */
 #define CONFIG_BOARD_EARLY_INIT_F 1
+#define CONFIG_MISC_INIT_R
 
 #undef	CONFIG_BOOTARGS
 /* #define CONFIG_BOOTCOMMAND							\
diff --git a/include/configs/IP860.h b/include/configs/IP860.h
index b9c5713..125aa6c 100644
--- a/include/configs/IP860.h
+++ b/include/configs/IP860.h
@@ -209,6 +209,9 @@
 #if defined(CONFIG_CMD_KGDB)
 #define CONFIG_SYS_CACHELINE_SHIFT	4	/* log base 2 of the above value	*/
 #endif
+#define CONFIG_SYS_DELAYED_ICACHE	1	/* enable ICache not before
+						 * running in RAM.
+						 */
 
 /*-----------------------------------------------------------------------
  * SYPCR - System Protection Control				11-9
diff --git a/include/configs/LANTEC.h b/include/configs/LANTEC.h
index f14d945..6e8a4b8 100644
--- a/include/configs/LANTEC.h
+++ b/include/configs/LANTEC.h
@@ -352,14 +352,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/M52277EVB.h b/include/configs/M52277EVB.h
index 5d5966f..053a914 100644
--- a/include/configs/M52277EVB.h
+++ b/include/configs/M52277EVB.h
@@ -246,6 +246,7 @@
 
 /* Initial Memory map for Linux */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*
  * Configuration for environment
diff --git a/include/configs/M5235EVB.h b/include/configs/M5235EVB.h
index 8c66f87..6b26c0b 100644
--- a/include/configs/M5235EVB.h
+++ b/include/configs/M5235EVB.h
@@ -197,6 +197,7 @@
  */
 /* Initial Memory map for Linux */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*-----------------------------------------------------------------------
  * FLASH organization
diff --git a/include/configs/M5253DEMO.h b/include/configs/M5253DEMO.h
index 378e45a..1fea6c3 100644
--- a/include/configs/M5253DEMO.h
+++ b/include/configs/M5253DEMO.h
@@ -200,6 +200,7 @@
  * the maximum mapped by the Linux kernel during initialization ??
  */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /* FLASH organization */
 #define CONFIG_SYS_FLASH_BASE		(CONFIG_SYS_CS0_BASE)
diff --git a/include/configs/M5253EVBE.h b/include/configs/M5253EVBE.h
index 86de97d..cf8b773 100644
--- a/include/configs/M5253EVBE.h
+++ b/include/configs/M5253EVBE.h
@@ -164,6 +164,7 @@
  * the maximum mapped by the Linux kernel during initialization ??
  */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /* FLASH organization */
 #define CONFIG_SYS_FLASH_BASE		CONFIG_SYS_CS0_BASE
diff --git a/include/configs/M5275EVB.h b/include/configs/M5275EVB.h
index db48d76..210bb2d 100644
--- a/include/configs/M5275EVB.h
+++ b/include/configs/M5275EVB.h
@@ -190,7 +190,8 @@
  * have to be in the first 8 MB of memory, since this is
  * the maximum mapped by the Linux kernel during initialization ??
  */
-#define CONFIG_SYS_BOOTMAPSZ		(8 << 20)	/* Initial mmap for Linux */
+#define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*-----------------------------------------------------------------------
  * FLASH organization
diff --git a/include/configs/M53017EVB.h b/include/configs/M53017EVB.h
index df54c60..07c85c4 100644
--- a/include/configs/M53017EVB.h
+++ b/include/configs/M53017EVB.h
@@ -196,6 +196,7 @@
  * the maximum mapped by the Linux kernel during initialization ??
  */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*-----------------------------------------------------------------------
  * FLASH organization
diff --git a/include/configs/M5329EVB.h b/include/configs/M5329EVB.h
index 1f1586a..a2d17c3 100644
--- a/include/configs/M5329EVB.h
+++ b/include/configs/M5329EVB.h
@@ -196,6 +196,7 @@
  * the maximum mapped by the Linux kernel during initialization ??
  */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*-----------------------------------------------------------------------
  * FLASH organization
diff --git a/include/configs/M5373EVB.h b/include/configs/M5373EVB.h
index 1991687..98d800f 100644
--- a/include/configs/M5373EVB.h
+++ b/include/configs/M5373EVB.h
@@ -196,6 +196,7 @@
  * the maximum mapped by the Linux kernel during initialization ??
  */
 #define CONFIG_SYS_BOOTMAPSZ		(CONFIG_SYS_SDRAM_BASE + (CONFIG_SYS_SDRAM_SIZE << 20))
+#define CONFIG_SYS_BOOTM_LEN		(CONFIG_SYS_SDRAM_SIZE << 20)
 
 /*-----------------------------------------------------------------------
  * FLASH organization
diff --git a/include/configs/MBX860T.h b/include/configs/MBX860T.h
index 4cb3a69..0c28710 100644
--- a/include/configs/MBX860T.h
+++ b/include/configs/MBX860T.h
@@ -50,6 +50,8 @@
 #undef	CONFIG_8xx_TFTP_MODE
 #endif
 
+#define CONFIG_MISC_INIT_R
+
 #define CONFIG_DRAM_SPEED	(CONFIG_8xx_BUSCLOCK)	/* MHz		*/
 #define CONFIG_BOOTCOMMAND	"bootm FE020000"	/* autoboot command */
 #define CONFIG_BOOTARGS		" "
diff --git a/include/configs/MHPC.h b/include/configs/MHPC.h
index 8e7f9cd..19a288c 100644
--- a/include/configs/MHPC.h
+++ b/include/configs/MHPC.h
@@ -200,7 +200,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -208,7 +208,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=mhpc-0"
 #define MTDPARTS_DEFAULT	"mtdparts=mhpc-0:-(jffs2)"
 */
diff --git a/include/configs/MIP405.h b/include/configs/MIP405.h
index c58ce05..a3869c8 100644
--- a/include/configs/MIP405.h
+++ b/include/configs/MIP405.h
@@ -243,7 +243,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -251,7 +251,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=mip405-0"
 #define MTDPARTS_DEFAULT	"mtdparts=mip405-0:-(jffs2)"
 */
diff --git a/include/configs/ML2.h b/include/configs/ML2.h
index 1902397..5fcc173 100644
--- a/include/configs/ML2.h
+++ b/include/configs/ML2.h
@@ -249,7 +249,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00080000
@@ -257,7 +257,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=ml2-0"
 #define MTDPARTS_DEFAULT	"mtdparts=ml2-0:-@512k(jffs2)"
 */
diff --git a/include/configs/MPC8266ADS.h b/include/configs/MPC8266ADS.h
index fe1cc17..4fd86d3 100644
--- a/include/configs/MPC8266ADS.h
+++ b/include/configs/MPC8266ADS.h
@@ -563,14 +563,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h
index 14cbc45..38a7386 100644
--- a/include/configs/MPC8349ITX.h
+++ b/include/configs/MPC8349ITX.h
@@ -78,6 +78,7 @@
 #ifdef CONFIG_MPC8349ITX
 #define CONFIG_COMPACT_FLASH	/* The CF card interface on the back of the board */
 #define CONFIG_VSC7385_ENET	/* VSC7385 ethernet support */
+#define CONFIG_SATA_SIL3114	/* SIL3114 SATA controller */
 #endif
 
 #define CONFIG_PCI
@@ -98,6 +99,7 @@
 #define CONFIG_SYS_I2C_OFFSET		0x3000
 #define CONFIG_SYS_I2C2_OFFSET		0x3100
 #define CONFIG_SYS_SPD_BUS_NUM		1	/* The I2C bus for SPD */
+#define CONFIG_SYS_RTC_BUS_NUM		1	/* The I2C bus for RTC */
 
 #define CONFIG_SYS_I2C_8574_ADDR1	0x20	/* I2C1, PCF8574 */
 #define CONFIG_SYS_I2C_8574_ADDR2	0x21	/* I2C1, PCF8574 */
@@ -141,7 +143,16 @@
 
 #define ATA_RESET_TIME	1	/* If a CF card is not inserted, time out quickly */
 
-#define CONFIG_DOS_PARTITION
+#endif
+
+/*
+ * SATA
+ */
+#ifdef CONFIG_SATA_SIL3114
+
+#define CONFIG_SYS_SATA_MAX_DEVICE      4
+#define CONFIG_LIBATA
+#define CONFIG_LBA48
 
 #endif
 
@@ -158,6 +169,9 @@
 #define CONFIG_SYS_DDR_SDRAM_CLK_CNTL	(DDR_SDRAM_CLK_CNTL_SS_EN | \
 				DDR_SDRAM_CLK_CNTL_CLK_ADJUST_075)
 
+#define CONFIG_VERY_BIG_RAM
+#define CONFIG_MAX_MEM_MAPPED   ((phys_size_t)256 << 20)
+
 #ifdef CONFIG_HARD_I2C
 #define CONFIG_SPD_EEPROM		/* use SPD EEPROM for DDR setup*/
 #endif
@@ -447,11 +461,21 @@
 #define CONFIG_CMD_IRQ
 #define CONFIG_CMD_NET
 #define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
 #define CONFIG_CMD_SDRAM
 
+#if defined(CONFIG_COMPACT_FLASH) || defined(CONFIG_SATA_SIL3114)
+    #define CONFIG_DOS_PARTITION
+    #define CONFIG_CMD_FAT
+#endif
+
 #ifdef CONFIG_COMPACT_FLASH
     #define CONFIG_CMD_IDE
-    #define CONFIG_CMD_FAT
+#endif
+
+#ifdef CONFIG_SATA_SIL3114
+    #define CONFIG_CMD_SATA
+    #define CONFIG_CMD_EXT2
 #endif
 
 #ifdef CONFIG_PCI
diff --git a/include/configs/MPC837XERDB.h b/include/configs/MPC837XERDB.h
index 2e31dd0..8d0c93b 100644
--- a/include/configs/MPC837XERDB.h
+++ b/include/configs/MPC837XERDB.h
@@ -49,6 +49,7 @@
 #else
 #define CONFIG_83XX_CLKIN	66666667 /* in Hz */
 #define CONFIG_83XX_GENERIC_PCI	1
+#define CONFIG_83XX_GENERIC_PCIE	1
 #endif
 
 #ifndef CONFIG_SYS_CLK_FREQ
@@ -375,6 +376,26 @@
 #define CONFIG_SYS_PCI_SLV_MEM_BUS	0x00000000
 #define CONFIG_SYS_PCI_SLV_MEM_SIZE	0x80000000
 
+#define CONFIG_SYS_PCIE1_BASE		0xA0000000
+#define CONFIG_SYS_PCIE1_CFG_BASE	0xA0000000
+#define CONFIG_SYS_PCIE1_CFG_SIZE	0x08000000
+#define CONFIG_SYS_PCIE1_MEM_BASE	0xA8000000
+#define CONFIG_SYS_PCIE1_MEM_PHYS	0xA8000000
+#define CONFIG_SYS_PCIE1_MEM_SIZE	0x10000000
+#define CONFIG_SYS_PCIE1_IO_BASE	0x00000000
+#define CONFIG_SYS_PCIE1_IO_PHYS	0xB8000000
+#define CONFIG_SYS_PCIE1_IO_SIZE	0x00800000
+
+#define CONFIG_SYS_PCIE2_BASE		0xC0000000
+#define CONFIG_SYS_PCIE2_CFG_BASE	0xC0000000
+#define CONFIG_SYS_PCIE2_CFG_SIZE	0x08000000
+#define CONFIG_SYS_PCIE2_MEM_BASE	0xC8000000
+#define CONFIG_SYS_PCIE2_MEM_PHYS	0xC8000000
+#define CONFIG_SYS_PCIE2_MEM_SIZE	0x10000000
+#define CONFIG_SYS_PCIE2_IO_BASE	0x00000000
+#define CONFIG_SYS_PCIE2_IO_PHYS	0xD8000000
+#define CONFIG_SYS_PCIE2_IO_SIZE	0x00800000
+
 #ifdef CONFIG_PCI
 #define CONFIG_NET_MULTI
 #define CONFIG_PCI_PNP		/* do pci plug-and-play */
diff --git a/include/configs/NC650.h b/include/configs/NC650.h
index 0b97f0c..6343cfe 100644
--- a/include/configs/NC650.h
+++ b/include/configs/NC650.h
@@ -440,13 +440,13 @@
  */
 
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nand0"
 #define CONFIG_JFFS2_PART_SIZE		0x00400000
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=nc650-0,nand0=nc650-nand"
 
 #define MTDPARTS_DEFAULT	"mtdparts=nc650-0:1m(kernel1),1m(kernel2)," \
diff --git a/include/configs/NETTA.h b/include/configs/NETTA.h
index 34fdba5..724e807 100644
--- a/include/configs/NETTA.h
+++ b/include/configs/NETTA.h
@@ -702,7 +702,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nand0"
 #define CONFIG_JFFS2_PART_SIZE		0x00100000
 #define CONFIG_JFFS2_PART_OFFSET	0x00200000
@@ -710,7 +710,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nand0=netta-nand"
 #define MTDPARTS_DEFAULT	"mtdparts=netta-nand:1m@2m(jffs2)"
 */
diff --git a/include/configs/PPChameleonEVB.h b/include/configs/PPChameleonEVB.h
index d2eae1d..16baf8c 100644
--- a/include/configs/PPChameleonEVB.h
+++ b/include/configs/PPChameleonEVB.h
@@ -804,14 +804,14 @@
  */
 
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nand0"
 #define CONFIG_JFFS2_PART_SIZE		0x00400000
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=PPChameleon-0,nand0=ppchameleonevb-nand"
 */
 
diff --git a/include/configs/R360MPI.h b/include/configs/R360MPI.h
index bab4460..830f4bc 100644
--- a/include/configs/R360MPI.h
+++ b/include/configs/R360MPI.h
@@ -167,14 +167,14 @@
  */
 /* No command line, one static partition
  * use all the space starting at offset 3MB*/
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00300000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=r360-0"
 #define MTDPARTS_DEFAULT	"mtdparts=r360-0:-@3m(user)"
 */
diff --git a/include/configs/RBC823.h b/include/configs/RBC823.h
index 280175a..f36244d 100644
--- a/include/configs/RBC823.h
+++ b/include/configs/RBC823.h
@@ -429,7 +429,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -437,7 +437,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/RPXClassic.h b/include/configs/RPXClassic.h
index 162ef09..bec5278 100644
--- a/include/configs/RPXClassic.h
+++ b/include/configs/RPXClassic.h
@@ -53,6 +53,7 @@
 #define CONFIG_SYS_DISCOVER_PHY        1
 #define CONFIG_MII              1
 #endif /* CONFIG_FEC_ENET */
+#define CONFIG_MISC_INIT_R
 
 /* Video console (graphic: Epson SED13806 on ECCX board, no keyboard         */
 #if 1
diff --git a/include/configs/Rattler.h b/include/configs/Rattler.h
index 01d0d5f..5b6f271 100644
--- a/include/configs/Rattler.h
+++ b/include/configs/Rattler.h
@@ -202,7 +202,7 @@
  *
  */
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00100000
@@ -210,7 +210,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=rattler-0"
 #define MTDPARTS_DEFAULT	"mtdparts=rattler-0:-@1m(jffs2)"
 */
diff --git a/include/configs/SIMPC8313.h b/include/configs/SIMPC8313.h
index b939cfa..e20527e 100644
--- a/include/configs/SIMPC8313.h
+++ b/include/configs/SIMPC8313.h
@@ -189,7 +189,7 @@
 #define CONFIG_JFFS2_DEV	"nand0"
 
 /* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nand0=nand0"
 #define MTDPARTS_DEFAULT	"mtdparts=nand0:2M(u-boot),6M(kernel),-(jffs2)"
 
diff --git a/include/configs/SXNI855T.h b/include/configs/SXNI855T.h
index 9857bf6..cac04b4 100644
--- a/include/configs/SXNI855T.h
+++ b/include/configs/SXNI855T.h
@@ -174,7 +174,7 @@
  *
  */
 /* No command line, one static partition */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 
 /*
 #define CONFIG_JFFS2_DEV		"nor0"
@@ -189,7 +189,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=sixnet-0,nand0=sixnet-nand"
 #define MTDPARTS_DEFAULT	"mtdparts=sixnet-0:7680k@512k();sixnet-nand:2m(jffs2-nand)"
 */
diff --git a/include/configs/TB5200.h b/include/configs/TB5200.h
index b42d3d9..92b4fa5 100644
--- a/include/configs/TB5200.h
+++ b/include/configs/TB5200.h
@@ -275,7 +275,7 @@
 					   (= chip selects) */
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM5200-0"
 #if defined(CONFIG_TQM5200_B)
 #define MTDPARTS_DEFAULT	"mtdparts=TQM5200-0:768k(firmware),"	\
diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h
index 6850eba..d374981 100644
--- a/include/configs/TQM5200.h
+++ b/include/configs/TQM5200.h
@@ -407,7 +407,7 @@
 #endif
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM5200-0"
 
 #ifdef CONFIG_STK52XX
diff --git a/include/configs/TQM823L.h b/include/configs/TQM823L.h
index 8934d51..87e5a65 100644
--- a/include/configs/TQM823L.h
+++ b/include/configs/TQM823L.h
@@ -231,7 +231,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/TQM823M.h b/include/configs/TQM823M.h
index fd41573..f666443 100644
--- a/include/configs/TQM823M.h
+++ b/include/configs/TQM823M.h
@@ -227,7 +227,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h
index e126dc3..b74b404 100644
--- a/include/configs/TQM834x.h
+++ b/include/configs/TQM834x.h
@@ -537,7 +537,7 @@
  * JFFS2 partitions
  */
 /* mtdparts command line support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM834x-0"
 
 /* default mtd partition table */
diff --git a/include/configs/TQM850L.h b/include/configs/TQM850L.h
index 77eb5a9..dc80b47 100644
--- a/include/configs/TQM850L.h
+++ b/include/configs/TQM850L.h
@@ -216,7 +216,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/TQM850M.h b/include/configs/TQM850M.h
index bb8825b..2289443 100644
--- a/include/configs/TQM850M.h
+++ b/include/configs/TQM850M.h
@@ -216,7 +216,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/TQM855L.h b/include/configs/TQM855L.h
index 2ccbaf8..999bdaa 100644
--- a/include/configs/TQM855L.h
+++ b/include/configs/TQM855L.h
@@ -221,7 +221,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/TQM855M.h b/include/configs/TQM855M.h
index 8a65183..b54967d 100644
--- a/include/configs/TQM855M.h
+++ b/include/configs/TQM855M.h
@@ -256,7 +256,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/TQM85xx.h b/include/configs/TQM85xx.h
index 3b2272c..72db26c 100644
--- a/include/configs/TQM85xx.h
+++ b/include/configs/TQM85xx.h
@@ -597,14 +597,14 @@
 
 #define	CONFIG_JFFS2_NAND	1
 
-#ifdef CONFIG_JFFS2_CMDLINE
+#ifdef CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nand0=TQM85xx-nand"
 #define MTDPARTS_DEFAULT	"mtdparts=TQM85xx-nand:-"
 #else
 #define CONFIG_JFFS2_DEV 	"nand0"	/* NAND device jffs2 lives on	*/
 #define CONFIG_JFFS2_PART_OFFSET 0	/* start of jffs2 partition	*/
 #define CONFIG_JFFS2_PART_SIZE	0x200000 /* size of jffs2 partition	*/
-#endif /* CONFIG_JFFS2_CMDLINE */
+#endif /* CONFIG_CMD_MTDPARTS */
 
 #endif /* CONFIG_NAND */
 
diff --git a/include/configs/TQM860L.h b/include/configs/TQM860L.h
index 8bd1fe0..2e2a165 100644
--- a/include/configs/TQM860L.h
+++ b/include/configs/TQM860L.h
@@ -220,7 +220,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/TQM860M.h b/include/configs/TQM860M.h
index ad2c71c..1148f2e 100644
--- a/include/configs/TQM860M.h
+++ b/include/configs/TQM860M.h
@@ -221,7 +221,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/TQM862L.h b/include/configs/TQM862L.h
index 0a5180e..577f982 100644
--- a/include/configs/TQM862L.h
+++ b/include/configs/TQM862L.h
@@ -224,7 +224,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/TQM862M.h b/include/configs/TQM862M.h
index ee6980c..69070e6 100644
--- a/include/configs/TQM862M.h
+++ b/include/configs/TQM862M.h
@@ -225,7 +225,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/TQM866M.h b/include/configs/TQM866M.h
index 421a2d8..bb68614 100644
--- a/include/configs/TQM866M.h
+++ b/include/configs/TQM866M.h
@@ -265,7 +265,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxM-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxM-0:512k(u-boot),"	\
diff --git a/include/configs/Total5200.h b/include/configs/Total5200.h
index 9a75848..1daa574 100644
--- a/include/configs/Total5200.h
+++ b/include/configs/Total5200.h
@@ -397,6 +397,7 @@
 #define	CONFIG_IDE_RESET		/* reset for ide supported	*/
 #define CONFIG_IDE_PREINIT
 
+#define CONFIG_SYS_ATA_CS_ON_I2C2
 #define CONFIG_SYS_IDE_MAXBUS		1	/* max. 1 IDE bus		*/
 #define CONFIG_SYS_IDE_MAXDEVICE	1	/* max. 1 drive per IDE bus	*/
 
diff --git a/include/configs/XPEDITE1K.h b/include/configs/XPEDITE1K.h
index 8d44ec6..74e55c9 100644
--- a/include/configs/XPEDITE1K.h
+++ b/include/configs/XPEDITE1K.h
@@ -38,6 +38,7 @@
 #define CONFIG_440		1
 #define CONFIG_440GX		1		/* 440 GX */
 #define CONFIG_BOARD_EARLY_INIT_F 1		/* Call board_pre_init	*/
+#define CONFIG_MISC_INIT_R
 #undef	CONFIG_SYS_DRAM_TEST				/* Disable-takes long time! */
 #define CONFIG_SYS_CLK_FREQ	33333333	/* external freq to pll */
 
diff --git a/include/configs/ZUMA.h b/include/configs/ZUMA.h
index 08c4ced..b73aaa8 100644
--- a/include/configs/ZUMA.h
+++ b/include/configs/ZUMA.h
@@ -130,7 +130,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -138,7 +138,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor1=zuma-1,nor2=zuma-2"
 #define MTDPARTS_DEFAULT	"mtdparts=zuma-1:-(jffs2),zuma-2:-(user)"
 */
diff --git a/include/configs/apollon.h b/include/configs/apollon.h
index dff47fc..f83dd9c 100644
--- a/include/configs/apollon.h
+++ b/include/configs/apollon.h
@@ -258,7 +258,7 @@
 #define CONFIG_ENV_ADDR		0x00020000
 
 #ifdef CONFIG_SYS_USE_UBI
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"onenand0=onenand"
 #define MTDPARTS_DEFAULT	"mtdparts=onenand:128k(bootloader),"	\
 					"128k(params),"			\
diff --git a/include/configs/cm5200.h b/include/configs/cm5200.h
index ddcc6aa..54cf40d 100644
--- a/include/configs/cm5200.h
+++ b/include/configs/cm5200.h
@@ -222,7 +222,7 @@
 /*
  * MTD configuration
  */
-#define CONFIG_JFFS2_CMDLINE	1
+#define CONFIG_CMD_MTDPARTS	1
 #define MTDIDS_DEFAULT		"nor0=cm5200-0"
 #define MTDPARTS_DEFAULT	"mtdparts=cm5200-0:"			\
 					"384k(uboot),128k(env),"	\
diff --git a/include/configs/cmc_pu2.h b/include/configs/cmc_pu2.h
index d9acb47..e5c74e1 100644
--- a/include/configs/cmc_pu2.h
+++ b/include/configs/cmc_pu2.h
@@ -143,6 +143,7 @@
 #endif
 
 
+#define CONFIG_MISC_INIT_R
 #define CONFIG_SYS_LONGHELP
 
 #define AT91_SMART_MEDIA_ALE	(1 << 22)	/* our ALE is AD22 */
diff --git a/include/configs/debris.h b/include/configs/debris.h
index 4d65f6a..dc59df9 100644
--- a/include/configs/debris.h
+++ b/include/configs/debris.h
@@ -234,7 +234,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -246,7 +246,7 @@
  * Note: fake mtd_id's used, no linux mtd map file.
  */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=debris-0"
 #define MTDPARTS_DEFAULT	"mtdparts=debris-0:-(jffs2)"
 */
diff --git a/include/configs/digsy_mtc.h b/include/configs/digsy_mtc.h
new file mode 100644
index 0000000..2716d5b
--- /dev/null
+++ b/include/configs/digsy_mtc.h
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2005-2007
+ * Modified for InterControl digsyMTC MPC5200 board by
+ * Frank Bodammer, GCD Hard- & Software GmbH,
+ *                 frank.bodammer@gcd-solutions.de
+ *
+ * (C) Copyright 2009 Semihalf
+ * Optimized for digsyMTC by: Grzegorz Bernacki <gjb@semihalf.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
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+
+#define CONFIG_MPC5xxx		1	/* This is an MPC5xxx CPU */
+#define CONFIG_MPC5200		1	/* (more precisely an MPC5200 CPU) */
+#define CONFIG_DIGSY_MTC	1	/* ... on InterControl digsyMTC board */
+
+#define CONFIG_SYS_MPC5XXX_CLKIN	33000000
+
+#define BOOTFLAG_COLD		0x01
+#define BOOTFLAG_WARM		0x02
+
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+/*
+ * Serial console configuration
+ */
+#define CONFIG_PSC_CONSOLE	4	/* console is on PSC4  */
+#define CONFIG_BAUDRATE		115200	/* ... at 115200  bps  */
+#define CONFIG_SYS_BAUDRATE_TABLE	\
+	{ 9600, 19200, 38400, 57600, 115200, 230400 }
+
+/*
+ * PCI Mapping:
+ * 0x40000000 - 0x4fffffff - PCI Memory
+ * 0x50000000 - 0x50ffffff - PCI IO Space
+ */
+#define CONFIG_PCI		1
+#define CONFIG_PCI_PNP		1
+#define CONFIG_PCI_SCAN_SHOW	1
+
+#define CONFIG_PCI_MEM_BUS	0x40000000
+#define CONFIG_PCI_MEM_PHYS	CONFIG_PCI_MEM_BUS
+#define CONFIG_PCI_MEM_SIZE	0x10000000
+
+#define CONFIG_PCI_IO_BUS	0x50000000
+#define CONFIG_PCI_IO_PHYS	CONFIG_PCI_IO_BUS
+#define CONFIG_PCI_IO_SIZE	0x01000000
+
+/*
+ *  Partitions
+ */
+#define CONFIG_DOS_PARTITION
+#define CONFIG_BZIP2
+
+/*
+ * Command line configuration.
+ */
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_DFL
+#define CONFIG_CMD_CACHE
+#define CONFIG_CMD_DATE
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_DIAG
+#define CONFIG_CMD_EEPROM
+#define CONFIG_CMD_ELF
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_FAT
+#define CONFIG_CMD_I2C
+#define CONFIG_CMD_IDE
+#define CONFIG_CMD_IRQ
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PCI
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_REGINFO
+#define CONFIG_CMD_SAVES
+#define CONFIG_CMD_USB
+
+#if (TEXT_BASE == 0xFF000000)
+#define CONFIG_SYS_LOWBOOT	1
+#endif
+
+/*
+ * Autobooting
+ */
+#define CONFIG_BOOTDELAY	1
+
+#undef	CONFIG_BOOTARGS
+
+#define CONFIG_EXTRA_ENV_SETTINGS			\
+	"netdev=eth0\0"					\
+	"console=ttyPSC0\0"				\
+	"kernel_addr_r=400000\0"			\
+	"fdt_addr_r=600000\0"				\
+	"nfsargs=setenv bootargs root=/dev/nfs rw "	\
+	"nfsroot=${serverip}:${rootpath}\0"		\
+	"addip=setenv bootargs ${bootargs} "		\
+		"ip=${ipaddr}:${serverip}:${gatewayip}:"\
+		"${netmask}:${hostname}:${netdev}:off panic=1\0"	\
+	"addcons=setenv bootargs ${bootargs} console=${console},${baudrate}\0"\
+	"rootpath=/opt/eldk/ppc_6xx\0"			\
+	"net_nfs=tftp ${kernel_addr_r} ${bootfile};"	\
+		"tftp ${fdt_addr_r} ${fdt_file};"	\
+		"run nfsargs addip addcons;"		\
+		"bootm ${kernel_addr_r} - ${fdt_addr_r}\0"	\
+	"load=tftp 200000 ${u-boot}\0"			\
+	"update=protect off FFF00000 +${filesize};"	\
+		"erase FFF00000 +${filesize};"		\
+		"cp.b 200000 FFF00000 ${filesize};"	\
+		"protect on FFF00000 +${filesize}\0"	\
+	""
+
+/*
+ * I2C configuration
+ */
+#define CONFIG_HARD_I2C		1
+#define CONFIG_SYS_I2C_MODULE	1
+#define CONFIG_SYS_I2C_SPEED	100000
+#define CONFIG_SYS_I2C_SLAVE	0x7F
+
+/*
+ * EEPROM configuration
+ */
+#define CONFIG_SYS_I2C_EEPROM_ADDR		0x50	/* 1010000x */
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 	1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	70
+
+/*
+ * RTC configuration
+ */
+#define CONFIG_RTC_DS1337
+#define CONFIG_SYS_I2C_RTC_ADDR	0x68
+
+/*
+ * Flash configuration
+ */
+#define	CONFIG_SYS_FLASH_CFI		1
+#define	CONFIG_FLASH_CFI_DRIVER	1
+
+#define CONFIG_SYS_FLASH_BASE		0xFF000000
+#define CONFIG_SYS_FLASH_SIZE	0x01000000
+
+#define CONFIG_SYS_MAX_FLASH_BANKS	1
+#define CONFIG_SYS_MAX_FLASH_SECT	256
+#define CONFIG_FLASH_16BIT
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_BANKS_LIST	{ CONFIG_SYS_FLASH_BASE }
+#define CONFIG_SYS_FLASH_ERASE_TOUT	240000
+#define CONFIG_SYS_FLASH_WRITE_TOUT	500
+
+#define CONFIG_OF_LIBFDT  1
+#define CONFIG_OF_BOARD_SETUP	1
+
+#define OF_CPU			"PowerPC,5200@0"
+#define OF_SOC			"soc5200@f0000000"
+#define OF_TBCLK		(bd->bi_busfreq / 4)
+
+#define CONFIG_BOARD_EARLY_INIT_R
+#define CONFIG_MISC_INIT_R
+
+/*
+ * Environment settings
+ */
+#define CONFIG_ENV_IS_IN_FLASH	1
+#if defined(CONFIG_LOWBOOT)
+#define CONFIG_ENV_ADDR		0xFF060000
+#else	/* CONFIG_LOWBOOT */
+#define CONFIG_ENV_ADDR		0xFFF60000
+#endif	/* CONFIG_LOWBOOT */
+#define CONFIG_ENV_SIZE		0x10000
+#define CONFIG_ENV_SECT_SIZE	0x20000
+#define CONFIG_ENV_OVERWRITE	1
+
+/*
+ * Memory map
+ */
+#define CONFIG_SYS_MBAR		0xF0000000
+#define CONFIG_SYS_SDRAM_BASE		0x00000000
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_DEFAULT_MBAR	0x80000000
+#else
+#define CONFIG_SYS_DEFAULT_MBAR	0xF0000000
+#endif
+
+/*
+ *  Use SRAM until RAM will be available
+ */
+#define CONFIG_SYS_INIT_RAM_ADDR	MPC5XXX_SRAM
+#define CONFIG_SYS_INIT_RAM_END		MPC5XXX_SRAM_SIZE
+
+#define CONFIG_SYS_GBL_DATA_SIZE	4096
+#define CONFIG_SYS_GBL_DATA_OFFSET	\
+	(CONFIG_SYS_INIT_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_OFFSET	CONFIG_SYS_GBL_DATA_OFFSET
+
+#define CONFIG_SYS_MONITOR_BASE	TEXT_BASE
+#if (CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE)
+#define CONFIG_SYS_RAMBOOT		1
+#endif
+
+#define CONFIG_SYS_MONITOR_LEN	(256 << 10)
+#define CONFIG_SYS_MALLOC_LEN	(4096 << 10)
+#define CONFIG_SYS_BOOTMAPSZ	(8 << 20)
+
+/*
+ * Ethernet configuration
+ */
+#define CONFIG_MPC5xxx_FEC	1
+#define CONFIG_MPC5xxx_FEC_MII100
+#define CONFIG_PHY_ADDR		0x00
+#define CONFIG_PHY_RESET_DELAY	1000
+
+#define CONFIG_NETCONSOLE		/* include NetConsole support	*/
+
+/*
+ * GPIO configuration
+ */
+#define CONFIG_SYS_GPS_PORT_CONFIG	0xA2552112
+
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_AUTO_COMPLETE	1
+#define CONFIG_SYS_PROMPT	"=> "
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+
+#define CONFIG_AUTOBOOT_KEYED
+#define CONFIG_AUTOBOOT_PROMPT "autoboot in %d seconds\n", bootdelay
+#define CONFIG_AUTOBOOT_DELAY_STR	" "
+
+#define CONFIG_LOOPW		1
+#define CONFIG_MX_CYCLIC	1
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+
+#define CONFIG_SYS_CBSIZE		1024
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16)
+#define CONFIG_SYS_MAXARGS		32
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_ALT_MEMTEST
+#define CONFIG_SYS_MEMTEST_SCRATCH	0x00001000
+#define CONFIG_SYS_MEMTEST_START	0x00010000
+#define CONFIG_SYS_MEMTEST_END		0x019fffff
+
+#define CONFIG_SYS_LOAD_ADDR		0x00100000
+
+#define CONFIG_SYS_HZ			1000
+
+/*
+ * Various low-level settings
+ */
+#define CONFIG_SYS_SDRAM_CS1		1
+#define CONFIG_SYS_XLB_PIPELINING	1
+
+#define CONFIG_SYS_HID0_INIT		HID0_ICE | HID0_ICFI
+#define CONFIG_SYS_HID0_FINAL		HID0_ICE
+
+#if defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_BOOTCS_START	CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_BOOTCS_SIZE		CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_BOOTCS_CFG		0x0002DD00
+#endif
+
+#define CONFIG_SYS_CS4_START		0x60000000
+#define CONFIG_SYS_CS4_SIZE		0x1000
+#define CONFIG_SYS_CS4_CFG		0x0008FC00
+
+#define CONFIG_SYS_CS0_START		CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_CS0_SIZE		CONFIG_SYS_FLASH_SIZE
+#define CONFIG_SYS_CS0_CFG		0x0002DD00
+
+#define CONFIG_SYS_CS_BURST		0x00000000
+#define CONFIG_SYS_CS_DEADCYCLE	0x11111111
+
+#if !defined(CONFIG_SYS_LOWBOOT)
+#define CONFIG_SYS_RESET_ADDRESS	0xfff00100
+#else
+#define CONFIG_SYS_RESET_ADDRESS	0xff000100
+#endif
+
+/*
+ * USB
+ */
+#define CONFIG_USB_OHCI_NEW
+#define CONFIG_SYS_OHCI_BE_CONTROLLER
+#define CONFIG_USB_STORAGE
+
+#define CONFIG_USB_CLOCK	0x00013333
+#define CONFIG_USB_CONFIG	0x00002000
+
+#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS	15
+#define CONFIG_SYS_USB_OHCI_REGS_BASE	MPC5XXX_USB
+#define CONFIG_SYS_USB_OHCI_SLOT_NAME	"mpc5200"
+#define CONFIG_SYS_USB_OHCI_CPU_INIT
+
+/*
+ * IDE/ATA
+ */
+#define CONFIG_IDE_RESET
+#define CONFIG_IDE_PREINIT
+
+#define CONFIG_SYS_ATA_CS_ON_I2C2
+#define CONFIG_SYS_IDE_MAXBUS		1
+#define CONFIG_SYS_IDE_MAXDEVICE	1
+
+#define CONFIG_SYS_ATA_IDE0_OFFSET	0x0000
+#define CONFIG_SYS_ATA_BASE_ADDR	MPC5XXX_ATA
+#define CONFIG_SYS_ATA_DATA_OFFSET	(0x0060)
+#define CONFIG_SYS_ATA_REG_OFFSET	(CONFIG_SYS_ATA_DATA_OFFSET)
+#define CONFIG_SYS_ATA_ALT_OFFSET	(0x005C)
+#define CONFIG_SYS_ATA_STRIDE		4
+
+#define CONFIG_ATAPI		1
+#define CONFIG_LBA48		1
+
+#endif /* __CONFIG_H */
+
diff --git a/include/configs/eNET.h b/include/configs/eNET.h
index 447c7bc..84e1aef 100644
--- a/include/configs/eNET.h
+++ b/include/configs/eNET.h
@@ -40,8 +40,8 @@
 #define DEBUG_PARSER
 
 #define CONFIG_X86			1	/* Intel X86 CPU */
-#define CONFIG_SC520			1	/* AMD SC520 */
-#define CONFIG_SC520_SSI
+#define CONFIG_SYS_SC520		1	/* AMD SC520 */
+#define CONFIG_SYS_SC520_SSI
 #define CONFIG_SHOW_BOOT_PROGRESS	1
 #define CONFIG_LAST_STAGE_INIT		1
 
@@ -90,7 +90,7 @@
 #define CONFIG_CMD_RUN		/* run command in env variable	*/
 #define CONFIG_CMD_SETGETDCR	/* DCR support on 4xx		*/
 #define CONFIG_CMD_XIMG		/* Load part of Multi Image	*/
-#undef CONFIG_CMD_IRQ		/* IRQ Information		*/
+#define CONFIG_CMD_IRQ		/* IRQ Information		*/
 
 #define CONFIG_BOOTDELAY		15
 #define CONFIG_BOOTARGS			"root=/dev/mtdblock0 console=ttyS0,9600"
@@ -142,12 +142,14 @@
  * CPU Features
  */
 #define CONFIG_SYS_SC520_HIGH_SPEED	0	/* 100 or 133MHz */
-#undef  CONFIG_SYS_RESET_SC520			/* use SC520 MMCR's to reset cpu */
-#define CONFIG_SYS_TIMER_SC520			/* use SC520 swtimers */
-#undef  CONFIG_SYS_TIMER_GENERIC		/* use the i8254 PIT timers */
-#undef  CONFIG_SYS_TIMER_TSC			/* use the Pentium TSC timers */
+#undef  CONFIG_SYS_SC520_RESET			/* use SC520 MMCR's to reset cpu */
+#define CONFIG_SYS_SC520_TIMER			/* use SC520 swtimers */
+#undef  CONFIG_SYS_GENERIC_TIMER		/* use the i8254 PIT timers */
+#undef  CONFIG_SYS_TSC_TIMER			/* use the Pentium TSC timers */
 #define CONFIG_SYS_USE_SIO_UART		0       /* prefer the uarts on the SIO to those
 					 * in the SC520 on the CDP */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS		16
 
 /*-----------------------------------------------------------------------
  * Memory organization
diff --git a/include/configs/ep7312.h b/include/configs/ep7312.h
index 0581842..322a3ca 100644
--- a/include/configs/ep7312.h
+++ b/include/configs/ep7312.h
@@ -158,7 +158,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -166,7 +166,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=ep7312-0"
 #define MTDPARTS_DEFAULT	"mtdparts=ep7312-0:-(jffs2)"
 */
diff --git a/include/configs/ep8260.h b/include/configs/ep8260.h
index d49d02f..3f4425a 100644
--- a/include/configs/ep8260.h
+++ b/include/configs/ep8260.h
@@ -758,7 +758,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -766,7 +766,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/fx12mm.h b/include/configs/fx12mm.h
index 5844567..27c6e7d 100644
--- a/include/configs/fx12mm.h
+++ b/include/configs/fx12mm.h
@@ -37,7 +37,7 @@
 
 /* cmd config */
 #define CONFIG_CMD_JFFS2
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #undef CONFIG_CMD_NET
 
 /* sdram */
diff --git a/include/configs/hymod.h b/include/configs/hymod.h
index 0fdcda2..2dacfb6 100644
--- a/include/configs/hymod.h
+++ b/include/configs/hymod.h
@@ -730,14 +730,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		""
 #define MTDPARTS_DEFAULT	""
 */
diff --git a/include/configs/idmr.h b/include/configs/idmr.h
index 1dd89f9..944d06f 100644
--- a/include/configs/idmr.h
+++ b/include/configs/idmr.h
@@ -229,7 +229,7 @@
 
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=idmr-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=idmr-0:128k(u-boot),"	\
diff --git a/include/configs/impa7.h b/include/configs/impa7.h
index bb3c02e..a3d023f 100644
--- a/include/configs/impa7.h
+++ b/include/configs/impa7.h
@@ -160,14 +160,14 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00020000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=impA7 NOR Flash Bank #0,nor1=impA7 NOR Flash Bank #1"
 #define MTDPARTS_DEFAULT	"mtdparts=impA7 NOR Flash Bank #0:-(FileSystem1);impA7 NOR Flash Bank #1:-(FileSystem2)"
 */
diff --git a/include/configs/imx31_litekit.h b/include/configs/imx31_litekit.h
index 6c150ae..9ac6eec 100644
--- a/include/configs/imx31_litekit.h
+++ b/include/configs/imx31_litekit.h
@@ -170,7 +170,7 @@
 /*
  * JFFS2 partitions
  */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV	"nor0"
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/imx31_phycore.h b/include/configs/imx31_phycore.h
index f0d28ee..cbc0b92 100644
--- a/include/configs/imx31_phycore.h
+++ b/include/configs/imx31_phycore.h
@@ -175,7 +175,30 @@
 /*
  * JFFS2 partitions
  */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV	"nor0"
 
+/* EET platform additions */
+#ifdef CONFIG_IMX31_PHYCORE_EET
+#define BOARD_LATE_INIT
+
+#define CONFIG_MX31_GPIO			1
+
+#define CONFIG_HARD_SPI				1
+#define CONFIG_MXC_SPI				1
+#define CONFIG_CMD_SPI
+
+#define CONFIG_S6E63D6				1
+
+#define CONFIG_LCD				1
+#define CONFIG_VIDEO_MX3			1
+#define CONFIG_SYS_WHITE_ON_BLACK		1
+#define LCD_BPP					LCD_COLOR8
+#define	CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE	1
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV		1
+
+#define	CONFIG_SPLASH_SCREEN			1
+#define CONFIG_CMD_BMP				1
+#endif
+
 #endif /* __CONFIG_H */
diff --git a/include/configs/incaip.h b/include/configs/incaip.h
index a18ba80..2129dfd 100644
--- a/include/configs/incaip.h
+++ b/include/configs/incaip.h
@@ -168,14 +168,14 @@
  * JFFS2 partitions
  */
 /* No command line, one static partition, use all space on the device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor1"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=INCA-IP Bank 0"
 #define MTDPARTS_DEFAULT	"mtdparts=INCA-IP Bank 0:192k(uboot)," \
 							"64k(env)," \
diff --git a/include/configs/innokom.h b/include/configs/innokom.h
index d9b1555..043ae2f 100644
--- a/include/configs/innokom.h
+++ b/include/configs/innokom.h
@@ -203,7 +203,7 @@
 */
 
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -211,7 +211,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=innokom-0"
 */
 
diff --git a/include/configs/keymile-common.h b/include/configs/keymile-common.h
index d70bc48..58b95f4 100644
--- a/include/configs/keymile-common.h
+++ b/include/configs/keymile-common.h
@@ -27,9 +27,7 @@
 /* Do boardspecific init for all boards */
 #define CONFIG_BOARD_EARLY_INIT_R       1
 
-#if defined(CONFIG_MGCOGE) || defined(CONFIG_MGSUVD)
 #define CONFIG_BOOTCOUNT_LIMIT
-#endif
 
 /*
  * Command line configuration.
@@ -42,17 +40,14 @@
 #define CONFIG_CMD_IMMAP
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_PING
-
-/* should go away, if kmeter I2C support is enabled */
-#if defined(CONFIG_MGCOGE) || defined(CONFIG_MGSUVD)
 #define CONFIG_CMD_DTT
 #define CONFIG_CMD_EEPROM
 #define CONFIG_CMD_I2C
-#endif
+#define CONFIG_CMD_JFFS2
+#define CONFIG_JFFS2_CMDLINE
 
 #undef	CONFIG_WATCHDOG			/* disable platform specific watchdog */
 
-#define CONFIG_BOOTCOMMAND	"run net_nfs"
 #define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds */
 #undef	CONFIG_BOOTARGS			/* the boot command will set bootargs */
 
@@ -72,11 +67,10 @@
 #define CONFIG_SYS_MAXARGS		16	/* max number of command args */
 #define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE	/* Boot Argument Buffer Size  */
 #define CONFIG_CMDLINE_EDITING		1	/* add command line history     */
+#define CONFIG_COMMAND_HISTORY		1
+#define CONFIG_AUTO_COMPLETE		/* add autocompletion support	*/
 
-/* should go away, if kmeter I2C support is enabled */
-#if defined(CONFIG_MGCOGE) || defined(CONFIG_MGSUVD)
 #define CONFIG_HUSH_INIT_VAR	1
-#endif
 
 #define CONFIG_SYS_ALT_MEMTEST		/* memory test, takes time */
 #define CONFIG_SYS_MEMTEST_START	0x00100000	/* memtest works on */
@@ -102,6 +96,25 @@
 #define CONFIG_SYS_SLOT_ID_OFF		(0x07)	/* register offset */
 #define CONFIG_SYS_SLOT_ID_MASK		(0x3f)	/* mask for slot ID bits */
 
+#define CONFIG_I2C_MULTI_BUS	1
+#define CONFIG_I2C_CMD_TREE	1
+#define CONFIG_SYS_MAX_I2C_BUS		2
+#define CONFIG_SYS_I2C_INIT_BOARD	1
+#define CONFIG_I2C_MUX		1
+
+/* EEprom support */
+#define CONFIG_SYS_I2C_MULTI_EEPROMS	1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_ENABLE
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 10
+
+/* Support the IVM EEprom */
+#define	CONFIG_SYS_IVM_EEPROM_ADR	0x50
+#define CONFIG_SYS_IVM_EEPROM_MAX_LEN	0x400
+#define CONFIG_SYS_IVM_EEPROM_PAGE_LEN	0x100
+
+#define	CONFIG_SYS_FLASH_PROTECTION 1
+
 /*
  * BOOTP options
  */
@@ -110,4 +123,130 @@
 #define CONFIG_BOOTP_GATEWAY
 #define CONFIG_BOOTP_HOSTNAME
 
+/* define this to use the keymile's io muxing feature */
+/*#define CONFIG_IO_MUXING */
+
+#ifdef CONFIG_IO_MUXING
+#define	CONFIG_KM_DEF_ENV_IOMUX \
+	"nc=setenv ethact HDLC ETHERNET \0" \
+	"nce=setenv ethact SCC ETHERNET \0"	\
+	"stderr=serial,nc \0"	\
+	"stdin=serial,nc \0" \
+	"stdout=serial,nc \0" \
+	"tftpsrcp=69 \0" \
+	"tftpdstp=69 \0"
+#else
+#define	CONFIG_KM_DEF_ENV_IOMUX \
+	"stderr=serial \0" \
+	"stdin=serial \0"	 \
+	"stdout=serial \0"
+#endif
+
+#ifndef CONFIG_KM_DEF_ENV_PRIVATE
+#define	CONFIG_KM_DEF_ENV_PRIVATE \
+	"kmprivate=empty\0"
+#endif
+
+#define xstr(s)	str(s)
+#define str(s)	#s
+
+#ifndef CONFIG_KM_DEF_ENV
+#define CONFIG_KM_DEF_ENV	\
+	"netdev=eth0\0"							\
+	"u-boot_addr_r=100000\0"					\
+	"kernel_addr_r=200000\0"					\
+	"fdt_addr_r=600000\0"						\
+	"ram_ws=800000 \0"						\
+	"autoscr_ws=780000 \0"						\
+	"fdt_file=" xstr(CONFIG_HOSTNAME) "/" 				\
+		xstr(CONFIG_HOSTNAME) ".dtb\0"				\
+	"u-boot=" xstr(CONFIG_HOSTNAME) "/u-boot.bin \0" 		\
+	"kernel_file=" xstr(CONFIG_HOSTNAME) "/uImage \0" 		\
+	"load=tftp ${u-boot_addr_r} ${u-boot}\0"			\
+	"update=protect off " xstr(BOOTFLASH_START) " +${filesize};"	\
+		"erase " xstr(BOOTFLASH_START) "  +${filesize};"	\
+		"cp.b ${u-boot_addr_r} " xstr(BOOTFLASH_START) 		\
+		"  ${filesize};"					\
+		"protect on " xstr(BOOTFLASH_START) "  +${filesize}\0"	\
+	"load_fdt=tftp ${fdt_addr_r} ${fdt_file}; "			\
+		"setenv actual_fdt_addr ${fdt_addr_r} \0" 		\
+	"load_kernel=tftp ${kernel_addr_r} ${kernel_file}; " 		\
+		"setenv actual_kernel_addr ${kernel_addr_r} \0" 	\
+	"ramargs=setenv bootargs root=/dev/ram rw\0"			\
+	"nfsargs=setenv bootargs root=/dev/nfs rw "			\
+		"nfsroot=${serverip}:${rootpath}\0"			\
+	"mtdargs=setenv bootargs root=${actual_rootfs} rw "		\
+		"rootfstype=jffs2 \0" 					\
+	"altmtdargs=setenv bootargs root=${backup_rootfs} rw "		\
+		"rootfstype=jffs2 \0" 					\
+	"addmtd=setenv bootargs ${bootargs} ${mtdparts}\0"		\
+	"addip=setenv bootargs ${bootargs} "				\
+		"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}"	\
+		":${hostname}:${netdev}:off panic=1\0"			\
+	"addboardid=setenv bootargs ${bootargs} " 			\
+		"hwKey=${IVM_HWKey} boardId=0x${IVM_BoardId} \0" 	\
+	"addpram=setenv bootargs ${bootargs} "				\
+		"mem=${mem} pram=${pram}\0"				\
+	"pram=" xstr(CONFIG_PRAM) "k\0"					\
+	"net_nfs=tftp ${kernel_addr_r} ${kernel_file}; "		\
+		"tftp ${fdt_addr_r} ${fdt_file}; "			\
+		"run nfsargs addip addcon addboardid addpram;"		\
+		"bootm ${kernel_addr_r} - ${fdt_addr_r}\0"		\
+	"net_self=tftp ${kernel_addr_r} ${kernel_file}; "		\
+		"tftp ${fdt_addr_r} ${fdt_file}; "			\
+		"tftp ${ramdisk_addr} ${ramdisk_file}; "		\
+		"run ramargs addip addboardid addpram; "		\
+		"bootm ${kernel_addr_r} ${ramdisk_addr} ${fdt_addr_r}\0"\
+	"flash_nfs=run nfsargs addip addcon;"				\
+		"bootm ${kernel_addr} - ${fdt_addr}\0"			\
+	"flash_self=run ramargs addip addcon addboardid addpram;"	\
+		"bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"	\
+	"bootcmd=run mtdargs addip addcon addboardid addpram; "		\
+		"bootm ${actual_kernel_addr} - ${actual_fdt_addr} \0"	\
+	"altbootcmd=run altmtdargs addip addcon addboardid addpram; "	\
+		"bootm ${backup_kernel_addr} - ${backup_fdt_addr} \0"	\
+	"actual0=setenv actual_bank 0; setenv actual_kernel_addr "	\
+		"${bank0_kernel_addr}; "				\
+		"setenv actual_fdt_addr ${bank0_fdt_addr}; "		\
+		"setenv actual_rootfs ${bank0_rootfs} \0" 		\
+	"actual1=setenv actual_bank 1; setenv actual_kernel_addr "	\
+		"${bank1_kernel_addr}; "				\
+		"setenv actual_fdt_addr ${bank1_fdt_addr}; "		\
+		"setenv actual_rootfs ${bank1_rootfs} \0" 		\
+	"backup0=setenv backup_bank 0; setenv backup_kernel_addr " 	\
+		"${bank0_kernel_addr}; "				\
+		"setenv backup_fdt_addr ${bank0_fdt_addr}; "		\
+		"setenv backup_rootfs ${bank0_rootfs} \0"		\
+	"backup1=setenv backup_bank 1; setenv backup_kernel_addr "	\
+		"${bank1_kernel_addr}; "				\
+		"setenv backup_fdt_addr ${bank1_fdt_addr}; " 		\
+		"setenv backup_rootfs ${bank1_rootfs} \0" 		\
+	"setbank0=run actual0 backup1 \0" 				\
+	"setbank1=run actual1 backup0 \0" 				\
+	"release=setenv bootcmd "					\
+		"\'run mtdargs addip addcon addboardid addpram;" 	\
+		"bootm ${actual_kernel_addr} - ${actual_fdt_addr} \'; "	\
+		"saveenv \0"						\
+	"develop=setenv bootcmd "					\
+		"\'run nfsargs addip addcon addboardid addpram;" 	\
+		"bootm ${actual_kernel_addr} - ${actual_fdt_addr} \'; "	\
+		"saveenv \0"						\
+	"developall=setenv bootcmd "					\
+		"\'run load_fdt load_kernel nfsargs "			\
+		"addip addcon addboardid addpram; "			\
+		"bootm ${actual_kernel_addr} - ${actual_fdt_addr} \'; "	\
+		"saveenv \0"						\
+	"set_new_esw_script=setenv new_esw_script "			\
+		"new_esw_0x${IVM_BoardId}_0x${IVM_HWKey}.scr \0"	\
+	"new_esw=run set_new_esw_script; "				\
+		"tftp ${autoscr_ws} ${new_esw_script}; "		\
+		"iminfo ${autoscr_ws}; autoscr ${autoscr_ws} \0"	\
+	"bootlimit=0 \0" 						\
+	CONFIG_KM_DEF_ENV_IOMUX						\
+	CONFIG_KM_DEF_ENV_PRIVATE					\
+	""
+#endif /* CONFIG_KM_DEF_ENV */
+
+#define CONFIG_VERSION_VARIABLE 	/* include version env variable */
+
 #endif /* __CONFIG_KEYMILE_H */
diff --git a/include/configs/km8xx.h b/include/configs/km8xx.h
new file mode 100644
index 0000000..c305b89
--- /dev/null
+++ b/include/configs/km8xx.h
@@ -0,0 +1,343 @@
+/*
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs@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
+ */
+
+/*
+ * configuration options, keymile 8xx board specific
+ */
+
+#ifndef __CONFIG_KM8XX_H
+#define __CONFIG_KM8XX_H
+
+/*
+ * High Level Configuration Options
+ * (easy to change)
+ */
+
+#define CONFIG_KM8XX		1	/* on a km8xx board */
+
+/* include common defines/options for all Keymile boards */
+#include "keymile-common.h"
+
+#if defined(CONFIG_KMSUPX4)
+#undef	CONFIG_I2C_MUX			/* no I2C mux on this board */
+#endif
+
+#define CONFIG_8xx_GCLK_FREQ		66000000
+
+#define CONFIG_SYS_SMC_UCODE_PATCH	1	/* Relocate SMC1 */
+#define CONFIG_SYS_SMC_DPMEM_OFFSET	0x1fc0
+#define CONFIG_8xx_CONS_SMC1	1	/* Console is on SMC1 */
+#define CONFIG_SYS_SMC_RXBUFLEN	128
+#define CONFIG_SYS_MAXIDLE	10
+
+#define CONFIG_SYS_CPM_BOOTCOUNT_ADDR	0x1eb0	/* In case of SMC relocation,
+						 * the default value is not
+						 * working
+						 */
+
+#define BOOTFLASH_START	F0000000
+#define CONFIG_PRAM	512	/* protected RAM [KBytes] */
+
+#define CONFIG_PREBOOT	"echo;" \
+	"echo Type \\\"run flash_nfs\\\" to mount root filesystem over NFS;" \
+	"echo"
+
+#define BOOTFLASH_START	F0000000
+#define CONFIG_PRAM	512	/* protected RAM [KBytes] */
+
+#if defined(CONFIG_MGSUVD)
+#define CONFIG_ENV_IVM	"EEprom_ivm=pca9544a:70:4 \0"
+#else
+#define CONFIG_ENV_IVM	""
+#endif
+
+#define MTDIDS_DEFAULT		"nor0=app"
+#define MTDPARTS_DEFAULT \
+	"mtdparts=app:384k(u-boot),128k(env),128k(envred),128k(free),"	\
+	"1536k(esw0),8704k(rootfs0),1536k(esw1),2432k(rootfs1),640k(var)," \
+	"768k(cfg)"
+
+#define CONFIG_EXTRA_ENV_SETTINGS					\
+	CONFIG_KM_DEF_ENV						\
+	"rootpath=/opt/eldk/ppc_8xx\0"					\
+	"addcon=setenv bootargs ${bootargs} "				\
+		"console=ttyCPM0,${baudrate}\0"				\
+	"mtdids=nor0=app \0"						\
+	"mtdparts=" MK_STR(MTDPARTS_DEFAULT) "\0"			\
+	"partition=nor0,9 \0"						\
+	"new_env=prot off F0060000 F009FFFF; era F0060000 F009FFFF \0" 	\
+	CONFIG_ENV_IVM							\
+	""
+
+#undef CONFIG_RTC_MPC8xx		/* MPC866 does not support RTC	*/
+
+#define	CONFIG_TIMESTAMP		/* but print image timestmps	*/
+
+/*
+ * Low Level Configuration Settings
+ * (address mappings, register initial values, etc.)
+ * You should know what you are doing if you make changes here.
+ */
+/*-----------------------------------------------------------------------
+ * Internal Memory Mapped Register
+ */
+#define CONFIG_SYS_IMMR		0xFFF00000
+
+/*-----------------------------------------------------------------------
+ * Definitions for initial stack pointer and data area (in DPRAM)
+ */
+#define CONFIG_SYS_INIT_RAM_ADDR	CONFIG_SYS_IMMR
+#define CONFIG_SYS_INIT_RAM_END	0x2F00	/* End of used area in DPRAM	*/
+#define CONFIG_SYS_GBL_DATA_SIZE	64
+#define CONFIG_SYS_GBL_DATA_OFFSET	(CONFIG_SYS_INIT_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_OFFSET	CONFIG_SYS_GBL_DATA_OFFSET
+
+/*-----------------------------------------------------------------------
+ * Start addresses for the final memory configuration
+ * (Set up by the startup code)
+ * Please note that CONFIG_SYS_SDRAM_BASE _must_ start at 0
+ */
+#define CONFIG_SYS_SDRAM_BASE		0x00000000
+#define CONFIG_SYS_FLASH_BASE		0xf0000000
+#define CONFIG_SYS_MONITOR_LEN		(384 << 10) /* 384 kB for Monitor */
+#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_FLASH_BASE
+#define CONFIG_SYS_MALLOC_LEN		(256 << 10) /* 256 kB for malloc() */
+
+/*
+ * For booting Linux, the board info and command line data
+ * have to be in the first 8 MB of memory, since this is
+ * the maximum mapped by the Linux kernel during initialization.
+ */
+#define CONFIG_SYS_BOOTMAPSZ		(8 << 20)
+
+/*-----------------------------------------------------------------------
+ * FLASH organization
+ */
+/* max number of memory banks */
+#define CONFIG_SYS_MAX_FLASH_BANKS	1
+#define CONFIG_SYS_FLASH_SIZE		32
+#define CONFIG_SYS_FLASH_CFI
+#define CONFIG_FLASH_CFI_DRIVER
+/* max num of sects on one chip */
+#define CONFIG_SYS_MAX_FLASH_SECT	256
+
+#define CONFIG_SYS_FLASH_ERASE_TOUT	120000	/* (in ms) */
+#define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* (in ms) */
+
+#define CONFIG_ENV_IS_IN_FLASH	1
+#define CONFIG_ENV_OFFSET	CONFIG_SYS_MONITOR_LEN
+#define CONFIG_ENV_SIZE		0x04000 /* Total Size of Environment Sector */
+#define CONFIG_ENV_SECT_SIZE	0x20000 /* Total Size of Environment Sector */
+
+/* Address and size of Redundant Environment Sector	*/
+#define CONFIG_ENV_OFFSET_REDUND	(CONFIG_ENV_OFFSET+CONFIG_ENV_SECT_SIZE)
+#define CONFIG_ENV_SIZE_REDUND	(CONFIG_ENV_SIZE)
+#define CONFIG_ENV_BUFFER_PRINT		1
+
+/*-----------------------------------------------------------------------
+ * Cache Configuration
+ */
+#define CONFIG_SYS_CACHELINE_SIZE	16	/* For all MPC8xx CPUs	*/
+#if defined(CONFIG_CMD_KGDB)
+#define CONFIG_SYS_CACHELINE_SHIFT	4	/* log base 2 of the above value */
+#endif
+
+/*-----------------------------------------------------------------------
+ * SYPCR - System Protection Control				11-9
+ * SYPCR can only be written once after reset!
+ *-----------------------------------------------------------------------
+ * Software & Bus Monitor Timer max, Bus Monitor enable, SW Watchdog freeze
+ */
+#define CONFIG_SYS_SYPCR	0xffffff89
+
+/*-----------------------------------------------------------------------
+ * SIUMCR - SIU Module Configuration				11-6
+ *-----------------------------------------------------------------------
+ */
+#if defined(CONFIG_MGSUVD)
+#define CONFIG_SYS_SIUMCR	0x00610480
+#else
+#define CONFIG_SYS_SIUMCR	0x00610400
+#endif
+
+/*-----------------------------------------------------------------------
+ * TBSCR - Time Base Status and Control				11-26
+ *-----------------------------------------------------------------------
+ * Clear Reference Interrupt Status, Timebase freezing enabled
+ */
+#define CONFIG_SYS_TBSCR	(TBSCR_REFA | TBSCR_REFB | TBSCR_TBF)
+
+/*-----------------------------------------------------------------------
+ * PISCR - Periodic Interrupt Status and Control		11-31
+ *-----------------------------------------------------------------------
+ * Clear Periodic Interrupt Status, Interrupt Timer freezing enabled
+ */
+#define CONFIG_SYS_PISCR	(PISCR_PS | PISCR_PITF)
+
+/*-----------------------------------------------------------------------
+ * SCCR - System Clock and reset Control Register		15-27
+ *-----------------------------------------------------------------------
+ * Set clock output, timebase and RTC source and divider,
+ * power management and some other internal clocks
+ */
+#if defined(CONFIG_MGSUVD)
+#define SCCR_MASK	0x01800000
+#else
+#define SCCR_MASK	0x00000000
+#endif
+#define CONFIG_SYS_SCCR	0x01800000
+
+#define CONFIG_SYS_DER 0
+
+/*
+ * Init Memory Controller:
+ *
+ * BR0/1 and OR0/1 (FLASH)
+ */
+
+#define FLASH_BASE0_PRELIM	0xf0000000	/* FLASH bank #0	*/
+
+/* used to re-map FLASH both when starting from SRAM or FLASH:
+ * restrict access enough to keep SRAM working (if any)
+ * but not too much to meddle with FLASH accesses
+ */
+#define CONFIG_SYS_REMAP_OR_AM		0x80000000	/* OR addr mask */
+#define CONFIG_SYS_PRELIM_OR_AM	0xE0000000	/* OR addr mask */
+
+/*
+ * FLASH timing: Default value of OR0 after reset
+ */
+#define CONFIG_SYS_OR0_PRELIM	0xfe000954
+#define CONFIG_SYS_BR0_PRELIM	0xf0000401
+
+/*
+ * BR1 and OR1 (SDRAM)
+ *
+ */
+#define SDRAM_BASE1_PRELIM	0x00000000	/* SDRAM bank #0	*/
+#define SDRAM_MAX_SIZE		(64 << 20)	/* max 64 MB per bank	*/
+
+/* SDRAM timing: Multiplexed addresses, GPL5 output to GPL5_A (don't care) */
+#define CONFIG_SYS_OR_TIMING_SDRAM	0x00000A00
+
+#define CONFIG_SYS_OR1_PRELIM	0xfc000800
+#define CONFIG_SYS_BR1_PRELIM	(0x000000C0 | 0x01)
+
+#define CONFIG_SYS_MPTPR	0x0200
+/* PTB=16, AMB=001, FIXME 1 RAS precharge cycles, 1 READ loop cycle (not used),
+   1 Write loop Cycle (not used), 1 Timer Loop Cycle */
+#if defined(CONFIG_MGSUVD)
+#define CONFIG_SYS_MBMR	0x10964111
+#else
+#define CONFIG_SYS_MBMR	0x20964111
+#endif
+#define CONFIG_SYS_MAR		0x00000088
+
+/*
+ * 4096	Rows from SDRAM example configuration
+ * 1000	factor s -> ms
+ * 64	PTP (pre-divider from MPTPR) from SDRAM example configuration
+ * 4	Number of refresh cycles per period
+ * 64	Refresh cycle in ms per number of rows
+ */
+#define CONFIG_SYS_PTA_PER_CLK	((4096 * 64 * 1000) / (4 * 64))
+
+/* GPIO/PIGGY on CS3 initialization values
+*/
+#define CONFIG_SYS_PIGGY_BASE	(0x30000000)
+#if defined(CONFIG_MGSUVD)
+#define CONFIG_SYS_OR3_PRELIM	(0xfe000d24)
+#define CONFIG_SYS_BR3_PRELIM	(0x30000401)
+#else
+#define CONFIG_SYS_OR3_PRELIM	(0xf8000d26)
+#define CONFIG_SYS_BR3_PRELIM	(0x30000401)
+#endif
+
+/*
+ * Internal Definitions
+ *
+ * Boot Flags
+ */
+#define BOOTFLAG_COLD	0x01	/* Normal Power-On: Boot from FLASH */
+#define BOOTFLAG_WARM	0x02	/* Software reboot		    */
+
+#define CONFIG_SCC3_ENET
+#define CONFIG_ETHPRIME		"SCC ETHERNET"
+#define CONFIG_HAS_ETH0
+
+/* pass open firmware flat tree */
+#define CONFIG_OF_LIBFDT	1
+#define CONFIG_OF_BOARD_SETUP	1
+
+#define OF_STDOUT_PATH		"/soc/cpm/serial@a80"
+
+/* enable I2C and select the hardware/software driver */
+#undef	CONFIG_HARD_I2C			/* I2C with hardware support */
+#define	CONFIG_SOFT_I2C		1	/* I2C bit-banged	*/
+/* I2C speed and slave address */
+#define CONFIG_SYS_I2C_SPEED		50000
+#define CONFIG_SYS_I2C_SLAVE		0x7F
+#define I2C_SOFT_DECLARATIONS
+
+/*
+ * Software (bit-bang) I2C driver configuration
+ */
+#define I2C_BASE_DIR	((u16 *)(CONFIG_SYS_PIGGY_BASE + 0x04))
+#define I2C_BASE_PORT	((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x09))
+
+#define SDA_BIT		0x40
+#define SCL_BIT		0x80
+#define SDA_CONF	0x1000
+#define SCL_CONF	0x2000
+
+#define I2C_ACTIVE	do {} while (0)
+#define I2C_TRISTATE	do {} while (0)
+#define I2C_READ	((in_8(I2C_BASE_PORT) & SDA_BIT) == SDA_BIT)
+#define I2C_SDA(bit)	if(bit) { \
+				clrbits(be16, I2C_BASE_DIR, SDA_CONF); \
+			} else { \
+				clrbits(8, I2C_BASE_PORT, SDA_BIT); \
+				setbits(be16, I2C_BASE_DIR, SDA_CONF); \
+			}
+#define I2C_SCL(bit)	if(bit) { \
+				clrbits(be16, I2C_BASE_DIR, SCL_CONF); \
+			} else { \
+				clrbits(8, I2C_BASE_PORT, SCL_BIT); \
+				setbits(be16, I2C_BASE_DIR, SCL_CONF); \
+			}
+#define I2C_DELAY	udelay(50)	/* 1/4 I2C clock duration */
+
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
+
+/* I2C SYSMON (LM75, AD7414 is almost compatible)		*/
+#define CONFIG_DTT_LM75		1	/* ON Semi's LM75	*/
+#if defined(CONFIG_MGSUVD)
+#define CONFIG_DTT_SENSORS	{0, 2, 4, 6}	/* Sensor addresses */
+#else
+#define CONFIG_DTT_SENSORS	{0}	/* Sensor addresses */
+#endif
+#define CONFIG_SYS_DTT_MAX_TEMP	70
+#define CONFIG_SYS_DTT_LOW_TEMP	-30
+#define CONFIG_SYS_DTT_HYSTERESIS	3
+#define CONFIG_SYS_DTT_BUS_NUM		(CONFIG_SYS_MAX_I2C_BUS)
+#endif	/* __CONFIG_KM8XX_H */
diff --git a/include/configs/kmeter1.h b/include/configs/kmeter1.h
index b86c61d..f7fc6c5 100644
--- a/include/configs/kmeter1.h
+++ b/include/configs/kmeter1.h
@@ -28,10 +28,13 @@
 #define CONFIG_MPC83XX		1 /* MPC83XX family */
 #define CONFIG_MPC8360		1 /* MPC8360 CPU specific */
 #define CONFIG_KMETER1		1 /* KMETER1 board specific */
+#define CONFIG_HOSTNAME		kmeter1
 
 /* include common defines/options for all Keymile boards */
 #include "keymile-common.h"
 
+#undef CONFIG_SYS_I2C_INIT_BOARD
+#define CONFIG_MISC_INIT_R	1
 /*
  * System Clock Setup
  */
@@ -51,10 +54,11 @@
 #define CONFIG_SYS_HRCW_HIGH (\
 	HRCWH_CORE_ENABLE | \
 	HRCWH_FROM_0X00000100 | \
-	HRCWH_BOOTSEQ_NORMAL | \
+	HRCWH_BOOTSEQ_DISABLE | \
 	HRCWH_SW_WATCHDOG_DISABLE | \
 	HRCWH_ROM_LOC_LOCAL_16BIT | \
 	HRCWH_BIG_ENDIAN | \
+	HRCWH_LALE_EARLY | \
 	HRCWH_LDP_CLEAR )
 
 /*
@@ -91,8 +95,8 @@
  * Manually set up DDR parameters
  */
 #define CONFIG_DDR_II
-#define CONFIG_SYS_DDR_SIZE		256 /* MB */
-#define CONFIG_SYS_DDR_CS0_BNDS		0x0000000f
+#define CONFIG_SYS_DDR_SIZE		2048 /* MB */
+#define CONFIG_SYS_DDR_CS0_BNDS		0x0000007f
 #define CONFIG_SYS_DDR_CS0_CONFIG	(CSCONFIG_EN | CSCONFIG_AP | \
 					 CSCONFIG_ROW_BIT_13 | \
 					 CSCONFIG_COL_BIT_10 | CSCONFIG_ODT_WR_ACS)
@@ -101,11 +105,12 @@
 					 SDRAM_CFG_SREN)
 #define CONFIG_SYS_DDR_SDRAM_CFG2	0x00401000
 #define CONFIG_SYS_DDR_CLK_CNTL	(DDR_SDRAM_CLK_CNTL_CLK_ADJUST_05)
-#define CONFIG_SYS_DDR_INTERVAL	((0x100 << SDRAM_INTERVAL_BSTOPRE_SHIFT) | \
-				 (0x406 << SDRAM_INTERVAL_REFINT_SHIFT))
+#define CONFIG_SYS_DDR_INTERVAL	((0x080 << SDRAM_INTERVAL_BSTOPRE_SHIFT) | \
+				 (0x3cf << SDRAM_INTERVAL_REFINT_SHIFT))
 
-#define CONFIG_SYS_DDR_MODE		0x04440242
-#define CONFIG_SYS_DDR_MODE2		0x00800000
+#define	CONFIG_SYS_DDRCDR		0x40000001
+#define CONFIG_SYS_DDR_MODE		0x47860452
+#define CONFIG_SYS_DDR_MODE2		0x8080c000
 
 #define CONFIG_SYS_DDR_TIMING_0	((2 << TIMING_CFG0_MRS_CYC_SHIFT) | \
 				 (8 << TIMING_CFG0_ODT_PD_EXIT_SHIFT) | \
@@ -116,22 +121,22 @@
 				 (0 << TIMING_CFG0_WRT_SHIFT) | \
 				 (0 << TIMING_CFG0_RWT_SHIFT))
 
-#define CONFIG_SYS_DDR_TIMING_1	((      TIMING_CFG1_CASLAT_40) | \
+#define CONFIG_SYS_DDR_TIMING_1	((      TIMING_CFG1_CASLAT_50) | \
 				 ( 2 << TIMING_CFG1_WRTORD_SHIFT) | \
-				 ( 1 << TIMING_CFG1_ACTTOACT_SHIFT) | \
-				 ( 2 << TIMING_CFG1_WRREC_SHIFT) | \
-				 ( 2 << TIMING_CFG1_REFREC_SHIFT) | \
-				 ( 2 << TIMING_CFG1_ACTTORW_SHIFT) | \
-				 ( 6 << TIMING_CFG1_ACTTOPRE_SHIFT) | \
-				 ( 2 << TIMING_CFG1_PRETOACT_SHIFT))
+				 ( 2 << TIMING_CFG1_ACTTOACT_SHIFT) | \
+				 ( 3 << TIMING_CFG1_WRREC_SHIFT) | \
+				 ( 7 << TIMING_CFG1_REFREC_SHIFT) | \
+				 ( 3 << TIMING_CFG1_ACTTORW_SHIFT) | \
+				 ( 8 << TIMING_CFG1_ACTTOPRE_SHIFT) | \
+				 ( 3 << TIMING_CFG1_PRETOACT_SHIFT))
 
-#define CONFIG_SYS_DDR_TIMING_2	((5 << TIMING_CFG2_FOUR_ACT_SHIFT) | \
+#define CONFIG_SYS_DDR_TIMING_2	((8 << TIMING_CFG2_FOUR_ACT_SHIFT) | \
 				 (3 << TIMING_CFG2_CKE_PLS_SHIFT) | \
 				 (2 << TIMING_CFG2_WR_DATA_DELAY_SHIFT) | \
-				 (1 << TIMING_CFG2_RD_TO_PRE_SHIFT) | \
-				 (3 << TIMING_CFG2_WR_LAT_DELAY_SHIFT) | \
+				 (2 << TIMING_CFG2_RD_TO_PRE_SHIFT) | \
+				 (4 << TIMING_CFG2_WR_LAT_DELAY_SHIFT) | \
 				 (0 << TIMING_CFG2_ADD_LAT_SHIFT) | \
-				 (4 << TIMING_CFG2_CPO_SHIFT))
+				 (5 << TIMING_CFG2_CPO_SHIFT))
 
 #define CONFIG_SYS_DDR_TIMING_3	0x00000000
 
@@ -141,9 +146,10 @@
 #define CONFIG_SYS_MONITOR_BASE	TEXT_BASE /* start of monitor */
 #define CONFIG_SYS_FLASH_BASE		0xF0000000
 #define CONFIG_SYS_FLASH_BASE_1		0xF2000000
-#define CONFIG_SYS_PIGGY_BASE		0x80000000
+#define CONFIG_SYS_PIGGY_BASE		0xE8000000
+#define	CONFIG_SYS_PIGGY_SIZE		128
 #define CONFIG_SYS_PAXE_BASE		0xA0000000
-#define	CONFIG_SYS_PAXE_SIZE		256
+#define	CONFIG_SYS_PAXE_SIZE		512
 
 #if (CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE)
 #define CONFIG_SYS_RAMBOOT
@@ -151,7 +157,7 @@
 #undef	CONFIG_SYS_RAMBOOT
 #endif
 
-#define CONFIG_SYS_MONITOR_LEN		(256 * 1024) /* Reserve 256 kB for Mon */
+#define CONFIG_SYS_MONITOR_LEN		(384 * 1024) /* Reserve 256 kB for Mon */
 #define CONFIG_SYS_MALLOC_LEN		(128 * 1024) /* Reserved for malloc */
 
 /*
@@ -174,8 +180,8 @@
  * Bank Bus     Machine PortSz  Size  Device
  * ---- ---     ------- ------  -----  ------
  *  0   Local   GPCM    16 bit  256MB FLASH
- *  1   Local   GPCM     8 bit  256KB GPIO/PIGGY
- *  3   Local   GPCM     8 bit  256MB PAXE
+ *  1   Local   GPCM     8 bit  128MB GPIO/PIGGY
+ *  3   Local   GPCM     8 bit  512MB PAXE
  *
  */
 /*
@@ -209,12 +215,12 @@
  * PRIO1/PIGGY on the local bus CS1
  */
 #define CONFIG_SYS_LBLAWBAR1_PRELIM	CONFIG_SYS_PIGGY_BASE /* Window base at flash base */
-#define CONFIG_SYS_LBLAWAR1_PRELIM	0x80000011 /* 256KB window size */
+#define CONFIG_SYS_LBLAWAR1_PRELIM	0x8000001A /* 128MB window size */
 
 #define CONFIG_SYS_BR1_PRELIM	(CONFIG_SYS_PIGGY_BASE | \
 				(1 << BR_PS_SHIFT) | /* 8 bit port size */ \
 				BR_V)
-#define CONFIG_SYS_OR1_PRELIM		(0xfffc0000 | /* 256KB */ \
+#define CONFIG_SYS_OR1_PRELIM		(MEG_TO_AM(CONFIG_SYS_PIGGY_SIZE) | /* 128MB */ \
 				OR_GPCM_CSNT | OR_GPCM_ACS_DIV2 | \
 				OR_GPCM_SCY_2 | \
 				OR_GPCM_TRLX | OR_GPCM_EAD)
@@ -223,7 +229,7 @@
  * PAXE on the local bus CS3
  */
 #define CONFIG_SYS_LBLAWBAR3_PRELIM	CONFIG_SYS_PAXE_BASE /* Window base at flash base */
-#define CONFIG_SYS_LBLAWAR3_PRELIM	0x8000001b /* 256MB window size */
+#define CONFIG_SYS_LBLAWAR3_PRELIM	0x8000001C /* 512MB window size */
 
 #define CONFIG_SYS_BR3_PRELIM	(CONFIG_SYS_PAXE_BASE | \
 				(1 << BR_PS_SHIFT) | /* 8 bit port size */ \
@@ -296,10 +302,33 @@
 #else /* CFG_RAMBOOT */
 #define CONFIG_SYS_NO_FLASH		1	/* Flash is not usable now */
 #define CONFIG_ENV_IS_NOWHERE	1	/* Store ENV in memory only */
-#define CONFIG_ENV_ADDR		(CFG_MONITOR_BASE - 0x1000)
+#define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE - 0x1000)
 #define CONFIG_ENV_SIZE		0x2000
 #endif /* CFG_RAMBOOT */
 
+/* I2C */
+#define CONFIG_HARD_I2C		/* I2C with hardware support */
+#undef	CONFIG_SOFT_I2C		/* I2C bit-banged */
+#define CONFIG_FSL_I2C
+#define CONFIG_SYS_I2C_SPEED	200000	/* I2C speed and slave address */
+#define CONFIG_SYS_I2C_SLAVE	0x7F
+#define CONFIG_SYS_I2C_OFFSET	0x3000
+#define CONFIG_I2C_MULTI_BUS	1
+#define CONFIG_I2C_CMD_TREE	1
+#define CONFIG_SYS_MAX_I2C_BUS		2
+#define CONFIG_I2C_MUX		1
+
+/* EEprom support */
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	2
+
+/* I2C SYSMON (LM75, AD7414 is almost compatible)			*/
+#define CONFIG_DTT_LM75		1	/* ON Semi's LM75		*/
+#define CONFIG_DTT_SENSORS	{0, 1, 2, 3}	/* Sensor addresses		*/
+#define CONFIG_SYS_DTT_MAX_TEMP	70
+#define CONFIG_SYS_DTT_LOW_TEMP	-30
+#define CONFIG_SYS_DTT_HYSTERESIS	3
+#define CONFIG_SYS_DTT_BUS_NUM		(2)
+
 #if defined(CONFIG_PCI)
 #define CONFIG_CMD_PCI
 #endif
@@ -345,7 +374,7 @@
 
 /* PRIO1, PIGGY:  icache cacheable, but dcache-inhibit and guarded */
 #define CONFIG_SYS_IBAT2L	(CONFIG_SYS_PIGGY_BASE | BATL_PP_10 | BATL_MEMCOHERENCE)
-#define CONFIG_SYS_IBAT2U	(CONFIG_SYS_PIGGY_BASE | BATU_BL_256K | BATU_VS | BATU_VP)
+#define CONFIG_SYS_IBAT2U	(CONFIG_SYS_PIGGY_BASE | BATU_BL_128M | BATU_VS | BATU_VP)
 #define CONFIG_SYS_DBAT2L	(CONFIG_SYS_PIGGY_BASE | BATL_PP_10 | \
 				 BATL_CACHEINHIBIT | BATL_GUARDEDSTORAGE)
 #define CONFIG_SYS_DBAT2U	CONFIG_SYS_IBAT2U
@@ -365,7 +394,7 @@
 
 /* PAXE:  icache cacheable, but dcache-inhibit and guarded */
 #define CONFIG_SYS_IBAT5L	(CONFIG_SYS_PAXE_BASE | BATL_PP_10 | BATL_MEMCOHERENCE)
-#define CONFIG_SYS_IBAT5U	(CONFIG_SYS_PAXE_BASE | BATU_BL_256K | BATU_VS | BATU_VP)
+#define CONFIG_SYS_IBAT5U	(CONFIG_SYS_PAXE_BASE | BATU_BL_256M | BATU_VS | BATU_VP)
 #define CONFIG_SYS_DBAT5L	(CONFIG_SYS_PAXE_BASE | BATL_PP_10 | \
 				 BATL_CACHEINHIBIT | BATL_GUARDEDSTORAGE)
 #define CONFIG_SYS_DBAT5U	CONFIG_SYS_IBAT5U
@@ -401,57 +430,44 @@
 #define BOOTFLAG_COLD	0x01 /* Normal Power-On: Boot from FLASH */
 #define BOOTFLAG_WARM	0x02 /* Software reboot */
 
+#define BOOTFLASH_START	F0000000
+
+#define CONFIG_PRAM	512	/* protected RAM [KBytes] */
+
+#define MTDIDS_DEFAULT		"nor0=app"
+#define MTDPARTS_DEFAULT \
+	"mtdparts=app:256k(u-boot),128k(env),128k(envred),"	\
+	"1536k(esw0),8704k(rootfs0),1536k(esw1),2432k(rootfs1),640k(var),768k(cfg)"
+
 /*
  * Environment Configuration
  */
 #define CONFIG_ENV_OVERWRITE
+#ifndef CONFIG_KM_DEF_ENV		/* if not set by keymile-common.h */
+#define CONFIG_KM_DEF_ENV "km-common=empty\0"
+#endif
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+       CONFIG_KM_DEF_ENV						\
+	"rootpath=/opt/eldk/ppc_82xx\0"					\
+	"addcon=setenv bootargs ${bootargs} console=ttyS0,${baudrate}\0"\
+	"ramdisk_file=/tftpboot/kmeter1/uRamdisk\0"			\
+	"loadram=tftp ${ramdisk_addr_r} ${ramdisk_file}\0"		\
+	"loadfdt=tftp ${fdt_addr_r} ${fdt_file}\0"			\
+	"loadkernel=tftp ${kernel_addr_r} ${bootfile}\0"		\
+	"unlock=yes\0"							\
+	"fdt_addr=F0080000\0"						\
+	"kernel_addr=F00a0000\0"					\
+	"ramdisk_addr=F03a0000\0"					\
+	"ramdisk_addr_r=F10000\0"					\
+	"EEprom_ivm=pca9547:70:9\0"					\
+	"dtt_bus=pca9547:70:a\0"					\
+	"mtdids=nor0=app \0"						\
+	"mtdparts=" MK_STR(MTDPARTS_DEFAULT) "\0"			\
+   ""
 
 #if defined(CONFIG_UEC_ETH)
 #define CONFIG_HAS_ETH0
 #endif
 
-#define CONFIG_EXTRA_ENV_SETTINGS \
-	"netdev=eth0\0"							\
-	"rootpath=/opt/eldk/ppc_82xx\0"					\
-	"nfsargs=setenv bootargs root=/dev/nfs rw "			\
-		"nfsroot=${serverip}:${rootpath}\0"			\
-	"ramargs=setenv bootargs root=/dev/ram rw\0"			\
-	"addip=setenv bootargs ${bootargs} "				\
-		"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}"	\
-		":${hostname}:${netdev}:off panic=1\0"			\
-	"addtty=setenv bootargs ${bootargs}"				\
-		" console=ttyS0,${baudrate}\0"				\
-	"fdt_addr=f0080000\0"						\
-	"kernel_addr=f00a0000\0"					\
-	"ramdisk_addr=f03a0000\0"					\
-	"kernel_addr_r=400000\0"					\
-	"fdt_addr_r=800000\0"						\
-	"ramdisk_addr_r=810000\0"					\
-	"flash_self=run ramargs addip addtty;"				\
-		"bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"	\
-	"flash_nfs=run nfsargs addip addtty;"				\
-		"bootm ${kernel_addr} - ${fdt_addr}\0"			\
-	"net_nfs=tftp ${kernel_addr_r} ${boot_file}; "			\
-		"tftp ${fdt_addr_r} ${fdt_file}; "			\
-		"run nfsargs addip addtty;"				\
-		"bootm ${kernel_addr_r} - ${fdt_addr_r}\0"		\
-	"fdt_file=/tftpboot/kmeter1/kmeter1.dtb\0"			\
-	"boot_file=/tftpboot/kmeter1/uImage\0"				\
-	"ramdisk_file=/tftpboot/kmeter1/uRamdisk\0"			\
-	"u-boot=/tftpboot/kmeter1/u-boot.bin\0"				\
-	"loadaddr=" MK_STR(CONFIG_SYS_LOAD_ADDR) "\0"			\
-	"load=tftp $loadaddr ${u-boot}\0"				\
-	"update=protect off " MK_STR(TEXT_BASE) " +$filesize;"		\
-		"erase " MK_STR(TEXT_BASE) " +$filesize;"		\
-		"cp.b $loadaddr " MK_STR(TEXT_BASE) " $filesize;"	\
-		"protect on " MK_STR(TEXT_BASE) " +$filesize;"		\
-		"cmp.b $loadaddr " MK_STR(TEXT_BASE) " $filesize;"	\
-		"setenv filesize;saveenv\0"				\
-	"upd=run load update\0"						\
-	"loadram=tftp ${ramdisk_addr_r} ${ramdisk_file}\0"		\
-	"loadfdt=tftp ${fdt_addr_r} ${fdt_file}\0"			\
-	"loadkernel=tftp ${kernel_addr_r} ${boot_file}\0"		\
-	"unlock=yes\0"							\
-   ""
-
 #endif /* __CONFIG_H */
diff --git a/include/configs/kmsupx4.h b/include/configs/kmsupx4.h
new file mode 100644
index 0000000..8f1e602
--- /dev/null
+++ b/include/configs/kmsupx4.h
@@ -0,0 +1,41 @@
+/*
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs@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
+ */
+
+/*
+ * board/config.h - configuration options, board specific
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_MPC852T		1	/* This is a MPC852T CPU	*/
+#define CONFIG_KMSUPX4		1	/* ...on a kmsupx4 board	*/
+#define CONFIG_HOSTNAME		kmsupx4
+
+/* include common defines/options for all Keymile 8xx boards */
+#include "km8xx.h"
+
+#define CONFIG_SYS_DELAYED_ICACHE	1	/* enable ICache not before
+						 * running in RAM.
+						 */
+#endif	/* __CONFIG_H */
diff --git a/include/configs/mgcoge.h b/include/configs/mgcoge.h
index 79c7050..cc42101 100644
--- a/include/configs/mgcoge.h
+++ b/include/configs/mgcoge.h
@@ -86,39 +86,24 @@
 	"mtdparts=boot:384k(u-boot),128k(env),128k(envred),3456k(free);" \
 	"app:3m(esw0),10m(rootfs0),3m(esw1),10m(rootfs1),1m(var),5m(cfg)"
 
+#ifndef CONFIG_KM_DEF_ENV		/* if not set by keymile-common.h */
+#define CONFIG_KM_DEF_ENV "km-common=empty\0"
+#endif
 /*
  * Default environment settings
  */
-#define CONFIG_EXTRA_ENV_SETTINGS						\
-	"netdev=eth0\0"								\
-	"u-boot_addr=100000\0"							\
-	"kernel_addr=200000\0"							\
-	"fdt_addr=400000\0"							\
-	"rootpath=/opt/eldk-4.2/ppc_82xx\0"					\
-	"u-boot=/tftpboot/mgcoge/u-boot.bin\0"					\
-	"bootfile=/tftpboot/mgcoge/uImage\0"					\
-	"fdt_file=/tftpboot/mgcoge/mgcoge.dtb\0"				\
-	"load=tftp ${u-boot_addr} ${u-boot}\0"					\
-	"update=prot off fe000000 fe03ffff; era fe000000 fe03ffff; "		\
-		"cp.b ${u-boot_addr} fe000000 ${filesize};"			\
-		"prot on fe000000 fe03ffff\0"					\
-	"ramargs=setenv bootargs root=/dev/ram rw\0"				\
-	"nfsargs=setenv bootargs root=/dev/nfs rw "				\
-		"nfsroot=${serverip}:${rootpath}\0"				\
-	"addcons=setenv bootargs ${bootargs} console=ttyCPM0,${baudrate}\0"	\
-	"addmtd=setenv bootargs ${bootargs} ${mtdparts}\0"			\
-	"addip=setenv bootargs ${bootargs} "					\
-		"ip=${ipaddr}:${serverip}:${gatewayip}:"			\
-		"${netmask}:${hostname}:${netdev}:off panic=1\0"		\
-	"net_nfs=tftp ${kernel_addr} ${bootfile}; "				\
-		"tftp ${fdt_addr} ${fdt_file}; run nfsargs addip addcons;"	\
-		"bootm ${kernel_addr} - ${fdt_addr}\0"				\
-	"net_self=tftp ${kernel_addr} ${bootfile}; "				\
-		"tftp ${fdt_addr} ${fdt_file}; "				\
-		"tftp ${ramdisk_addr} ${ramdisk_file}; "			\
-		"run ramargs addip; "						\
-		"bootm ${kernel_addr} ${ramdisk_addr} ${fdt_addr}\0"		\
-	"EEprom_ivm=pca9544a:70:4 \0"						\
+#define	CONFIG_EXTRA_ENV_SETTINGS	\
+	CONFIG_KM_DEF_ENV						\
+	"rootpath=/opt/eldk/ppc_82xx\0"					\
+	"addcon=setenv bootargs ${bootargs} "				\
+		"console=ttyCPM0,${baudrate}\0"				\
+	"mtdids=nor0=boot,nor1=app \0"					\
+	"mtdparts=mtdparts=boot:384k(u-boot),128k(env),128k(envred),"	\
+		"3456k(free);app:3m(esw0),10m(rootfs0),3m(esw1),"	\
+		"10m(rootfs1),1m(var),5m(cfg) \0"			\
+	"partition=nor1,5 \0"						\
+	"new_env=prot off FE060000 FE09FFFF; era FE060000 FE09FFFF \0" 	\
+	"EEprom_ivm=pca9544a:70:4 \0"					\
 	"mtdparts=" MK_STR(MTDPARTS_DEFAULT) "\0"				\
 	""
 
@@ -140,12 +125,12 @@
 #define CONFIG_SYS_RAMBOOT
 #endif
 
-#define CONFIG_SYS_MONITOR_LEN		(384 << 10)     /* Reserve 384KB for Monitor */
+#define CONFIG_SYS_MONITOR_LEN		(384 << 10)	/* Reserve 384KB for Monitor */
 
 #define CONFIG_ENV_IS_IN_FLASH
 
 #ifdef CONFIG_ENV_IS_IN_FLASH
-#define CONFIG_ENV_SECT_SIZE	0x4000
+#define CONFIG_ENV_SECT_SIZE	0x20000
 #define CONFIG_ENV_ADDR		(CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
 #define CONFIG_ENV_OFFSET	CONFIG_SYS_MONITOR_LEN
 
@@ -175,24 +160,6 @@
 			else    iop->pdat &= ~0x00020000
 #define I2C_DELAY	udelay(5)	/* 1/4 I2C clock duration */
 
-#define CONFIG_I2C_MULTI_BUS	1
-#define CONFIG_I2C_CMD_TREE	1
-#define CONFIG_SYS_MAX_I2C_BUS		2
-#define CONFIG_SYS_I2C_INIT_BOARD	1
-#define CONFIG_I2C_MUX		1
-
-/* EEprom support */
-#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
-#define CONFIG_SYS_I2C_MULTI_EEPROMS	1
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_ENABLE
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 10
-
-/* Support the IVM EEprom */
-#define	CONFIG_SYS_IVM_EEPROM_ADR	0x50
-#define CONFIG_SYS_IVM_EEPROM_MAX_LEN	0x400
-#define CONFIG_SYS_IVM_EEPROM_PAGE_LEN	0x100
-
 /* I2C SYSMON (LM75, AD7414 is almost compatible)			*/
 #define CONFIG_DTT_LM75		1	/* ON Semi's LM75		*/
 #define CONFIG_DTT_SENSORS	{0}	/* Sensor addresses		*/
diff --git a/include/configs/mgsuvd.h b/include/configs/mgsuvd.h
index 4623e4c..1618f7d 100644
--- a/include/configs/mgsuvd.h
+++ b/include/configs/mgsuvd.h
@@ -28,312 +28,11 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * High Level Configuration Options
- * (easy to change)
- */
-
 #define CONFIG_MPC866		1	/* This is a MPC866 CPU		*/
 #define CONFIG_MGSUVD		1	/* ...on a mgsuvd board	*/
 #define CONFIG_HOSTNAME		mgsuvd
 
-/* include common defines/options for all Keymile boards */
-#include "keymile-common.h"
-
-#define CONFIG_8xx_GCLK_FREQ		66000000
-
-#define CONFIG_SYS_SMC_UCODE_PATCH	1	/* Relocate SMC1 */
-#define CONFIG_SYS_SMC_DPMEM_OFFSET	0x1fc0
-#define CONFIG_8xx_CONS_SMC1	1	/* Console is on SMC1		*/
-#define CONFIG_SYS_SMC_RXBUFLEN	128
-#define CONFIG_SYS_MAXIDLE	10
-
-#define CONFIG_SYS_CPM_BOOTCOUNT_ADDR	0x1eb0	/* In case of SMC relocation, the
-					 * default value is not working */
-
-#define BOOTFLASH_START	F0000000
-#define CONFIG_PRAM	512	/* protected RAM [KBytes] */
-
-#define CONFIG_PREBOOT	"echo;" \
-	"echo Type \\\"run flash_nfs\\\" to mount root filesystem over NFS;" \
-	"echo"
-
-#define CONFIG_EXTRA_ENV_SETTINGS						\
-	"netdev=eth0\0"								\
-	"addcons=setenv bootargs ${bootargs} console=ttyCPM0,${baudrate}\0"	\
-	"nfsargs=setenv bootargs root=/dev/nfs rw "				\
-		"nfsroot=${serverip}:${rootpath}\0"				\
-	"ramargs=setenv bootargs root=/dev/ram rw\0"				\
-	"addip=setenv bootargs ${bootargs} "					\
-		"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}"		\
-		":${hostname}:${netdev}:off panic=1\0"				\
-	"flash_nfs=run nfsargs addip;"						\
-		"bootm ${kernel_addr}\0"					\
-	"flash_self=run ramargs addip;"						\
-		"bootm ${kernel_addr} ${ramdisk_addr}\0"			\
-	"net_nfs=tftp ${kernel_addr} ${bootfile}; "				\
-		"tftp ${fdt_addr} ${fdt_file}; run nfsargs addip addcons;"	\
-		"bootm ${kernel_addr} - ${fdt_addr}\0"				\
-	"rootpath=/opt/eldk/ppc_8xx\0"						\
-	"bootfile=/tftpboot/mgsuvd/uImage\0"					\
-	"fdt_addr=400000\0"							\
-	"kernel_addr=200000\0"							\
-	"fdt_file=/tftpboot/mgsuvd/mgsuvd.dtb\0"				\
-	"load=tftp 200000 ${u-boot}\0"						\
-	"update=protect off f0000000 +${filesize};"				\
-		"erase f0000000 +${filesize};"					\
-		"cp.b 200000 f0000000 ${filesize};"				\
-		"protect on f0000000 +${filesize}\0"				\
-	""
-
-#undef CONFIG_RTC_MPC8xx		/* MPC866 does not support RTC	*/
-
-#define	CONFIG_TIMESTAMP		/* but print image timestmps	*/
-
-/*
- * Low Level Configuration Settings
- * (address mappings, register initial values, etc.)
- * You should know what you are doing if you make changes here.
- */
-/*-----------------------------------------------------------------------
- * Internal Memory Mapped Register
- */
-#define CONFIG_SYS_IMMR		0xFFF00000
-
-/*-----------------------------------------------------------------------
- * Definitions for initial stack pointer and data area (in DPRAM)
- */
-#define CONFIG_SYS_INIT_RAM_ADDR	CONFIG_SYS_IMMR
-#define CONFIG_SYS_INIT_RAM_END	0x2F00	/* End of used area in DPRAM	*/
-#define CONFIG_SYS_GBL_DATA_SIZE	64  /* size in bytes reserved for initial data */
-#define CONFIG_SYS_GBL_DATA_OFFSET	(CONFIG_SYS_INIT_RAM_END - CONFIG_SYS_GBL_DATA_SIZE)
-#define CONFIG_SYS_INIT_SP_OFFSET	CONFIG_SYS_GBL_DATA_OFFSET
-
-/*-----------------------------------------------------------------------
- * Start addresses for the final memory configuration
- * (Set up by the startup code)
- * Please note that CONFIG_SYS_SDRAM_BASE _must_ start at 0
- */
-#define CONFIG_SYS_SDRAM_BASE		0x00000000
-#define CONFIG_SYS_FLASH_BASE		0xf0000000
-#define CONFIG_SYS_MONITOR_LEN		(384 << 10)	/* Reserve 384 kB for Monitor	*/
-#define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_FLASH_BASE
-#define CONFIG_SYS_MALLOC_LEN		(256 << 10)	/* Reserve 256 kB for malloc()	*/
-
-/*
- * For booting Linux, the board info and command line data
- * have to be in the first 8 MB of memory, since this is
- * the maximum mapped by the Linux kernel during initialization.
- */
-#define CONFIG_SYS_BOOTMAPSZ		(8 << 20)	/* Initial Memory map for Linux */
-
-/*-----------------------------------------------------------------------
- * FLASH organization
- */
-#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* max number of memory banks		*/
-#define CONFIG_SYS_FLASH_SIZE		32
-#define CONFIG_SYS_FLASH_CFI
-#define CONFIG_FLASH_CFI_DRIVER
-#define CONFIG_SYS_MAX_FLASH_SECT	256	/* max num of sects on one chip */
-
-
-#define CONFIG_SYS_FLASH_ERASE_TOUT	120000	/* Timeout for Flash Erase (in ms)	*/
-#define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* Timeout for Flash Write (in ms)	*/
-
-#define CONFIG_ENV_IS_IN_FLASH	1
-#define CONFIG_ENV_OFFSET	CONFIG_SYS_MONITOR_LEN
-#define CONFIG_ENV_SIZE		0x04000 /* Total Size of Environment Sector	*/
-#define CONFIG_ENV_SECT_SIZE	0x20000 /* Total Size of Environment Sector	*/
-
-/* Address and size of Redundant Environment Sector	*/
-#define CONFIG_ENV_OFFSET_REDUND	(CONFIG_ENV_OFFSET+CONFIG_ENV_SECT_SIZE)
-#define CONFIG_ENV_SIZE_REDUND	(CONFIG_ENV_SIZE)
-#define CONFIG_ENV_BUFFER_PRINT		1
-
-/*-----------------------------------------------------------------------
- * Cache Configuration
- */
-#define CONFIG_SYS_CACHELINE_SIZE	16	/* For all MPC8xx CPUs			*/
-#if defined(CONFIG_CMD_KGDB)
-#define CONFIG_SYS_CACHELINE_SHIFT	4	/* log base 2 of the above value	*/
-#endif
-
-/*-----------------------------------------------------------------------
- * SYPCR - System Protection Control				11-9
- * SYPCR can only be written once after reset!
- *-----------------------------------------------------------------------
- * Software & Bus Monitor Timer max, Bus Monitor enable, SW Watchdog freeze
- */
-#define CONFIG_SYS_SYPCR	0xffffff89
-
-/*-----------------------------------------------------------------------
- * SIUMCR - SIU Module Configuration				11-6
- *-----------------------------------------------------------------------
- */
-#define CONFIG_SYS_SIUMCR	0x00610480
-
-/*-----------------------------------------------------------------------
- * TBSCR - Time Base Status and Control				11-26
- *-----------------------------------------------------------------------
- * Clear Reference Interrupt Status, Timebase freezing enabled
- */
-#define CONFIG_SYS_TBSCR	(TBSCR_REFA | TBSCR_REFB | TBSCR_TBF)
-
-/*-----------------------------------------------------------------------
- * PISCR - Periodic Interrupt Status and Control		11-31
- *-----------------------------------------------------------------------
- * Clear Periodic Interrupt Status, Interrupt Timer freezing enabled
- */
-#define CONFIG_SYS_PISCR	(PISCR_PS | PISCR_PITF)
-
-/*-----------------------------------------------------------------------
- * SCCR - System Clock and reset Control Register		15-27
- *-----------------------------------------------------------------------
- * Set clock output, timebase and RTC source and divider,
- * power management and some other internal clocks
- */
-#define SCCR_MASK	0x01800000
-#define CONFIG_SYS_SCCR	0x01800000
-
-#define CONFIG_SYS_DER 0
-
-/*
- * Init Memory Controller:
- *
- * BR0/1 and OR0/1 (FLASH)
- */
-
-#define FLASH_BASE0_PRELIM	0xf0000000	/* FLASH bank #0	*/
-
-/* used to re-map FLASH both when starting from SRAM or FLASH:
- * restrict access enough to keep SRAM working (if any)
- * but not too much to meddle with FLASH accesses
- */
-#define CONFIG_SYS_REMAP_OR_AM		0x80000000	/* OR addr mask */
-#define CONFIG_SYS_PRELIM_OR_AM	0xE0000000	/* OR addr mask */
-
-/*
- * FLASH timing: Default value of OR0 after reset
- */
-#define CONFIG_SYS_OR0_PRELIM	0xfe000954
-#define CONFIG_SYS_BR0_PRELIM	0xf0000401
-
-/*
- * BR1 and OR1 (SDRAM)
- *
- */
-#define SDRAM_BASE1_PRELIM	0x00000000	/* SDRAM bank #0	*/
-#define SDRAM_MAX_SIZE		(64 << 20)	/* max 64 MB per bank	*/
-
-/* SDRAM timing: Multiplexed addresses, GPL5 output to GPL5_A (don't care)	*/
-#define CONFIG_SYS_OR_TIMING_SDRAM	0x00000A00
-
-#define CONFIG_SYS_OR1_PRELIM	0xfc000800
-#define CONFIG_SYS_BR1_PRELIM	(0x000000C0 | 0x01)
-
-#define CONFIG_SYS_MPTPR	0x0200
-/* PTB=16, AMB=001, FIXME 1 RAS precharge cycles, 1 READ loop cycle (not used),
-   1 Write loop Cycle (not used), 1 Timer Loop Cycle */
-#define CONFIG_SYS_MBMR	0x10964111
-#define CONFIG_SYS_MAR		0x00000088
-
-/*
- * 4096	Rows from SDRAM example configuration
- * 1000	factor s -> ms
- * 64	PTP (pre-divider from MPTPR) from SDRAM example configuration
- * 4	Number of refresh cycles per period
- * 64	Refresh cycle in ms per number of rows
- */
-#define CONFIG_SYS_PTA_PER_CLK	((4096 * 64 * 1000) / (4 * 64))
-
-/* GPIO/PIGGY on CS3 initialization values
-*/
-#define CONFIG_SYS_PIGGY_BASE	(0x30000000)
-#define CONFIG_SYS_OR3_PRELIM	(0xfe000d24)
-#define CONFIG_SYS_BR3_PRELIM	(0x30000401)
-
-/*
- * Internal Definitions
- *
- * Boot Flags
- */
-#define BOOTFLAG_COLD	0x01		/* Normal Power-On: Boot from FLASH	*/
-#define BOOTFLAG_WARM	0x02		/* Software reboot			*/
-
-#define CONFIG_SCC3_ENET
-#define CONFIG_ETHPRIME		"SCC ETHERNET"
-#define CONFIG_HAS_ETH0
-
-/* pass open firmware flat tree */
-#define CONFIG_OF_LIBFDT	1
-#define CONFIG_OF_BOARD_SETUP	1
-
-#define OF_STDOUT_PATH		"/soc/cpm/serial@a80"
-
-/* enable I2C and select the hardware/software driver */
-#undef	CONFIG_HARD_I2C			/* I2C with hardware support	*/
-#define	CONFIG_SOFT_I2C		1	/* I2C bit-banged		*/
-#define CONFIG_SYS_I2C_SPEED		50000	/* I2C speed and slave address	*/
-#define CONFIG_SYS_I2C_SLAVE		0x7F
-#define I2C_SOFT_DECLARATIONS
-
-/*
- * Software (bit-bang) I2C driver configuration
- */
-#define I2C_BASE_DIR	((u16 *)(CONFIG_SYS_PIGGY_BASE + 0x04))
-#define I2C_BASE_PORT	((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x09))
-
-#define SDA_BIT		0x40
-#define SCL_BIT		0x80
-#define SDA_CONF	0x1000
-#define SCL_CONF	0x2000
-
-#define I2C_ACTIVE	do {} while (0)
-#define I2C_TRISTATE	do {} while (0)
-#define I2C_READ	((in_8(I2C_BASE_PORT) & SDA_BIT) == SDA_BIT)
-#define I2C_SDA(bit)	if(bit) { \
-				clrbits(be16, I2C_BASE_DIR, SDA_CONF); \
-			} else { \
-				clrbits(8, I2C_BASE_PORT, SDA_BIT); \
-				setbits(be16, I2C_BASE_DIR, SDA_CONF); \
-			}
-#define I2C_SCL(bit)	if(bit) { \
-				clrbits(be16, I2C_BASE_DIR, SCL_CONF); \
-			} else { \
-				clrbits(8, I2C_BASE_PORT, SCL_BIT); \
-				setbits(be16, I2C_BASE_DIR, SCL_CONF); \
-			}
-#define I2C_DELAY	udelay(50)	/* 1/4 I2C clock duration */
-
-#define CONFIG_I2C_MULTI_BUS	1
-#define CONFIG_I2C_CMD_TREE	1
-#define CONFIG_SYS_MAX_I2C_BUS		2
-#define CONFIG_SYS_I2C_INIT_BOARD	1
-#define CONFIG_I2C_MUX		1
-
-/* EEprom support */
-#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
-#define CONFIG_SYS_I2C_MULTI_EEPROMS	1
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_ENABLE
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
-#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 10
-
-/* Support the IVM EEprom */
-#define	CONFIG_SYS_IVM_EEPROM_ADR	0x50
-#define CONFIG_SYS_IVM_EEPROM_MAX_LEN	0x400
-#define CONFIG_SYS_IVM_EEPROM_PAGE_LEN	0x100
-
-/* I2C SYSMON (LM75, AD7414 is almost compatible)			*/
-#define CONFIG_DTT_LM75		1	/* ON Semi's LM75		*/
-#define CONFIG_DTT_SENSORS	{0, 2, 4, 6}	/* Sensor addresses		*/
-#define CONFIG_SYS_DTT_MAX_TEMP	70
-#define CONFIG_SYS_DTT_LOW_TEMP	-30
-#define CONFIG_SYS_DTT_HYSTERESIS	3
-#define CONFIG_SYS_DTT_BUS_NUM		(CONFIG_SYS_MAX_I2C_BUS)
-
-#define MTDIDS_DEFAULT		"nor0=app"
-#define MTDPARTS_DEFAULT ( \
-	"mtdparts=app:384k(u-boot),128k(env),128k(envred),128k(free),"	\
-	"1536k(esw0),8704k(rootfs0),1536k(esw1),2432k(rootfs1),640k(var),768k(cfg)")
+/* include common defines/options for all Keymile 8xx boards */
+#include "km8xx.h"
 
 #endif	/* __CONFIG_H */
diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h
index ac18c87..aa117c8 100644
--- a/include/configs/microblaze-generic.h
+++ b/include/configs/microblaze-generic.h
@@ -259,7 +259,7 @@
 
 #if defined(CONFIG_CMD_JFFS2)
 /* JFFS2 partitions */
-#define CONFIG_JFFS2_CMDLINE	/* mtdparts command line support */
+#define CONFIG_CMD_MTDPARTS	/* mtdparts command line support */
 #define MTDIDS_DEFAULT		"nor0=ml401-0"
 
 /* default mtd partition table */
diff --git a/include/configs/mimc200.h b/include/configs/mimc200.h
index 2eb9ebc..8ff2f8a 100644
--- a/include/configs/mimc200.h
+++ b/include/configs/mimc200.h
@@ -74,12 +74,12 @@
 
 #define CONFIG_BAUDRATE			115200
 #define CONFIG_BOOTARGS							\
-	"console=ttyS0 root=/dev/mtdblock1 fbmem=600k rootfstype=jffs2"
+	"root=/dev/mtdblock1 rootfstype=jffs2 console=ttyS1"
 #define CONFIG_BOOTCOMMAND						\
-	"fsload; bootm"
+	"fsload boot/uImage; bootm"
 
 #define CONFIG_SILENT_CONSOLE		1	/* enable silent startup */
-#define CONFIG_SILENT_CONSOLE_INPUT	1	/* disable console inputs */
+#define CONFIG_DISABLE_CONSOLE		1	/* disable console */
 #define CONFIG_SYS_DEVICE_NULLDEV		1	/* include nulldev device */
 
 /*
diff --git a/include/configs/modnet50.h b/include/configs/modnet50.h
index c4f5286..27213a8 100644
--- a/include/configs/modnet50.h
+++ b/include/configs/modnet50.h
@@ -182,7 +182,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00080000
@@ -190,7 +190,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=modnet50-0"
 #define MTDPARTS_DEFAULT	"mtdparts=modnet50-0:-@512k(jffs2)"
 */
diff --git a/include/configs/motionpro.h b/include/configs/motionpro.h
index e6e3729..99a02cc 100644
--- a/include/configs/motionpro.h
+++ b/include/configs/motionpro.h
@@ -275,7 +275,7 @@
 /*
  * MTD configuration
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=motionpro-0"
 #define MTDPARTS_DEFAULT	"mtdparts=motionpro-0:"			  \
 					"13m(fs),2m(kernel),256k(uboot)," \
diff --git a/include/configs/mx1fs2.h b/include/configs/mx1fs2.h
index aaa4e98..a19eb78 100644
--- a/include/configs/mx1fs2.h
+++ b/include/configs/mx1fs2.h
@@ -176,7 +176,7 @@
  */
 /* No command line, one static partition, whole device */
 /*
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00050000
@@ -184,7 +184,7 @@
 
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=mx1fs2-0"
 
 #ifdef BUS32BIT_VERSION
diff --git a/include/configs/mx31ads.h b/include/configs/mx31ads.h
index 1649f1f..c31c06a 100644
--- a/include/configs/mx31ads.h
+++ b/include/configs/mx31ads.h
@@ -194,7 +194,7 @@
 /*
  * JFFS2 partitions
  */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV	"nor0"
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/netstar.h b/include/configs/netstar.h
index 2c90265..0b38549 100644
--- a/include/configs/netstar.h
+++ b/include/configs/netstar.h
@@ -64,12 +64,12 @@
  */
 #define CONFIG_SYS_FLASH_BASE		PHYS_FLASH_1
 #define CONFIG_SYS_MAX_FLASH_BANKS	1
-#define PHYS_FLASH_1_SIZE	(1 * 1024 * 1024)
+#define PHYS_FLASH_1_SIZE		(1 * 1024 * 1024)
 #define CONFIG_SYS_MAX_FLASH_SECT	19
 #define CONFIG_SYS_FLASH_ERASE_TOUT	(5*CONFIG_SYS_HZ) /* in ticks */
 #define CONFIG_SYS_FLASH_WRITE_TOUT	(5*CONFIG_SYS_HZ)
 
-#define CONFIG_SYS_MONITOR_BASE	PHYS_FLASH_1
+#define CONFIG_SYS_MONITOR_BASE		PHYS_FLASH_1
 #define CONFIG_SYS_MONITOR_LEN		(256 * 1024)
 
 /*
@@ -97,36 +97,31 @@
 /*
  * Hardware drivers
  */
-#define CONFIG_DRIVER_SMC91111
-#define CONFIG_SMC91111_BASE	0x04000300
-
-/*
- * NS16550 Configuration
- */
 #define CONFIG_SYS_NS16550
 #define CONFIG_SYS_NS16550_SERIAL
 #define CONFIG_SYS_NS16550_REG_SIZE	(-4)
 #define CONFIG_SYS_NS16550_CLK		(CONFIG_XTAL_FREQ)	/* can be 12M/32Khz or 48Mhz  */
-#define CONFIG_SYS_NS16550_COM1	OMAP1510_UART1_BASE	/* uart1 */
+#define CONFIG_SYS_NS16550_COM1		OMAP1510_UART1_BASE	/* uart1 */
 
-#define CONFIG_CONS_INDEX	1
-#define CONFIG_BAUDRATE		115200
+#define CONFIG_DRIVER_SMC91111
+#define CONFIG_SMC91111_BASE		0x04000300
+
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_SYS_NAND_BASE		0x04000000 + (2 << 23)
+#define NAND_ALLOW_ERASE_ALL		1
+
+
+#define CONFIG_CONS_INDEX		1
+#define CONFIG_BAUDRATE			115200
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
 
 /*#define CONFIG_SKIP_RELOCATE_UBOOT*/
 /*#define CONFIG_SKIP_LOWLEVEL_INIT */
 
 /*
- * NAND flash
- */
-#define CONFIG_SYS_MAX_NAND_DEVICE	1
-#define CONFIG_SYS_NAND_BASE	0x04000000 + (2 << 23)
-#define NAND_ALLOW_ERASE_ALL	1
-
-/*
  * partitions (mtdparts command line support)
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=omapflash.0,nand0=omapnand.0"
 #define MTDPARTS_DEFAULT	"mtdparts=" \
 	"omapflash.0:8k@16k(env),8k(r_env),448k@576k(u-boot);" \
@@ -136,7 +131,6 @@
 /*
  * Command line configuration.
  */
-
 #define CONFIG_CMD_BDI
 #define CONFIG_CMD_BOOTD
 #define CONFIG_CMD_DHCP
diff --git a/include/configs/omap2420h4.h b/include/configs/omap2420h4.h
index 92df0b4..983b5f2 100644
--- a/include/configs/omap2420h4.h
+++ b/include/configs/omap2420h4.h
@@ -296,7 +296,7 @@
  * JFFS2 partitions
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor1"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -304,7 +304,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor1=omap2420-1"
 #define MTDPARTS_DEFAULT	"mtdparts=omap2420-1:-(jffs2)"
 */
diff --git a/include/configs/pcu_e.h b/include/configs/pcu_e.h
index 9214519..7c2bf1b 100644
--- a/include/configs/pcu_e.h
+++ b/include/configs/pcu_e.h
@@ -246,6 +246,9 @@
  */
 #define CONFIG_SYS_CACHELINE_SIZE	16	/* For all MPC8xx CPUs			*/
 #define CONFIG_SYS_CACHELINE_SHIFT	4	/* log base 2 of the above value	*/
+#define CONFIG_SYS_DELAYED_ICACHE	1	/* enable ICache not before
+						 * running in RAM.
+						 */
 
 /*-----------------------------------------------------------------------
  * SYPCR - System Protection Control				11-9
diff --git a/include/configs/qong.h b/include/configs/qong.h
index ccc2625..a67006a 100644
--- a/include/configs/qong.h
+++ b/include/configs/qong.h
@@ -212,7 +212,7 @@
 /*
  * JFFS2 partitions
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=physmap-flash.0"
 #define MTDPARTS_DEFAULT	\
 	"mtdparts=physmap-flash.0:256k(U-Boot),128k(env1),"	\
diff --git a/include/configs/r2dplus.h b/include/configs/r2dplus.h
index 6921759..6fa1eaf 100644
--- a/include/configs/r2dplus.h
+++ b/include/configs/r2dplus.h
@@ -114,6 +114,9 @@
 #define CONFIG_PCI_IO_BUS	0xFE240000	/* IO space base address */
 #define CONFIG_PCI_IO_PHYS	CONFIG_PCI_IO_BUS
 #define CONFIG_PCI_IO_SIZE	0x00040000	/* Size of IO window */
+#define CONFIG_PCI_SYS_BUS	(CONFIG_SYS_SDRAM_BASE & 0x1fffffff)
+#define CONFIG_PCI_SYS_PHYS	(CONFIG_SYS_SDRAM_BASE & 0x1fffffff)
+#define CONFIG_PCI_SYS_SIZE	CONFIG_SYS_SDRAM_SIZE
 
 /*
  * Network device (RTL8139) support
diff --git a/include/configs/r7780mp.h b/include/configs/r7780mp.h
index 72a3b5c..88eb568 100644
--- a/include/configs/r7780mp.h
+++ b/include/configs/r7780mp.h
@@ -129,6 +129,9 @@
 #define CONFIG_PCI
 #define CONFIG_SH4_PCI
 #define CONFIG_SH7780_PCI
+#define CONFIG_SH7780_PCI_LSR	0x07f00001
+#define CONFIG_SH7780_PCI_LAR	CONFIG_SYS_SDRAM_SIZE
+#define CONFIG_SH7780_PCI_BAR	CONFIG_SYS_SDRAM_SIZE
 #define CONFIG_PCI_PNP
 #define CONFIG_PCI_SCAN_SHOW	1
 #define __io
diff --git a/include/configs/sc3.h b/include/configs/sc3.h
index 515b097..5b68ef9 100644
--- a/include/configs/sc3.h
+++ b/include/configs/sc3.h
@@ -430,7 +430,7 @@
 #define CONFIG_JFFS2_NAND 1			/* jffs2 on nand support */
 
 /* No command line, one static partition */
-#undef	CONFIG_JFFS2_CMDLINE
+#undef	CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nand0"
 #define CONFIG_JFFS2_PART_SIZE		0x01000000
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h
index 9f2357b..960350c 100644
--- a/include/configs/sc520_cdp.h
+++ b/include/configs/sc520_cdp.h
@@ -28,6 +28,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
 #define GRUSS_TESTING
 /*
  * High Level Configuration Options
@@ -35,7 +37,7 @@
  */
 
 #define CONFIG_X86		1	/* This is a X86 CPU		*/
-#define CONFIG_SC520		1	/* Include support for AMD SC520 */
+#define CONFIG_SYS_SC520	1	/* Include support for AMD SC520 */
 #define CONFIG_ALI152X		1	/* Include support for Ali 152x SIO */
 
 #define CONFIG_SYS_SDRAM_PRECHARGE_DELAY 6     /* 6T */
@@ -47,12 +49,14 @@
 #define CONFIG_SYS_SDRAM_CAS_LATENCY_3T
 
 #define CONFIG_SYS_SC520_HIGH_SPEED    0       /* 100 or 133MHz */
-#undef  CONFIG_SYS_RESET_SC520                 /* use SC520 MMCR's to reset cpu */
-#undef  CONFIG_SYS_TIMER_SC520                 /* use SC520 swtimers */
-#define CONFIG_SYS_TIMER_GENERIC       1       /* use the i8254 PIT timers */
-#undef  CONFIG_SYS_TIMER_TSC                   /* use the Pentium TSC timers */
+#undef  CONFIG_SYS_SC520_RESET                 /* use SC520 MMCR's to reset cpu */
+#undef  CONFIG_SYS_SC520_TIMER                 /* use SC520 swtimers */
+#define CONFIG_SYS_GENERIC_TIMER       1       /* use the i8254 PIT timers */
+#undef  CONFIG_SYS_TSC_TIMER                   /* use the Pentium TSC timers */
 #define  CONFIG_SYS_USE_SIO_UART       0       /* prefer the uarts on the SIO to those
 					 * in the SC520 on the CDP */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS		16
 
 #define CONFIG_SYS_STACK_SIZE          0x8000  /* Size of bootloader stack */
 
@@ -147,22 +151,22 @@
 #define CONFIG_SPI
 #define CONFIG_ENV_SIZE	       0x4000	/* Total Size of Environment EEPROM 16k is SPI is used or 128 bytes if MW is used*/
 #define CONFIG_ENV_OFFSET         0
-#define CONFIG_SC520_CDP_USE_SPI  /* Store configuration in the SPI part */
-#undef CONFIG_SC520_CDP_USE_MW    /* Store configuration in the MicroWire part */
+#define CONFIG_SYS_SC520_CDP_USE_SPI  /* Store configuration in the SPI part */
+#undef CONFIG_SYS_SC520_CDP_USE_MW    /* Store configuration in the MicroWire part */
 #define CONFIG_SPI_X 1
 
 /*
  * JFFS2 partitions
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
 
 /* mtdparts command line support */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=SC520CDP Flash Bank #0"
 #define MTDPARTS_DEFAULT	"mtdparts=SC520CDP Flash Bank #0:-(jffs2)"
 */
diff --git a/include/configs/sc520_spunk.h b/include/configs/sc520_spunk.h
index 50af732..2445a34 100644
--- a/include/configs/sc520_spunk.h
+++ b/include/configs/sc520_spunk.h
@@ -28,13 +28,15 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
 /*
  * High Level Configuration Options
  * (easy to change)
  */
 
 #define CONFIG_X86		1	/* This is a X86 CPU		*/
-#define CONFIG_SC520		1	/* Include support for AMD SC520 */
+#define CONFIG_SYS_SC520	1	/* Include support for AMD SC520 */
 
 #define CONFIG_SYS_SDRAM_PRECHARGE_DELAY 6     /* 6T */
 #define CONFIG_SYS_SDRAM_REFRESH_RATE    78    /* 7.8uS (choices are 7.8, 15.6, 31.2 or 62.5uS) */
@@ -45,10 +47,12 @@
 #define CONFIG_SYS_SDRAM_CAS_LATENCY_3T
 
 #define CONFIG_SYS_SC520_HIGH_SPEED    0       /* 100 or 133MHz */
-#undef  CONFIG_SYS_RESET_SC520                 /* use SC520 MMCR's to reset cpu */
-#undef  CONFIG_SYS_TIMER_SC520                 /* use SC520 swtimers */
-#define CONFIG_SYS_TIMER_GENERIC       1       /* use the i8254 PIT timers */
-#undef  CONFIG_SYS_TIMER_TSC                   /* use the Pentium TSC timers */
+#undef  CONFIG_SYS_SC520_RESET                 /* use SC520 MMCR's to reset cpu */
+#undef  CONFIG_SYS_SC520_TIMER                 /* use SC520 swtimers */
+#define CONFIG_SYS_GENERIC_TIMER       1       /* use the i8254 PIT timers */
+#undef  CONFIG_SYS_TSC_TIMER                   /* use the Pentium TSC timers */
+#define CONFIG_SYS_PCAT_INTERRUPTS
+#define CONFIG_SYS_NUM_IRQS		16
 
 #define CONFIG_SYS_STACK_SIZE          0x8000  /* Size of bootloader stack */
 
@@ -173,7 +177,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -181,7 +185,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=sc520_spunk-0"
 #define MTDPARTS_DEFAULT	"mtdparts=sc520_spunk-0:-(jffs2)"
 */
diff --git a/include/configs/sh7785lcr.h b/include/configs/sh7785lcr.h
index 537ec4e..21c3f70 100644
--- a/include/configs/sh7785lcr.h
+++ b/include/configs/sh7785lcr.h
@@ -61,11 +61,20 @@
 #undef	CONFIG_SHOW_BOOT_PROGRESS
 
 /* MEMORY */
+#if defined(CONFIG_SH_32BIT)
+#define SH7785LCR_SDRAM_PHYS_BASE	(0x48000000)
+#define SH7785LCR_SDRAM_BASE		(0x88000000)
+#define SH7785LCR_SDRAM_SIZE		(384 * 1024 * 1024)
+#define SH7785LCR_FLASH_BASE_1		(0xa0000000)
+#define SH7785LCR_FLASH_BANK_SIZE	(64 * 1024 * 1024)
+#define SH7785LCR_USB_BASE		(0xa6000000)
+#else
 #define SH7785LCR_SDRAM_BASE		(0x08000000)
 #define SH7785LCR_SDRAM_SIZE		(128 * 1024 * 1024)
 #define SH7785LCR_FLASH_BASE_1		(0xa0000000)
 #define SH7785LCR_FLASH_BANK_SIZE	(64 * 1024 * 1024)
 #define SH7785LCR_USB_BASE		(0xb4000000)
+#endif
 
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_SYS_PROMPT		"=> "
@@ -133,6 +142,15 @@
 #define CONFIG_PCI
 #define CONFIG_SH4_PCI
 #define CONFIG_SH7780_PCI
+#if defined(CONFIG_SH_32BIT)
+#define CONFIG_SH7780_PCI_LSR	0x1ff00001
+#define CONFIG_SH7780_PCI_LAR	0x5f000000
+#define CONFIG_SH7780_PCI_BAR	0x5f000000
+#else
+#define CONFIG_SH7780_PCI_LSR	0x07f00001
+#define CONFIG_SH7780_PCI_LAR	CONFIG_SYS_SDRAM_SIZE
+#define CONFIG_SH7780_PCI_BAR	CONFIG_SYS_SDRAM_SIZE
+#endif
 #define CONFIG_PCI_PNP
 #define CONFIG_PCI_SCAN_SHOW	1
 
@@ -144,6 +162,14 @@
 #define CONFIG_PCI_IO_PHYS	CONFIG_PCI_IO_BUS
 #define CONFIG_PCI_IO_SIZE	0x00200000	/* Size of IO window */
 
+#if defined(CONFIG_SH_32BIT)
+#define CONFIG_PCI_SYS_PHYS	SH7785LCR_SDRAM_PHYS_BASE
+#else
+#define CONFIG_PCI_SYS_PHYS	CONFIG_SYS_SDRAM_BASE
+#endif
+#define CONFIG_PCI_SYS_BUS	CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_SIZE	CONFIG_SYS_SDRAM_SIZE
+
 /* Network device (RTL8169) support */
 #define CONFIG_NET_MULTI
 #define CONFIG_RTL8169
diff --git a/include/configs/smmaco4.h b/include/configs/smmaco4.h
index a3f2677..35f3e3a 100644
--- a/include/configs/smmaco4.h
+++ b/include/configs/smmaco4.h
@@ -214,7 +214,7 @@
 #define CONFIG_SYS_FLASH_WRITE_TOUT	500	/* Flash Write Timeout (in ms)	*/
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM5200-0"
 #define MTDPARTS_DEFAULT	"mtdparts=TQM5200-0:640k(firmware),"	\
 						"1408k(kernel),"	\
diff --git a/include/configs/trab.h b/include/configs/trab.h
index 0a7a73d..8f13c35 100644
--- a/include/configs/trab.h
+++ b/include/configs/trab.h
@@ -375,7 +375,7 @@
 #define	CONFIG_SYS_MONITOR_LEN		(256 << 10)
 
 /* Dynamic MTD partition support */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=0"
 
 /* production flash layout */
diff --git a/include/configs/v37.h b/include/configs/v37.h
index a6b0f0d..7f1670e 100644
--- a/include/configs/v37.h
+++ b/include/configs/v37.h
@@ -106,7 +106,7 @@
  *
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor1"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -114,7 +114,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor1=v37-1"
 #define MTDPARTS_DEFAULT	"mtdparts=v37-1:-(jffs2)"
 */
diff --git a/include/configs/v38b.h b/include/configs/v38b.h
index fc7128e..92bcdb3 100644
--- a/include/configs/v38b.h
+++ b/include/configs/v38b.h
@@ -40,6 +40,7 @@
 
 #define CONFIG_BOARD_EARLY_INIT_R	1	/* do board-specific init */
 #define CONFIG_BOARD_EARLY_INIT_F	1	/* do board-specific init */
+#define CONFIG_MISC_INIT_R
 
 #define CONFIG_SYS_XLB_PIPELINING		1	/* gives better performance */
 
diff --git a/include/configs/vct.h b/include/configs/vct.h
index 391535e..5371e2d 100644
--- a/include/configs/vct.h
+++ b/include/configs/vct.h
@@ -286,7 +286,7 @@
 #define	CONFIG_CMD_UBI
 #define	CONFIG_RBTREE
 #define CONFIG_MTD_PARTITIONS
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 
 #define MTDIDS_DEFAULT		"onenand0=onenand"
 #define MTDPARTS_DEFAULT	"mtdparts=onenand:128k(u-boot),"	\
diff --git a/include/configs/virtlab2.h b/include/configs/virtlab2.h
index 7b61c82..021012d 100644
--- a/include/configs/virtlab2.h
+++ b/include/configs/virtlab2.h
@@ -225,7 +225,7 @@
 /*-----------------------------------------------------------------------
  * Dynamic MTD partition support
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=TQM8xxL-0"
 
 #define MTDPARTS_DEFAULT	"mtdparts=TQM8xxL-0:256k(u-boot),"	\
diff --git a/include/configs/voiceblue.h b/include/configs/voiceblue.h
index f460610..cadd906 100644
--- a/include/configs/voiceblue.h
+++ b/include/configs/voiceblue.h
@@ -189,7 +189,7 @@
 /*
  * JFFS2 partitions (mtdparts command line support)
  */
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=omapflash.0"
 #define MTDPARTS_DEFAULT	"mtdparts=omapflash.0:256k(u-boot),64k(env),64k(r_env),16192k(data0),-(data1)"
 
diff --git a/include/configs/xilinx-ppc.h b/include/configs/xilinx-ppc.h
index e7daa07..e3ea84b 100644
--- a/include/configs/xilinx-ppc.h
+++ b/include/configs/xilinx-ppc.h
@@ -41,7 +41,7 @@
 #define CONFIG_CMD_IRQ
 #define CONFIG_CMD_REGINFO
 #undef CONFIG_CMD_JFFS2
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #undef CONFIG_CMD_SPI
 #undef CONFIG_CMD_I2C
 #undef CONFIG_CMD_DTT
@@ -108,7 +108,7 @@
 #define	CONFIG_SYS_MAX_FLASH_BANKS	1
 #define	CONFIG_SYS_FLASH_PROTECTION
 #define CONFIG_CMD_JFFS2
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #else
 #define CONFIG_ENV_IS_NOWHERE
 #define CONFIG_SYS_NO_FLASH
diff --git a/include/configs/xsengine.h b/include/configs/xsengine.h
index 6761438..5d13f96 100644
--- a/include/configs/xsengine.h
+++ b/include/configs/xsengine.h
@@ -62,7 +62,7 @@
  * JFFS2 partitions
  */
 /* No command line, one static partition, whole device */
-#undef CONFIG_JFFS2_CMDLINE
+#undef CONFIG_CMD_MTDPARTS
 #define CONFIG_JFFS2_DEV		"nor0"
 #define CONFIG_JFFS2_PART_SIZE		0xFFFFFFFF
 #define CONFIG_JFFS2_PART_OFFSET	0x00000000
@@ -70,7 +70,7 @@
 /* mtdparts command line support */
 /* Note: fake mtd_id used, no linux mtd map file */
 /*
-#define CONFIG_JFFS2_CMDLINE
+#define CONFIG_CMD_MTDPARTS
 #define MTDIDS_DEFAULT		"nor0=xsengine-0"
 #define MTDPARTS_DEFAULT	"mtdparts=xsengine-0:256k(uboot),1m(kernel1),8m(kernel2)"
 */
diff --git a/include/lcd.h b/include/lcd.h
index 512221e..f054cac 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -148,14 +148,6 @@
 
 extern vidinfo_t panel_info;
 
-#elif defined(CONFIG_MCC200)
-typedef struct vidinfo {
-	ushort	vl_col;		/* Number of columns (i.e. 160) */
-	ushort	vl_row;		/* Number of rows (i.e. 100) */
-
-	u_char	vl_bpix;	/* Bits per pixel, 0 = 1 */
-} vidinfo_t;
-
 #elif defined(CONFIG_ATMEL_LCD)
 
 typedef struct vidinfo {
@@ -183,6 +175,19 @@
 
 extern vidinfo_t panel_info;
 
+#else
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 160) */
+	ushort	vl_row;		/* Number of rows (i.e. 100) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1 */
+
+	ushort	*cmap;		/* Pointer to the colormap */
+
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #endif /* CONFIG_MPC823, CONFIG_PXA250 or CONFIG_MCC200 or CONFIG_ATMEL_LCD */
 
 /* Video functions */
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
new file mode 100644
index 0000000..d793497
--- /dev/null
+++ b/include/linux/lzo.h
@@ -0,0 +1,44 @@
+#ifndef __LZO_H__
+#define __LZO_H__
+/*
+ *  LZO Public Kernel Interface
+ *  A mini subset of the LZO real-time data compression library
+ *
+ *  Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ *  The full LZO package can be found at:
+ *  http://www.oberhumer.com/opensource/lzo/
+ *
+ *  Changed for kernel use by:
+ *  Nitin Gupta <nitingupta910@gmail.com>
+ *  Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO1X_MEM_COMPRESS	(16384 * sizeof(unsigned char *))
+#define LZO1X_1_MEM_COMPRESS	LZO1X_MEM_COMPRESS
+
+#define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3)
+
+/* This requires 'workmem' of size LZO1X_1_MEM_COMPRESS */
+int lzo1x_1_compress(const unsigned char *src, size_t src_len,
+			unsigned char *dst, size_t *dst_len, void *wrkmem);
+
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const unsigned char *src, size_t src_len,
+			unsigned char *dst, size_t *dst_len);
+
+/*
+ * Return values (< 0 = Error)
+ */
+#define LZO_E_OK			0
+#define LZO_E_ERROR			(-1)
+#define LZO_E_OUT_OF_MEMORY		(-2)
+#define LZO_E_NOT_COMPRESSIBLE		(-3)
+#define LZO_E_INPUT_OVERRUN		(-4)
+#define LZO_E_OUTPUT_OVERRUN		(-5)
+#define LZO_E_LOOKBEHIND_OVERRUN	(-6)
+#define LZO_E_EOF_NOT_FOUND		(-7)
+#define LZO_E_INPUT_NOT_CONSUMED	(-8)
+#define LZO_E_NOT_YET_IMPLEMENTED	(-9)
+
+#endif
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644
index 0000000..6d760d7
--- /dev/null
+++ b/include/linux/math64.h
@@ -0,0 +1,85 @@
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <linux/types.h>
+
+#if BITS_PER_LONG == 64
+
+/**
+ * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ *
+ * This is commonly provided by 32bit archs to provide an optimized 64bit
+ * divide.
+ */
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+	*remainder = dividend % divisor;
+	return dividend / divisor;
+}
+
+/**
+ * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ */
+static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+	*remainder = dividend % divisor;
+	return dividend / divisor;
+}
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+	return dividend / divisor;
+}
+
+#elif BITS_PER_LONG == 32
+
+#ifndef div_u64_rem
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+	*remainder = do_div(dividend, divisor);
+	return dividend;
+}
+#endif
+
+#ifndef div_s64_rem
+extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
+#endif
+
+#ifndef div64_u64
+extern u64 div64_u64(u64 dividend, u64 divisor);
+#endif
+
+#endif /* BITS_PER_LONG */
+
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+#ifndef div_u64
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+	u32 remainder;
+	return div_u64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+/**
+ * div_s64 - signed 64bit divide with 32bit divisor
+ */
+#ifndef div_s64
+static inline s64 div_s64(s64 dividend, s32 divisor)
+{
+	s32 remainder;
+	return div_s64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
+
+#endif /* _LINUX_MATH64_H */
diff --git a/include/linux/unaligned/access_ok.h b/include/linux/unaligned/access_ok.h
new file mode 100644
index 0000000..5f46eee
--- /dev/null
+++ b/include/linux/unaligned/access_ok.h
@@ -0,0 +1,66 @@
+#ifndef _LINUX_UNALIGNED_ACCESS_OK_H
+#define _LINUX_UNALIGNED_ACCESS_OK_H
+
+#include <asm/byteorder.h>
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+	return le16_to_cpup((__le16 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+	return le32_to_cpup((__le32 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+	return le64_to_cpup((__le64 *)p);
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+	return be16_to_cpup((__be16 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+	return be32_to_cpup((__be32 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+	return be64_to_cpup((__be64 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+	*((__le16 *)p) = cpu_to_le16(val);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+	*((__le32 *)p) = cpu_to_le32(val);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+	*((__le64 *)p) = cpu_to_le64(val);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+	*((__be16 *)p) = cpu_to_be16(val);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+	*((__be32 *)p) = cpu_to_be32(val);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+	*((__be64 *)p) = cpu_to_be64(val);
+}
+
+#endif /* _LINUX_UNALIGNED_ACCESS_OK_H */
diff --git a/include/linux/unaligned/generic.h b/include/linux/unaligned/generic.h
new file mode 100644
index 0000000..cc688e1
--- /dev/null
+++ b/include/linux/unaligned/generic.h
@@ -0,0 +1,71 @@
+#ifndef _LINUX_UNALIGNED_GENERIC_H
+#define _LINUX_UNALIGNED_GENERIC_H
+
+/* define __force to nothing in U-Boot */
+#define __force
+
+/*
+ * Cause a link-time error if we try an unaligned access other than
+ * 1,2,4 or 8 bytes long
+ */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)),	\
+	__bad_unaligned_access_size()))));					\
+	}))
+
+#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr),			\
+	__builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)),	\
+	__builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)),	\
+	__bad_unaligned_access_size()))));					\
+	}))
+
+#define __put_unaligned_le(val, ptr) ({					\
+	void *__gu_p = (ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		*(u8 *)__gu_p = (__force u8)(val);			\
+		break;							\
+	case 2:								\
+		put_unaligned_le16((__force u16)(val), __gu_p);		\
+		break;							\
+	case 4:								\
+		put_unaligned_le32((__force u32)(val), __gu_p);		\
+		break;							\
+	case 8:								\
+		put_unaligned_le64((__force u64)(val), __gu_p);		\
+		break;							\
+	default:							\
+		__bad_unaligned_access_size();				\
+		break;							\
+	}								\
+	(void)0; })
+
+#define __put_unaligned_be(val, ptr) ({					\
+	void *__gu_p = (ptr);						\
+	switch (sizeof(*(ptr))) {					\
+	case 1:								\
+		*(u8 *)__gu_p = (__force u8)(val);			\
+		break;							\
+	case 2:								\
+		put_unaligned_be16((__force u16)(val), __gu_p);		\
+		break;							\
+	case 4:								\
+		put_unaligned_be32((__force u32)(val), __gu_p);		\
+		break;							\
+	case 8:								\
+		put_unaligned_be64((__force u64)(val), __gu_p);		\
+		break;							\
+	default:							\
+		__bad_unaligned_access_size();				\
+		break;							\
+	}								\
+	(void)0; })
+
+#endif /* _LINUX_UNALIGNED_GENERIC_H */
diff --git a/include/mpc83xx.h b/include/mpc83xx.h
index 3554fdd..fab3751 100644
--- a/include/mpc83xx.h
+++ b/include/mpc83xx.h
@@ -890,6 +890,8 @@
 #define TIMING_CFG1_CASLAT_30		0x00050000	/* CAS latency = 3.0 */
 #define TIMING_CFG1_CASLAT_35		0x00060000	/* CAS latency = 3.5 */
 #define TIMING_CFG1_CASLAT_40		0x00070000	/* CAS latency = 4.0 */
+#define TIMING_CFG1_CASLAT_45		0x00080000	/* CAS latency = 4.5 */
+#define TIMING_CFG1_CASLAT_50		0x00090000	/* CAS latency = 5.0 */
 
 /* TIMING_CFG_2 - DDR SDRAM Timing Configuration 2
  */
diff --git a/include/net.h b/include/net.h
index b192db1..5a1d36e 100644
--- a/include/net.h
+++ b/include/net.h
@@ -120,6 +120,9 @@
 extern struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
 extern int eth_get_dev_index (void);		/* get the device index */
 extern void eth_set_enetaddr(int num, char* a);	/* Set new MAC address */
+extern void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
+extern int eth_getenv_enetaddr(char *name, uchar *enetaddr);
+extern int eth_setenv_enetaddr(char *name, const uchar *enetaddr);
 
 extern int eth_init(bd_t *bis);			/* Initialize the device */
 extern int eth_send(volatile void *packet, int length);	   /* Send a packet */
@@ -408,9 +411,6 @@
 /* Processes a received packet */
 extern void	NetReceive(volatile uchar *, int);
 
-/* Print an IP address on the console */
-extern void	print_IPaddr (IPaddr_t);
-
 /*
  * The following functions are a bit ugly, but necessary to deal with
  * alignment restrictions on ARM.
diff --git a/include/pci.h b/include/pci.h
index d0594e3..aaa4554 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -535,6 +535,8 @@
 				  pci_addr_t mem,
 				  unsigned long command);
 
+int pci_last_busno(void);
+
 #ifdef CONFIG_MPC824X
 extern void pci_mpc824x_init (struct pci_controller *hose);
 #endif
diff --git a/include/s6e63d6.h b/include/s6e63d6.h
new file mode 100644
index 0000000..9f17fc0
--- /dev/null
+++ b/include/s6e63d6.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@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
+ */
+#ifndef _S6E63D6_H_
+#define _S6E63D6_H_
+
+struct s6e63d6 {
+	unsigned int bus;
+	unsigned int cs;
+	unsigned int id;
+	struct spi_slave *slave;
+};
+
+extern int s6e63d6_init(struct s6e63d6 *data);
+extern int s6e63d6_index(struct s6e63d6 *data, u8 idx);
+extern int s6e63d6_param(struct s6e63d6 *data, u16 param);
+
+#endif
diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h
index b415219..74312ab 100644
--- a/include/ubi_uboot.h
+++ b/include/ubi_uboot.h
@@ -18,7 +18,12 @@
 #include <malloc.h>
 #include <div64.h>
 #include <linux/crc32.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/string.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/ubi.h>
 
 #ifdef CONFIG_CMD_ONENAND
 #include <onenand_uboot.h>
@@ -193,7 +198,7 @@
 
 /* module */
 #define THIS_MODULE		0
-#define try_module_get(...)	0
+#define try_module_get(...)	1
 #define module_put(...)		do { } while (0)
 #define module_init(...)
 #define module_exit(...)
@@ -206,7 +211,9 @@
 #define MODULE_AUTHOR(...)
 #define MODULE_LICENSE(...)
 
+#ifndef __UBIFS_H__
 #include "../drivers/mtd/ubi/ubi.h"
+#endif
 
 /* functions */
 extern int ubi_mtd_param_parse(const char *val, struct kernel_param *kp);
diff --git a/lib_arm/board.c b/lib_arm/board.c
index 09eaaf2..3dfaec0 100644
--- a/lib_arm/board.c
+++ b/lib_arm/board.c
@@ -73,7 +73,7 @@
 	U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"CONFIG_IDENT_STRING;
 
 #ifdef CONFIG_DRIVER_CS8900
-extern void cs8900_get_enetaddr (uchar * addr);
+extern void cs8900_get_enetaddr (void);
 #endif
 
 #ifdef CONFIG_DRIVER_RTL8019
@@ -379,40 +379,8 @@
 	/* IP Address */
 	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 
-	/* MAC Address */
-	{
-		int i;
-		ulong reg;
-		char *s, *e;
-		char tmp[64];
-
-		i = getenv_r ("ethaddr", tmp, sizeof (tmp));
-		s = (i > 0) ? tmp : NULL;
-
-		for (reg = 0; reg < 6; ++reg) {
-			gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
-
-#ifdef CONFIG_HAS_ETH1
-		i = getenv_r ("eth1addr", tmp, sizeof (tmp));
-		s = (i > 0) ? tmp : NULL;
-
-		for (reg = 0; reg < 6; ++reg) {
-			gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
-#endif
-	}
-
 	devices_init ();	/* get the devices list going. */
 
-#ifdef CONFIG_CMC_PU2
-	load_sernum_ethaddr ();
-#endif /* CONFIG_CMC_PU2 */
-
 	jumptable_init ();
 
 #if defined(CONFIG_API)
@@ -432,19 +400,26 @@
 
 	/* Perform network card initialisation if necessary */
 #ifdef CONFIG_DRIVER_TI_EMAC
+	/* XXX: this needs to be moved to board init */
 extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
 	if (getenv ("ethaddr")) {
-		davinci_eth_set_mac_addr(gd->bd->bi_enetaddr);
+		uchar enetaddr[6];
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+		davinci_eth_set_mac_addr(enetaddr);
 	}
 #endif
 
 #ifdef CONFIG_DRIVER_CS8900
-	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
+	/* XXX: this needs to be moved to board init */
+	cs8900_get_enetaddr ();
 #endif
 
 #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
+	/* XXX: this needs to be moved to board init */
 	if (getenv ("ethaddr")) {
-		smc_set_mac_addr(gd->bd->bi_enetaddr);
+		uchar enetaddr[6];
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+		smc_set_mac_addr(enetaddr);
 	}
 #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
 
diff --git a/lib_blackfin/board.c b/lib_blackfin/board.c
index c223711..537f69a 100644
--- a/lib_blackfin/board.c
+++ b/lib_blackfin/board.c
@@ -106,10 +106,6 @@
 	printf(" \\-bd: %x\n", gd->bd);
 	printf("   |-bi_baudrate: %x\n", bd->bi_baudrate);
 	printf("   |-bi_ip_addr: %x\n", bd->bi_ip_addr);
-	printf("   |-bi_enetaddr: %x %x %x %x %x %x\n",
-	       bd->bi_enetaddr[0], bd->bi_enetaddr[1],
-	       bd->bi_enetaddr[2], bd->bi_enetaddr[3],
-	       bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
 	printf("   |-bi_boot_params: %x\n", bd->bi_boot_params);
 	printf("   |-bi_memstart: %x\n", bd->bi_memstart);
 	printf("   |-bi_memsize: %x\n", bd->bi_memsize);
@@ -338,35 +334,6 @@
 	/* relocate environment function pointers etc. */
 	env_relocate();
 
-#ifdef CONFIG_CMD_NET
-	/* board MAC address */
-	s = getenv("ethaddr");
-	if (s == NULL) {
-# ifndef CONFIG_ETHADDR
-#  if 0
-		if (!board_get_enetaddr(bd->bi_enetaddr)) {
-			char nid[20];
-			sprintf(nid, "%02X:%02X:%02X:%02X:%02X:%02X",
-				bd->bi_enetaddr[0], bd->bi_enetaddr[1],
-				bd->bi_enetaddr[2], bd->bi_enetaddr[3],
-				bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
-			setenv("ethaddr", nid);
-		}
-#  endif
-# endif
-	} else {
-		int i;
-		char *e;
-		for (i = 0; i < 6; ++i) {
-			bd->bi_enetaddr[i] = simple_strtoul(s, &e, 16);
-			s = (*e) ? e + 1 : e;
-		}
-	}
-
-	/* IP Address */
-	bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-#endif
-
 	/* Initialize devices */
 	devices_init();
 	jumptable_init();
@@ -393,21 +360,10 @@
 #endif
 
 #ifdef CONFIG_CMD_NET
+	/* IP Address */
+	bd->bi_ip_addr = getenv_IPaddr("ipaddr");
 	printf("Net:   ");
 	eth_initialize(gd->bd);
-	if ((s = getenv("ethaddr"))) {
-# ifndef CONFIG_NET_MULTI
-		size_t i;
-		char *e;
-		for (i = 0; i < 6; ++i) {
-			bd->bi_enetaddr[i] = simple_strtoul(s, &e, 16);
-			s = (*e) ? e + 1 : e;
-		}
-# endif
-		printf("MAC:   %02X:%02X:%02X:%02X:%02X:%02X\n",
-			bd->bi_enetaddr[0], bd->bi_enetaddr[1], bd->bi_enetaddr[2],
-			bd->bi_enetaddr[3], bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
-	}
 #endif
 
 	display_global_data();
diff --git a/board/keymile/mgsuvd/Makefile b/lib_generic/lzo/Makefile
similarity index 74%
copy from board/keymile/mgsuvd/Makefile
copy to lib_generic/lzo/Makefile
index 2c5732d..5dd1bf5 100644
--- a/board/keymile/mgsuvd/Makefile
+++ b/lib_generic/lzo/Makefile
@@ -1,6 +1,6 @@
 #
-# (C) Copyright 2007
-# Heiko Schocher, DENX Software Engineering, hs@denx.de.
+# (C) Copyright 2008
+# Stefan Roese, DENX Software Engineering, sr@denx.de.
 #
 # See file CREDITS for list of people who contributed to this
 # project.
@@ -22,18 +22,16 @@
 #
 
 include $(TOPDIR)/config.mk
-ifneq ($(OBJTREE),$(SRCTREE))
-$(shell mkdir -p $(obj)../common)
-endif
 
-LIB	= $(obj)lib$(BOARD).a
+LIB	= $(obj)liblzo.a
 
-COBJS	= $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \
-		mgsuvd_hdlc_enet.o
+SOBJS	=
 
-SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
-OBJS	:= $(addprefix $(obj),$(COBJS))
-SOBJS	:= $(addprefix $(obj),$(SOBJS))
+COBJS-$(CONFIG_LZO) += lzo1x_decompress.o
+
+COBJS	= $(COBJS-y)
+SRCS 	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
 
 $(LIB):	$(obj).depend $(OBJS)
 	$(AR) $(ARFLAGS) $@ $(OBJS)
diff --git a/lib_generic/lzo/lzo1x_decompress.c b/lib_generic/lzo/lzo1x_decompress.c
new file mode 100644
index 0000000..2780e11
--- /dev/null
+++ b/lib_generic/lzo/lzo1x_decompress.c
@@ -0,0 +1,245 @@
+/*
+ *  LZO1X Decompressor from MiniLZO
+ *
+ *  Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ *  The full LZO package can be found at:
+ *  http://www.oberhumer.com/opensource/lzo/
+ *
+ *  Changed for kernel use by:
+ *  Nitin Gupta <nitingupta910@gmail.com>
+ *  Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#include <common.h>
+#include <linux/lzo.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include "lzodefs.h"
+
+#define HAVE_IP(x, ip_end, ip) ((size_t)(ip_end - ip) < (x))
+#define HAVE_OP(x, op_end, op) ((size_t)(op_end - op) < (x))
+#define HAVE_LB(m_pos, out, op) (m_pos < out || m_pos >= op)
+
+#define COPY4(dst, src)	\
+		put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst))
+
+int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
+			unsigned char *out, size_t *out_len)
+{
+	const unsigned char * const ip_end = in + in_len;
+	unsigned char * const op_end = out + *out_len;
+	const unsigned char *ip = in, *m_pos;
+	unsigned char *op = out;
+	size_t t;
+
+	*out_len = 0;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		if (HAVE_OP(t, op_end, op))
+			goto output_overrun;
+		if (HAVE_IP(t + 1, ip_end, ip))
+			goto input_overrun;
+		do {
+			*op++ = *ip++;
+		} while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while ((ip < ip_end)) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		if (t == 0) {
+			if (HAVE_IP(1, ip_end, ip))
+				goto input_overrun;
+			while (*ip == 0) {
+				t += 255;
+				ip++;
+				if (HAVE_IP(1, ip_end, ip))
+					goto input_overrun;
+			}
+			t += 15 + *ip++;
+		}
+		if (HAVE_OP(t + 3, op_end, op))
+			goto output_overrun;
+		if (HAVE_IP(t + 4, ip_end, ip))
+			goto input_overrun;
+
+		COPY4(op, ip);
+		op += 4;
+		ip += 4;
+		if (--t > 0) {
+			if (t >= 4) {
+				do {
+					COPY4(op, ip);
+					op += 4;
+					ip += 4;
+					t -= 4;
+				} while (t >= 4);
+				if (t > 0) {
+					do {
+						*op++ = *ip++;
+					} while (--t > 0);
+				}
+			} else {
+				do {
+					*op++ = *ip++;
+				} while (--t > 0);
+			}
+		}
+
+first_literal_run:
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+
+		if (HAVE_LB(m_pos, out, op))
+			goto lookbehind_overrun;
+
+		if (HAVE_OP(3, op_end, op))
+			goto output_overrun;
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos;
+
+		goto match_done;
+
+		do {
+match:
+			if (t >= 64) {
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+				if (HAVE_LB(m_pos, out, op))
+					goto lookbehind_overrun;
+				if (HAVE_OP(t + 3 - 1, op_end, op))
+					goto output_overrun;
+				goto copy_match;
+			} else if (t >= 32) {
+				t &= 31;
+				if (t == 0) {
+					if (HAVE_IP(1, ip_end, ip))
+						goto input_overrun;
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						if (HAVE_IP(1, ip_end, ip))
+							goto input_overrun;
+					}
+					t += 31 + *ip++;
+				}
+				m_pos = op - 1;
+				m_pos -= get_unaligned_le16(ip) >> 2;
+				ip += 2;
+			} else if (t >= 16) {
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+
+				t &= 7;
+				if (t == 0) {
+					if (HAVE_IP(1, ip_end, ip))
+						goto input_overrun;
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						if (HAVE_IP(1, ip_end, ip))
+							goto input_overrun;
+					}
+					t += 7 + *ip++;
+				}
+				m_pos -= get_unaligned_le16(ip) >> 2;
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+			} else {
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+
+				if (HAVE_LB(m_pos, out, op))
+					goto lookbehind_overrun;
+				if (HAVE_OP(2, op_end, op))
+					goto output_overrun;
+
+				*op++ = *m_pos++;
+				*op++ = *m_pos;
+				goto match_done;
+			}
+
+			if (HAVE_LB(m_pos, out, op))
+				goto lookbehind_overrun;
+			if (HAVE_OP(t + 3 - 1, op_end, op))
+				goto output_overrun;
+
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+				COPY4(op, m_pos);
+				op += 4;
+				m_pos += 4;
+				t -= 4 - (3 - 1);
+				do {
+					COPY4(op, m_pos);
+					op += 4;
+					m_pos += 4;
+					t -= 4;
+				} while (t >= 4);
+				if (t > 0)
+					do {
+						*op++ = *m_pos++;
+					} while (--t > 0);
+			} else {
+copy_match:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+				do {
+					*op++ = *m_pos++;
+				} while (--t > 0);
+			}
+match_done:
+			t = ip[-2] & 3;
+			if (t == 0)
+				break;
+match_next:
+			if (HAVE_OP(t, op_end, op))
+				goto output_overrun;
+			if (HAVE_IP(t + 1, ip_end, ip))
+				goto input_overrun;
+
+			*op++ = *ip++;
+			if (t > 1) {
+				*op++ = *ip++;
+				if (t > 2)
+					*op++ = *ip++;
+			}
+
+			t = *ip++;
+		} while (ip < ip_end);
+	}
+
+	*out_len = op - out;
+	return LZO_E_EOF_NOT_FOUND;
+
+eof_found:
+	*out_len = op - out;
+	return (ip == ip_end ? LZO_E_OK :
+		(ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+input_overrun:
+	*out_len = op - out;
+	return LZO_E_INPUT_OVERRUN;
+
+output_overrun:
+	*out_len = op - out;
+	return LZO_E_OUTPUT_OVERRUN;
+
+lookbehind_overrun:
+	*out_len = op - out;
+	return LZO_E_LOOKBEHIND_OVERRUN;
+}
diff --git a/lib_generic/lzo/lzodefs.h b/lib_generic/lzo/lzodefs.h
new file mode 100644
index 0000000..b6d482c
--- /dev/null
+++ b/lib_generic/lzo/lzodefs.h
@@ -0,0 +1,43 @@
+/*
+ *  lzodefs.h -- architecture, OS and compiler specific defines
+ *
+ *  Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ *  The full LZO package can be found at:
+ *  http://www.oberhumer.com/opensource/lzo/
+ *
+ *  Changed for kernel use by:
+ *  Nitin Gupta <nitingupta910@gmail.com>
+ *  Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO_VERSION		0x2020
+#define LZO_VERSION_STRING	"2.02"
+#define LZO_VERSION_DATE	"Oct 17 2005"
+
+#define M1_MAX_OFFSET	0x0400
+#define M2_MAX_OFFSET	0x0800
+#define M3_MAX_OFFSET	0x4000
+#define M4_MAX_OFFSET	0xbfff
+
+#define M1_MIN_LEN	2
+#define M1_MAX_LEN	2
+#define M2_MIN_LEN	3
+#define M2_MAX_LEN	8
+#define M3_MIN_LEN	3
+#define M3_MAX_LEN	33
+#define M4_MIN_LEN	3
+#define M4_MAX_LEN	9
+
+#define M1_MARKER	0
+#define M2_MARKER	64
+#define M3_MARKER	32
+#define M4_MARKER	16
+
+#define D_BITS		14
+#define D_MASK		((1u << D_BITS) - 1)
+#define D_HIGH		((D_MASK >> 1) + 1)
+
+#define DX2(p, s1, s2)	(((((size_t)((p)[2]) << (s2)) ^ (p)[1]) \
+							<< (s1)) ^ (p)[0])
+#define DX3(p, s1, s2, s3)	((DX2((p)+1, s2, s3) << (s1)) ^ (p)[0])
diff --git a/lib_generic/vsprintf.c b/lib_generic/vsprintf.c
index 767dde1..3ab1f5c 100644
--- a/lib_generic/vsprintf.c
+++ b/lib_generic/vsprintf.c
@@ -21,6 +21,31 @@
 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
 #endif
 
+#ifdef CONFIG_SYS_64BIT_VSPRINTF
+# define NUM_TYPE long long
+#else
+# define NUM_TYPE long
+#endif
+#define noinline __attribute__((noinline))
+
+#define do_div(n, base) ({ \
+	unsigned int __res; \
+	__res = ((unsigned NUM_TYPE) n) % base; \
+	n = ((unsigned NUM_TYPE) n) / base; \
+	__res; \
+})
+
+const char hex_asc[] = "0123456789abcdef";
+#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
+#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
+
+static inline char *pack_hex_byte(char *buf, u8 byte)
+{
+	*buf++ = hex_asc_hi(byte);
+	*buf++ = hex_asc_lo(byte);
+	return buf;
+}
+
 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
 {
 	unsigned long result = 0,value;
@@ -120,52 +145,132 @@
 	return i;
 }
 
+/* Decimal conversion is by far the most typical, and is used
+ * for /proc and /sys data. This directly impacts e.g. top performance
+ * with many processes running. We optimize it for speed
+ * using code from
+ * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
+ * (with permission from the author, Douglas W. Jones). */
+
+/* Formats correctly any integer in [0,99999].
+ * Outputs from one to five digits depending on input.
+ * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
+static char* put_dec_trunc(char *buf, unsigned q)
+{
+	unsigned d3, d2, d1, d0;
+	d1 = (q>>4) & 0xf;
+	d2 = (q>>8) & 0xf;
+	d3 = (q>>12);
+
+	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+	q = (d0 * 0xcd) >> 11;
+	d0 = d0 - 10*q;
+	*buf++ = d0 + '0'; /* least significant digit */
+	d1 = q + 9*d3 + 5*d2 + d1;
+	if (d1 != 0) {
+		q = (d1 * 0xcd) >> 11;
+		d1 = d1 - 10*q;
+		*buf++ = d1 + '0'; /* next digit */
+
+		d2 = q + 2*d2;
+		if ((d2 != 0) || (d3 != 0)) {
+			q = (d2 * 0xd) >> 7;
+			d2 = d2 - 10*q;
+			*buf++ = d2 + '0'; /* next digit */
+
+			d3 = q + 4*d3;
+			if (d3 != 0) {
+				q = (d3 * 0xcd) >> 11;
+				d3 = d3 - 10*q;
+				*buf++ = d3 + '0';  /* next digit */
+				if (q != 0)
+					*buf++ = q + '0';  /* most sign. digit */
+			}
+		}
+	}
+	return buf;
+}
+/* Same with if's removed. Always emits five digits */
+static char* put_dec_full(char *buf, unsigned q)
+{
+	/* BTW, if q is in [0,9999], 8-bit ints will be enough, */
+	/* but anyway, gcc produces better code with full-sized ints */
+	unsigned d3, d2, d1, d0;
+	d1 = (q>>4) & 0xf;
+	d2 = (q>>8) & 0xf;
+	d3 = (q>>12);
+
+	/* Possible ways to approx. divide by 10 */
+	/* gcc -O2 replaces multiply with shifts and adds */
+	// (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
+	// (x * 0x67) >> 10:  1100111
+	// (x * 0x34) >> 9:    110100 - same
+	// (x * 0x1a) >> 8:     11010 - same
+	// (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
+
+	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+	q = (d0 * 0xcd) >> 11;
+	d0 = d0 - 10*q;
+	*buf++ = d0 + '0';
+	d1 = q + 9*d3 + 5*d2 + d1;
+		q = (d1 * 0xcd) >> 11;
+		d1 = d1 - 10*q;
+		*buf++ = d1 + '0';
+
+		d2 = q + 2*d2;
+			q = (d2 * 0xd) >> 7;
+			d2 = d2 - 10*q;
+			*buf++ = d2 + '0';
+
+			d3 = q + 4*d3;
+				q = (d3 * 0xcd) >> 11; /* - shorter code */
+				/* q = (d3 * 0x67) >> 10; - would also work */
+				d3 = d3 - 10*q;
+				*buf++ = d3 + '0';
+					*buf++ = q + '0';
+	return buf;
+}
+/* No inlining helps gcc to use registers better */
+static noinline char* put_dec(char *buf, unsigned NUM_TYPE num)
+{
+	while (1) {
+		unsigned rem;
+		if (num < 100000)
+			return put_dec_trunc(buf, num);
+		rem = do_div(num, 100000);
+		buf = put_dec_full(buf, rem);
+	}
+}
+
 #define ZEROPAD	1		/* pad with zero */
 #define SIGN	2		/* unsigned/signed long */
 #define PLUS	4		/* show plus */
 #define SPACE	8		/* space if plus */
 #define LEFT	16		/* left justified */
-#define SPECIAL	32		/* 0x */
-#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+#define SMALL	32		/* Must be 32 == 0x20 */
+#define SPECIAL	64		/* 0x */
 
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
-#define do_div(n,base) ({ \
-	unsigned int __res; \
-	__res = ((unsigned long long) n) % base; \
-	n = ((unsigned long long) n) / base; \
-	__res; \
-})
-#else
-#define do_div(n,base) ({ \
-	int __res; \
-	__res = ((unsigned long) n) % base; \
-	n = ((unsigned long) n) / base; \
-	__res; \
-})
-#endif
-
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
-static char * number(char * str, long long num, unsigned int base, int size, int precision ,int type)
-#else
-static char * number(char * str, long num, unsigned int base, int size, int precision ,int type)
-#endif
+static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int precision, int type)
 {
-	char c,sign,tmp[66];
-	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
+	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
+
+	char tmp[66];
+	char sign;
+	char locase;
+	int need_pfx = ((type & SPECIAL) && base != 10);
 	int i;
 
-	if (type & LARGE)
-		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
+	 * produces same digits or (maybe lowercased) letters */
+	locase = (type & SMALL);
 	if (type & LEFT)
 		type &= ~ZEROPAD;
-	if (base < 2 || base > 36)
-		return 0;
-	c = (type & ZEROPAD) ? '0' : ' ';
 	sign = 0;
 	if (type & SIGN) {
-		if (num < 0) {
+		if ((signed NUM_TYPE) num < 0) {
 			sign = '-';
-			num = -num;
+			num = - (signed NUM_TYPE) num;
 			size--;
 		} else if (type & PLUS) {
 			sign = '+';
@@ -175,68 +280,231 @@
 			size--;
 		}
 	}
-	if (type & SPECIAL) {
+	if (need_pfx) {
+		size--;
 		if (base == 16)
-			size -= 2;
-		else if (base == 8)
 			size--;
 	}
+
+	/* generate full string in tmp[], in reverse order */
 	i = 0;
 	if (num == 0)
-		tmp[i++]='0';
-	else while (num != 0)
-		tmp[i++] = digits[do_div(num,base)];
+		tmp[i++] = '0';
+	/* Generic code, for any base:
+	else do {
+		tmp[i++] = (digits[do_div(num,base)] | locase);
+	} while (num != 0);
+	*/
+	else if (base != 10) { /* 8 or 16 */
+		int mask = base - 1;
+		int shift = 3;
+		if (base == 16) shift = 4;
+		do {
+			tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
+			num >>= shift;
+		} while (num);
+	} else { /* base 10 */
+		i = put_dec(tmp, num) - tmp;
+	}
+
+	/* printing 100 using %2d gives "100", not "00" */
 	if (i > precision)
 		precision = i;
+	/* leading space padding */
 	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
+	if (!(type & (ZEROPAD+LEFT)))
+		while(--size >= 0)
+			*buf++ = ' ';
+	/* sign */
 	if (sign)
-		*str++ = sign;
-	if (type & SPECIAL) {
-		if (base==8)
-			*str++ = '0';
-		else if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
-		}
+		*buf++ = sign;
+	/* "0x" / "0" prefix */
+	if (need_pfx) {
+		*buf++ = '0';
+		if (base == 16)
+			*buf++ = ('X' | locase);
 	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
+	/* zero or space padding */
+	if (!(type & LEFT)) {
+		char c = (type & ZEROPAD) ? '0' : ' ';
+		while (--size >= 0)
+			*buf++ = c;
+	}
+	/* hmm even more zero padding? */
+	while (i <= --precision)
+		*buf++ = '0';
+	/* actual digits of result */
+	while (--i >= 0)
+		*buf++ = tmp[i];
+	/* trailing space padding */
+	while (--size >= 0)
+		*buf++ = ' ';
+	return buf;
 }
 
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
+static char *string(char *buf, char *s, int field_width, int precision, int flags)
+{
+	int len, i;
 
+	if (s == 0)
+		s = "<NULL>";
+
+	len = strnlen(s, precision);
+
+	if (!(flags & LEFT))
+		while (len < field_width--)
+			*buf++ = ' ';
+	for (i = 0; i < len; ++i)
+		*buf++ = *s++;
+	while (len < field_width--)
+		*buf++ = ' ';
+	return buf;
+}
+
+#ifdef CONFIG_CMD_NET
+static char *mac_address_string(char *buf, u8 *addr, int field_width,
+				int precision, int flags)
+{
+	char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
+	char *p = mac_addr;
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		p = pack_hex_byte(p, addr[i]);
+		if (!(flags & SPECIAL) && i != 5)
+			*p++ = ':';
+	}
+	*p = '\0';
+
+	return string(buf, mac_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip6_addr_string(char *buf, u8 *addr, int field_width,
+			 int precision, int flags)
+{
+	char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
+	char *p = ip6_addr;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		p = pack_hex_byte(p, addr[2 * i]);
+		p = pack_hex_byte(p, addr[2 * i + 1]);
+		if (!(flags & SPECIAL) && i != 7)
+			*p++ = ':';
+	}
+	*p = '\0';
+
+	return string(buf, ip6_addr, field_width, precision, flags & ~SPECIAL);
+}
+
+static char *ip4_addr_string(char *buf, u8 *addr, int field_width,
+			 int precision, int flags)
+{
+	char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
+	char temp[3];	/* hold each IP quad in reverse order */
+	char *p = ip4_addr;
+	int i, digits;
+
+	for (i = 0; i < 4; i++) {
+		digits = put_dec_trunc(temp, addr[i]) - temp;
+		/* reverse the digits in the quad */
+		while (digits--)
+			*p++ = temp[digits];
+		if (i != 3)
+			*p++ = '.';
+	}
+	*p = '\0';
+
+	return string(buf, ip4_addr, field_width, precision, flags & ~SPECIAL);
+}
+#endif
+
+/*
+ * Show a '%p' thing.  A kernel extension is that the '%p' is followed
+ * by an extra set of alphanumeric characters that are extended format
+ * specifiers.
+ *
+ * Right now we handle:
+ *
+ * - 'M' For a 6-byte MAC address, it prints the address in the
+ *       usual colon-separated hex notation
+ * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
+ *       decimal for v4 and colon separated network-order 16 bit hex for v6)
+ * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
+ *       currently the same
+ *
+ * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
+ * function pointers are really function descriptors, which contain a
+ * pointer to the real address.
+ */
+static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int precision, int flags)
+{
+	if (!ptr)
+		return string(buf, "(null)", field_width, precision, flags);
+
+#ifdef CONFIG_CMD_NET
+	switch (*fmt) {
+	case 'm':
+		flags |= SPECIAL;
+		/* Fallthrough */
+	case 'M':
+		return mac_address_string(buf, ptr, field_width, precision, flags);
+	case 'i':
+		flags |= SPECIAL;
+		/* Fallthrough */
+	case 'I':
+		if (fmt[1] == '6')
+			return ip6_addr_string(buf, ptr, field_width, precision, flags);
+		if (fmt[1] == '4')
+			return ip4_addr_string(buf, ptr, field_width, precision, flags);
+		flags &= ~SPECIAL;
+		break;
+	}
+#endif
+	flags |= SMALL;
+	if (field_width == -1) {
+		field_width = 2*sizeof(void *);
+		flags |= ZEROPAD;
+	}
+	return number(buf, (unsigned long) ptr, 16, field_width, precision, flags);
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * This function follows C99 vsprintf, but has some extensions:
+ * %pS output the name of a text symbol
+ * %pF output the name of a function pointer
+ * %pR output the address range in a struct resource
+ *
+ * The function returns the number of characters written
+ * into @buf.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf() instead.
+ */
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
-	int len;
-#ifdef CONFIG_SYS_64BIT_VSPRINTF
-	unsigned long long num;
-#else
-	unsigned long num;
-#endif
-	int i, base;
-	char * str;
-	const char *s;
+	unsigned NUM_TYPE num;
+	int base;
+	char *str;
 
 	int flags;		/* flags to number() */
 
 	int field_width;	/* width of output field */
 	int precision;		/* min. # of digits for integers; max
 				   number of chars for from string */
-	int qualifier;		/* 'h', 'l', or 'q' for integer fields */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+				/* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+				/* 't' added for ptrdiff_t */
 
-	for (str=buf ; *fmt ; ++fmt) {
+	str = buf;
+
+	for (; *fmt ; ++fmt) {
 		if (*fmt != '%') {
 			*str++ = *fmt;
 			continue;
@@ -252,7 +520,7 @@
 				case ' ': flags |= SPACE; goto repeat;
 				case '#': flags |= SPECIAL; goto repeat;
 				case '0': flags |= ZEROPAD; goto repeat;
-				}
+			}
 
 		/* get field width */
 		field_width = -1;
@@ -286,14 +554,13 @@
 		/* get the conversion qualifier */
 		qualifier = -1;
 		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
-		    *fmt == 'Z' || *fmt == 'z' || *fmt == 't' ||
-		    *fmt == 'q' ) {
+		    *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
 			qualifier = *fmt;
-			if (qualifier == 'l' && *(fmt+1) == 'l') {
-				qualifier = 'q';
+			++fmt;
+			if (qualifier == 'l' && *fmt == 'l') {
+				qualifier = 'L';
 				++fmt;
 			}
-			++fmt;
 		}
 
 		/* default base */
@@ -310,32 +577,18 @@
 			continue;
 
 		case 's':
-			s = va_arg(args, char *);
-			if (!s)
-				s = "<NULL>";
-
-			len = strnlen(s, precision);
-
-			if (!(flags & LEFT))
-				while (len < field_width--)
-					*str++ = ' ';
-			for (i = 0; i < len; ++i)
-				*str++ = *s++;
-			while (len < field_width--)
-				*str++ = ' ';
+			str = string(str, va_arg(args, char *), field_width, precision, flags);
 			continue;
 
 		case 'p':
-			if (field_width == -1) {
-				field_width = 2*sizeof(void *);
-				flags |= ZEROPAD;
-			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
+			str = pointer(fmt+1, str,
+					va_arg(args, void *),
+					field_width, precision, flags);
+			/* Skip all alphanumeric pointer suffixes */
+			while (isalnum(fmt[1]))
+				fmt++;
 			continue;
 
-
 		case 'n':
 			if (qualifier == 'l') {
 				long * ip = va_arg(args, long *);
@@ -355,9 +608,9 @@
 			base = 8;
 			break;
 
-		case 'X':
-			flags |= LARGE;
 		case 'x':
+			flags |= SMALL;
+		case 'X':
 			base = 16;
 			break;
 
@@ -376,12 +629,14 @@
 			continue;
 		}
 #ifdef CONFIG_SYS_64BIT_VSPRINTF
-		if (qualifier == 'q')  /* "quad" for 64 bit variables */
+		if (qualifier == 'L')  /* "quad" for 64 bit variables */
 			num = va_arg(args, unsigned long long);
 		else
 #endif
 		if (qualifier == 'l') {
 			num = va_arg(args, unsigned long);
+			if (flags & SIGN)
+				num = (signed long) num;
 		} else if (qualifier == 'Z' || qualifier == 'z') {
 			num = va_arg(args, size_t);
 		} else if (qualifier == 't') {
@@ -389,17 +644,29 @@
 		} else if (qualifier == 'h') {
 			num = (unsigned short) va_arg(args, int);
 			if (flags & SIGN)
-				num = (short) num;
-		} else if (flags & SIGN)
-			num = va_arg(args, int);
-		else
+				num = (signed short) num;
+		} else {
 			num = va_arg(args, unsigned int);
+			if (flags & SIGN)
+				num = (signed int) num;
+		}
 		str = number(str, num, base, field_width, precision, flags);
 	}
 	*str = '\0';
 	return str-buf;
 }
 
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf.
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
 int sprintf(char * buf, const char *fmt, ...)
 {
 	va_list args;
diff --git a/lib_i386/Makefile b/lib_i386/Makefile
index 4fbcd08..ec6f236 100644
--- a/lib_i386/Makefile
+++ b/lib_i386/Makefile
@@ -38,6 +38,10 @@
 COBJS-y	+= video_bios.o
 COBJS-y	+= video.o
 COBJS-y	+= zimage.o
+COBJS-y	+= interrupts.o
+COBJS-y	+= timer.o
+COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o
+COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o
 
 SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
diff --git a/lib_i386/board.c b/lib_i386/board.c
index 1734f86..e18dfa5 100644
--- a/lib_i386/board.c
+++ b/lib_i386/board.c
@@ -225,6 +225,9 @@
 	static bd_t bd_data;
 	init_fnc_t **init_fnc_ptr;
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	cmd_tbl_t *p;
+#endif
 	show_boot_progress(0x21);
 
 	gd = &gd_data;
@@ -238,6 +241,10 @@
 
 	gd->baudrate =  CONFIG_BAUDRATE;
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* Need to set relocation offset here for interrupt initialization */
+	gd->reloc_off =  CONFIG_SYS_BL_START_RAM - TEXT_BASE;
+#endif
 	for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
 		show_boot_progress(0xa130|i);
 
@@ -247,6 +254,26 @@
 	}
 	show_boot_progress(0x23);
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	for (p = &__u_boot_cmd_start; p != &__u_boot_cmd_end; p++) {
+		ulong addr;
+		addr = (ulong) (p->cmd) + gd->reloc_off;
+		p->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr;
+		addr = (ulong)(p->name) + gd->reloc_off;
+		p->name = (char *)addr;
+
+		if (p->usage != NULL) {
+			addr = (ulong)(p->usage) + gd->reloc_off;
+			p->usage = (char *)addr;
+		}
+	#ifdef	CONFIG_SYS_LONGHELP
+		if (p->help != NULL) {
+			addr = (ulong)(p->help) + gd->reloc_off;
+			p->help = (char *)addr;
+		}
+	#endif
+	}
+#endif
 	/* configure available FLASH banks */
 	size = flash_init();
 	display_flash_config(size);
@@ -262,23 +289,6 @@
 	/* IP Address */
 	bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
 
-	/* MAC Address */
-	{
-		int i;
-		ulong reg;
-		char *s, *e;
-		char tmp[64];
-
-		i = getenv_r ("ethaddr", tmp, sizeof (tmp));
-		s = (i > 0) ? tmp : NULL;
-
-		for (reg = 0; reg < 6; ++reg) {
-			bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
-	}
-
 #if defined(CONFIG_PCI)
 	/*
 	 * Do pci configuration
diff --git a/lib_i386/interrupts.c b/lib_i386/interrupts.c
new file mode 100644
index 0000000..3f3613a
--- /dev/null
+++ b/lib_i386/interrupts.c
@@ -0,0 +1,159 @@
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, graeme.russ@gmail.com
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com
+ *
+ * (C) Copyright 2006
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de
+ *
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * 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
+ */
+
+/*
+ * This file contains the high-level API for the interrupt sub-system
+ * of the i386 port of U-Boot. Most of the functionality has been
+ * shamelessly stolen from the leon2 / leon3 ports of U-Boot.
+ * Daniel Hellstrom, Detlev Zundel, Wolfgang Denk and Josh Huber are
+ * credited for the corresponding work on those ports. The original
+ * interrupt handling routines for the i386 port were written by
+ * Daniel Engström
+ */
+
+#include <common.h>
+#include <asm/interrupt.h>
+
+struct irq_action {
+	interrupt_handler_t *handler;
+	void *arg;
+	unsigned int count;
+};
+
+static struct irq_action irq_handlers[CONFIG_SYS_NUM_IRQS] = { {0} };
+static int spurious_irq_cnt = 0;
+static int spurious_irq = 0;
+
+void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
+{
+	int status;
+
+	if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+		printf("irq_install_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	if (irq_handlers[irq].handler != NULL)
+		printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+		       (ulong) handler + gd->reloc_off,
+		       (ulong) irq_handlers[irq].handler);
+
+	status = disable_interrupts ();
+
+	irq_handlers[irq].handler = handler + gd->reloc_off;
+	irq_handlers[irq].arg = arg;
+	irq_handlers[irq].count = 0;
+
+	unmask_irq(irq);
+
+	if (status)
+		enable_interrupts();
+
+	return;
+}
+
+void irq_free_handler(int irq)
+{
+	int status;
+
+	if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+		printf("irq_free_handler: bad irq number %d\n", irq);
+		return;
+	}
+
+	status = disable_interrupts ();
+
+	mask_irq(irq);
+
+	irq_handlers[irq].handler = NULL;
+	irq_handlers[irq].arg = NULL;
+
+	if (status)
+		enable_interrupts();
+
+	return;
+}
+
+__isr__ do_irq(int irq)
+{
+	if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
+		printf("do_irq: bad irq number %d\n", irq);
+		return;
+	}
+
+	if (irq_handlers[irq].handler) {
+		mask_irq(irq);
+
+		irq_handlers[irq].handler(irq_handlers[irq].arg);
+		irq_handlers[irq].count++;
+
+		unmask_irq(irq);
+		specific_eoi(irq);
+
+	} else {
+		if ((irq & 7) != 7) {
+			spurious_irq_cnt++;
+			spurious_irq = irq;
+		}
+	}
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int irq;
+
+	printf("Spurious IRQ: %u, last unknown IRQ: %d\n",
+	       spurious_irq_cnt, spurious_irq);
+
+	printf ("Interrupt-Information:\n");
+	printf ("Nr  Routine   Arg       Count\n");
+
+	for (irq = 0; irq <= CONFIG_SYS_NUM_IRQS; irq++) {
+		if (irq_handlers[irq].handler != NULL) {
+			printf ("%02d  %08lx  %08lx  %d\n",
+					irq,
+					(ulong)irq_handlers[irq].handler,
+					(ulong)irq_handlers[irq].arg,
+					irq_handlers[irq].count);
+		}
+	}
+
+	return 0;
+}
+#endif
diff --git a/lib_i386/pcat_interrupts.c b/lib_i386/pcat_interrupts.c
new file mode 100644
index 0000000..f01298e
--- /dev/null
+++ b/lib_i386/pcat_interrupts.c
@@ -0,0 +1,165 @@
+/*
+ * (C) Copyright 2009
+ * Graeme Russ, graeme.russ@gmail.com
+ *
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * 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
+ */
+
+/*
+ * This file provides the interrupt handling functionality for systems
+ * based on the standard PC/AT architecture using two cascaded i8259
+ * Programmable Interrupt Controllers.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include <asm/ibmpc.h>
+#include <asm/interrupt.h>
+
+#if CONFIG_SYS_NUM_IRQS != 16
+#error "CONFIG_SYS_NUM_IRQS must equal 16 if CONFIG_SYS_NUM_IRQS is defined"
+#endif
+
+DECLARE_INTERRUPT(0);
+DECLARE_INTERRUPT(1);
+DECLARE_INTERRUPT(3);
+DECLARE_INTERRUPT(4);
+DECLARE_INTERRUPT(5);
+DECLARE_INTERRUPT(6);
+DECLARE_INTERRUPT(7);
+DECLARE_INTERRUPT(8);
+DECLARE_INTERRUPT(9);
+DECLARE_INTERRUPT(10);
+DECLARE_INTERRUPT(11);
+DECLARE_INTERRUPT(12);
+DECLARE_INTERRUPT(13);
+DECLARE_INTERRUPT(14);
+DECLARE_INTERRUPT(15);
+
+int interrupt_init(void)
+{
+	u8 i;
+
+	disable_interrupts();
+
+	/* Setup interrupts */
+	set_vector(0x20, irq_0);
+	set_vector(0x21, irq_1);
+	set_vector(0x23, irq_3);
+	set_vector(0x24, irq_4);
+	set_vector(0x25, irq_5);
+	set_vector(0x26, irq_6);
+	set_vector(0x27, irq_7);
+	set_vector(0x28, irq_8);
+	set_vector(0x29, irq_9);
+	set_vector(0x2a, irq_10);
+	set_vector(0x2b, irq_11);
+	set_vector(0x2c, irq_12);
+	set_vector(0x2d, irq_13);
+	set_vector(0x2e, irq_14);
+	set_vector(0x2f, irq_15);
+
+	/* Mask all interrupts */
+	outb(0xff, MASTER_PIC + IMR);
+	outb(0xff, SLAVE_PIC + IMR);
+
+	/* Master PIC */
+	/* Place master PIC interrupts at INT20 */
+	/* ICW3, One slave PIC is present */
+	outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
+	outb(0x20, MASTER_PIC + ICW2);
+	outb(IR2, MASTER_PIC + ICW3);
+	outb(ICW4_PM, MASTER_PIC + ICW4);
+
+	for (i = 0; i < 8; i++)
+		outb(OCW2_SEOI | i, MASTER_PIC + OCW2);
+
+	/* Slave PIC */
+	/* Place slave PIC interrupts at INT28 */
+	/* Slave ID */
+	outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
+	outb(0x28, SLAVE_PIC + ICW2);
+	outb(0x02, SLAVE_PIC + ICW3);
+	outb(ICW4_PM, SLAVE_PIC + ICW4);
+
+	for (i = 0; i < 8; i++)
+		outb(OCW2_SEOI | i, SLAVE_PIC + OCW2);
+
+	/*
+	 * Enable cascaded interrupts by unmasking the cascade IRQ pin of
+	 * the master PIC
+	 */
+	unmask_irq (2);
+
+	enable_interrupts();
+
+	return 0;
+}
+
+void mask_irq(int irq)
+{
+	int imr_port;
+
+	if (irq >= CONFIG_SYS_NUM_IRQS)
+		return;
+
+	if (irq > 7)
+		imr_port = SLAVE_PIC + IMR;
+	else
+		imr_port = MASTER_PIC + IMR;
+
+	outb(inb(imr_port) | (1 << (irq & 7)), imr_port);
+}
+
+void unmask_irq(int irq)
+{
+	int imr_port;
+
+	if (irq >= CONFIG_SYS_NUM_IRQS)
+		return;
+
+	if (irq > 7)
+		imr_port = SLAVE_PIC + IMR;
+	else
+		imr_port = MASTER_PIC + IMR;
+
+	outb(inb(imr_port) & ~(1 << (irq & 7)), imr_port);
+}
+
+void specific_eoi(int irq)
+{
+	if (irq >= CONFIG_SYS_NUM_IRQS)
+		return;
+
+	if (irq > 7) {
+		/*
+		 *  IRQ is on the slave - Issue a corresponding EOI to the
+		 *  slave PIC and an EOI for IRQ2 (the cascade interrupt)
+		 *  on the master PIC
+		 */
+		outb(OCW2_SEOI | (irq & 7), SLAVE_PIC + OCW2);
+		irq = SEOI_IR2;
+	}
+
+	outb(OCW2_SEOI | irq, MASTER_PIC + OCW2);
+}
diff --git a/lib_i386/pcat_timer.c b/lib_i386/pcat_timer.c
new file mode 100644
index 0000000..e282f64
--- /dev/null
+++ b/lib_i386/pcat_timer.c
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * 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 <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
+#define TIMER2_VALUE 0x0a8e /* 440Hz */
+
+int timer_init(void)
+{
+	/* initialize timer 0 and 2
+	 *
+	 * Timer 0 is used to increment system_tick 1000 times/sec
+	 * Timer 1 was used for DRAM refresh in early PC's
+	 * Timer 2 is used to drive the speaker
+	 * (to stasrt a beep: write 3 to port 0x61,
+	 * to stop it again: write 0)
+	 */
+	outb (PIT_CMD_CTR0 | PIT_CMD_BOTH | PIT_CMD_MODE2,
+	      PIT_BASE + PIT_COMMAND);
+	outb (TIMER0_VALUE & 0xff, PIT_BASE + PIT_T0);
+	outb (TIMER0_VALUE >> 8, PIT_BASE + PIT_T0);
+
+	outb (PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
+	      PIT_BASE + PIT_COMMAND);
+	outb (TIMER2_VALUE & 0xff, PIT_BASE + PIT_T2);
+	outb (TIMER2_VALUE >> 8, PIT_BASE + PIT_T2);
+
+	irq_install_handler (0, timer_isr, NULL);
+	unmask_irq (0);
+
+	return 0;
+}
+
+static u16 read_pit(void)
+{
+	u8 low;
+
+	outb (PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
+	low = inb (PIT_BASE + PIT_T0);
+
+	return ((inb (PIT_BASE + PIT_T0) << 8) | low);
+}
+
+/* this is not very exact */
+void udelay (unsigned long usec)
+{
+	int counter;
+	int wraps;
+
+	if (timer_init_done)
+	{
+		counter = read_pit ();
+		wraps = usec / 1000;
+		usec = usec % 1000;
+
+		usec *= 1194;
+		usec /= 1000;
+		usec += counter;
+
+		while (usec > 1194) {
+			usec -= 1194;
+			wraps++;
+		}
+
+		while (1) {
+			int new_count = read_pit ();
+
+			if (((new_count < usec) && !wraps) || wraps < 0)
+				break;
+
+			if (new_count > counter)
+				wraps--;
+
+			counter = new_count;
+		}
+	}
+
+}
diff --git a/lib_i386/timer.c b/lib_i386/timer.c
new file mode 100644
index 0000000..58a0212
--- /dev/null
+++ b/lib_i386/timer.c
@@ -0,0 +1,107 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * 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 <malloc.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+struct timer_isr_function {
+	struct timer_isr_function *next;
+	timer_fnc_t *isr_func;
+};
+
+static struct timer_isr_function *first_timer_isr = NULL;
+static volatile unsigned long system_ticks = 0;
+
+/*
+ * register_timer_isr() allows multiple architecture and board specific
+ * functions to be called every millisecond. Keep the execution time of
+ * each function as low as possible
+ */
+int register_timer_isr (timer_fnc_t *isr_func)
+{
+	struct timer_isr_function *new_func;
+	struct timer_isr_function *temp;
+	int flag;
+
+	new_func = malloc(sizeof(struct timer_isr_function));
+
+	if (new_func == NULL)
+		return 1;
+
+	new_func->isr_func = isr_func + gd->reloc_off;
+	new_func->next = NULL;
+
+	/*
+	 *  Don't allow timer interrupts while the
+	 *  linked list is being modified
+	 */
+	flag = disable_interrupts ();
+
+	if (first_timer_isr == NULL) {
+		first_timer_isr = new_func;
+	} else {
+		temp = first_timer_isr;
+		while (temp->next != NULL)
+			temp = temp->next;
+		temp->next = new_func;
+	}
+
+	if (flag)
+		enable_interrupts ();
+
+	return 0;
+}
+
+/*
+ * timer_isr() MUST be the registered interrupt handler for
+ */
+void timer_isr(void *unused)
+{
+	struct timer_isr_function *temp = first_timer_isr;
+
+	system_ticks++;
+
+	/* Execute each registered function */
+	while (temp != NULL) {
+		temp->isr_func ();
+		temp = temp->next;
+	}
+}
+
+void reset_timer (void)
+{
+	system_ticks = 0;
+}
+
+ulong get_timer (ulong base)
+{
+	return (system_ticks - base);
+}
+
+void set_timer (ulong t)
+{
+	system_ticks = t;
+}
diff --git a/lib_m68k/board.c b/lib_m68k/board.c
index 583ce10..db45b00 100644
--- a/lib_m68k/board.c
+++ b/lib_m68k/board.c
@@ -584,44 +584,6 @@
 	 * where had to use getenv_r(), which can be pretty slow when
 	 * the environment is in EEPROM.
 	 */
-	s = getenv ("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#ifdef CONFIG_HAS_ETH1
-	/* handle the 2nd ethernet address */
-
-	s = getenv ("eth1addr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet1addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-#ifdef CONFIG_HAS_ETH2
-	/* handle the 3rd ethernet address */
-
-	s = getenv ("eth2addr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet2addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
-#ifdef CONFIG_HAS_ETH3
-	/* handle 4th ethernet address */
-	s = getenv("eth3addr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet3addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
-	/* IP Address */
 	bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 
 	WATCHDOG_RESET ();
diff --git a/lib_microblaze/board.c b/lib_microblaze/board.c
index 30d7641..1a42640 100644
--- a/lib_microblaze/board.c
+++ b/lib_microblaze/board.c
@@ -173,14 +173,6 @@
 #endif
 
 #if defined(CONFIG_CMD_NET)
-	/* board MAC address */
-	s = getenv ("ethaddr");
-	printf ("MAC:%s\n",s);
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
 	/* IP Address */
 	bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 	eth_init (bd);
diff --git a/lib_mips/board.c b/lib_mips/board.c
index dfe6831..6fc4845 100644
--- a/lib_mips/board.c
+++ b/lib_mips/board.c
@@ -401,14 +401,6 @@
 	/* relocate environment function pointers etc. */
 	env_relocate();
 
-	/* board MAC address */
-	s = getenv ("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-
 	/* IP Address */
 	bd->bi_ip_addr = getenv_IPaddr("ipaddr");
 
diff --git a/lib_nios/board.c b/lib_nios/board.c
index 024beb5..63e79ae 100644
--- a/lib_nios/board.c
+++ b/lib_nios/board.c
@@ -151,11 +151,6 @@
 	env_relocate();
 
 	bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-	s = getenv ("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s) s = (*e) ? e + 1 : e;
-	}
 
 	WATCHDOG_RESET ();
 	devices_init();
diff --git a/lib_nios2/board.c b/lib_nios2/board.c
index d759f0f..70fad1b 100644
--- a/lib_nios2/board.c
+++ b/lib_nios2/board.c
@@ -157,11 +157,6 @@
 	env_relocate();
 
 	bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-	s = getenv ("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s) s = (*e) ? e + 1 : e;
-	}
 
 	WATCHDOG_RESET ();
 	devices_init();
diff --git a/lib_ppc/board.c b/lib_ppc/board.c
index 3bcfb45..3b93e4e 100644
--- a/lib_ppc/board.c
+++ b/lib_ppc/board.c
@@ -339,9 +339,6 @@
 #if defined(CONFIG_HARD_SPI)
 	init_func_spi,
 #endif
-#if defined(CONFIG_DTT)		/* Digital Thermometers and Thermostats */
-	dtt_init,
-#endif
 #ifdef CONFIG_POST
 	post_init_f,
 #endif
@@ -648,9 +645,8 @@
 void board_init_r (gd_t *id, ulong dest_addr)
 {
 	cmd_tbl_t *cmdtp;
-	char *s, *e;
+	char *s;
 	bd_t *bd;
-	int i;
 	extern void malloc_bin_reloc (void);
 #ifndef CONFIG_ENV_IS_NOWHERE
 	extern char * env_name_spec;
@@ -739,8 +735,7 @@
 
 	WATCHDOG_RESET();
 
-#if defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || \
-	defined (CONFIG_FLAGADM) || defined(CONFIG_MPC83XX)
+#if defined(CONFIG_SYS_DELAYED_ICACHE) || defined(CONFIG_MPC83XX)
 	icache_enable ();	/* it's time to enable the instruction cache */
 #endif
 
@@ -882,20 +877,6 @@
 	mac_read_from_eeprom();
 #endif
 
-	s = getenv ("ethaddr");
-#if defined (CONFIG_MBX) || \
-    defined (CONFIG_RPXCLASSIC) || \
-    defined(CONFIG_IAD210) || \
-    defined(CONFIG_V38B)
-	if (s == NULL)
-		board_get_enetaddr (bd->bi_enetaddr);
-	else
-#endif
-		for (i = 0; i < 6; ++i) {
-			bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-			if (s)
-				s = (*e) ? e + 1 : e;
-		}
 #ifdef	CONFIG_HERMES
 	if ((gd->board_type >> 16) == 2)
 		bd->bi_ethspeed = gd->board_type & 0xFFFF;
@@ -903,88 +884,26 @@
 		bd->bi_ethspeed = 0xFFFF;
 #endif
 
-#ifdef CONFIG_NX823
-	load_sernum_ethaddr ();
-#endif
-
+#ifdef CONFIG_CMD_NET
+	/* kept around for legacy kernels only ... ignore the next section */
+	eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
 #ifdef CONFIG_HAS_ETH1
-	/* handle the 2nd ethernet address */
-
-	s = getenv ("eth1addr");
-
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet1addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
+	eth_getenv_enetaddr("eth1addr", bd->bi_enet1addr);
 #endif
 #ifdef CONFIG_HAS_ETH2
-	/* handle the 3rd ethernet address */
-
-	s = getenv ("eth2addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
-	if (s == NULL)
-		board_get_enetaddr(bd->bi_enet2addr);
-	else
+	eth_getenv_enetaddr("eth2addr", bd->bi_enet2addr);
 #endif
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet2addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
 #ifdef CONFIG_HAS_ETH3
-	/* handle 4th ethernet address */
-	s = getenv("eth3addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
-	if (s == NULL)
-		board_get_enetaddr(bd->bi_enet3addr);
-	else
+	eth_getenv_enetaddr("eth3addr", bd->bi_enet3addr);
 #endif
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet3addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
 #ifdef CONFIG_HAS_ETH4
-	/* handle 5th ethernet address */
-	s = getenv("eth4addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
-	if (s == NULL)
-		board_get_enetaddr(bd->bi_enet4addr);
-	else
+	eth_getenv_enetaddr("eth4addr", bd->bi_enet4addr);
 #endif
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet4addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
 #ifdef CONFIG_HAS_ETH5
-	/* handle 6th ethernet address */
-	s = getenv("eth5addr");
-#if defined(CONFIG_XPEDITE1K) || defined(CONFIG_METROBOX) || defined(CONFIG_KAREF)
-	if (s == NULL)
-		board_get_enetaddr(bd->bi_enet5addr);
-	else
+	eth_getenv_enetaddr("eth5addr", bd->bi_enet5addr);
 #endif
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet5addr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
+#endif /* CONFIG_CMD_NET */
 
-#if defined(CONFIG_TQM8xxL) || defined(CONFIG_TQM8260) || \
-    defined(CONFIG_TQM8272) || \
-    defined(CONFIG_CCM) || defined(CONFIG_KUP4K) || \
-    defined(CONFIG_KUP4X) || defined(CONFIG_PCS440EP)
-	load_sernum_ethaddr ();
-#endif
 	/* IP Address */
 	bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 
@@ -1072,6 +991,9 @@
 
 	WATCHDOG_RESET ();
 
+#if defined(CONFIG_DTT)		/* Digital Thermometers and Thermostats */
+	dtt_init ();
+#endif
 #if defined(CONFIG_CMD_SCSI)
 	WATCHDOG_RESET ();
 	puts ("SCSI:  ");
diff --git a/lib_sh/board.c b/lib_sh/board.c
index d4cc85c..2fd213b 100644
--- a/lib_sh/board.c
+++ b/lib_sh/board.c
@@ -125,17 +125,7 @@
 static int sh_net_init(void)
 {
 	DECLARE_GLOBAL_DATA_PTR;
-	char *s, *e;
-	int i;
-
 	gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-	s = getenv("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		gd->bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-
 	return 0;
 }
 #endif
diff --git a/lib_sparc/board.c b/lib_sparc/board.c
index e972d3e..2f3e673 100644
--- a/lib_sparc/board.c
+++ b/lib_sparc/board.c
@@ -390,25 +390,6 @@
 	board_late_init();
 #endif
 
-	s = getenv("ethaddr");
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-
-#ifdef CONFIG_HAS_ETH1
-	/* handle the 2nd ethernet address */
-
-	s = getenv("eth1addr");
-
-	for (i = 0; i < 6; ++i) {
-		bd->bi_enet1addr[i] = s ? simple_strtoul(s, &e, 16) : 0;
-		if (s)
-			s = (*e) ? e + 1 : e;
-	}
-#endif
-
 #ifdef CONFIG_ID_EEPROM
 	mac_read_from_eeprom();
 #endif
diff --git a/nand_spl/board/amcc/acadia/u-boot.lds b/nand_spl/board/amcc/acadia/u-boot.lds
index ab42701..b89cd80 100644
--- a/nand_spl/board/amcc/acadia/u-boot.lds
+++ b/nand_spl/board/amcc/acadia/u-boot.lds
@@ -42,7 +42,7 @@
 
   .data    :
   {
-    *(.rodata*)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
     *(.data*)
     *(.sdata*)
     __got2_start = .;
diff --git a/nand_spl/board/amcc/bamboo/u-boot.lds b/nand_spl/board/amcc/bamboo/u-boot.lds
index b13168f..d171269 100644
--- a/nand_spl/board/amcc/bamboo/u-boot.lds
+++ b/nand_spl/board/amcc/bamboo/u-boot.lds
@@ -44,7 +44,7 @@
 
   .data    :
   {
-    *(.rodata*)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
     *(.data*)
     *(.sdata*)
     __got2_start = .;
diff --git a/nand_spl/board/amcc/canyonlands/u-boot.lds b/nand_spl/board/amcc/canyonlands/u-boot.lds
index ef6d560..e676e0c 100644
--- a/nand_spl/board/amcc/canyonlands/u-boot.lds
+++ b/nand_spl/board/amcc/canyonlands/u-boot.lds
@@ -44,7 +44,7 @@
 
   .data    :
   {
-    *(.rodata*)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
     *(.data*)
     *(.sdata*)
     __got2_start = .;
diff --git a/nand_spl/board/amcc/kilauea/u-boot.lds b/nand_spl/board/amcc/kilauea/u-boot.lds
index 1335532..5a586fc 100644
--- a/nand_spl/board/amcc/kilauea/u-boot.lds
+++ b/nand_spl/board/amcc/kilauea/u-boot.lds
@@ -42,7 +42,7 @@
 
   .data    :
   {
-    *(.rodata*)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
     *(.data*)
     *(.sdata*)
     __got2_start = .;
diff --git a/nand_spl/board/amcc/sequoia/u-boot.lds b/nand_spl/board/amcc/sequoia/u-boot.lds
index d38d097..1601c36 100644
--- a/nand_spl/board/amcc/sequoia/u-boot.lds
+++ b/nand_spl/board/amcc/sequoia/u-boot.lds
@@ -44,7 +44,7 @@
 
   .data    :
   {
-    *(.rodata*)
+    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
     *(.data*)
     *(.sdata*)
     __got2_start = .;
diff --git a/nand_spl/board/freescale/mpc8313erdb/u-boot.lds b/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
index 40c4145..ad82589 100644
--- a/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
+++ b/nand_spl/board/freescale/mpc8313erdb/u-boot.lds
@@ -30,8 +30,8 @@
 	.text : {
 		*(.text*)
 		. = ALIGN(16);
-		*(.rodata*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/nand_spl/board/samsung/smdk6400/u-boot.lds b/nand_spl/board/samsung/smdk6400/u-boot.lds
index eb8910c..56e1015 100644
--- a/nand_spl/board/samsung/smdk6400/u-boot.lds
+++ b/nand_spl/board/samsung/smdk6400/u-boot.lds
@@ -42,7 +42,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/nand_spl/board/sheldon/simpc8313/Makefile b/nand_spl/board/sheldon/simpc8313/Makefile
index 416e176..20199c7 100644
--- a/nand_spl/board/sheldon/simpc8313/Makefile
+++ b/nand_spl/board/sheldon/simpc8313/Makefile
@@ -62,31 +62,40 @@
 # create symbolic links for common files
 
 $(obj)start.S:
-	ln -sf $(SRCTREE)/cpu/mpc83xx/start.S $<
+	@rm -f $@
+	ln -s $(SRCTREE)/cpu/mpc83xx/start.S $@
 
 $(obj)nand_boot_fsl_elbc.c:
-	ln -sf $(SRCTREE)/nand_spl/nand_boot_fsl_elbc.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/nand_spl/nand_boot_fsl_elbc.c $@
 
 $(obj)sdram.c:
-	ln -sf $(SRCTREE)/board/$(BOARDDIR)/sdram.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/board/$(BOARDDIR)/sdram.c $@
 
 $(obj)$(BOARD).c:
-	ln -sf $(SRCTREE)/board/$(BOARDDIR)/$(BOARD).c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/board/$(BOARDDIR)/$(BOARD).c $@
 
 $(obj)ns16550.c:
-	ln -sf $(SRCTREE)/drivers/serial/ns16550.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/drivers/serial/ns16550.c $@
 
 $(obj)nand_init.c:
-	ln -sf $(SRCTREE)/cpu/mpc83xx/nand_init.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/cpu/mpc83xx/nand_init.c $@
 
 $(obj)cache.c:
-	ln -sf $(SRCTREE)/lib_ppc/cache.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/lib_ppc/cache.c $@
 
 $(obj)time.c:
-	ln -sf $(SRCTREE)/lib_ppc/time.c $<
+	@rm -f $@
+	ln -s $(SRCTREE)/lib_ppc/time.c $@
 
 $(obj)ticks.S:
-	ln -sf $(SRCTREE)/lib_ppc/ticks.S $<
+	@rm -f $@
+	ln -s $(SRCTREE)/lib_ppc/ticks.S $@
 
 #########################################################################
 
diff --git a/nand_spl/board/sheldon/simpc8313/u-boot.lds b/nand_spl/board/sheldon/simpc8313/u-boot.lds
index 40c4145..ad82589 100644
--- a/nand_spl/board/sheldon/simpc8313/u-boot.lds
+++ b/nand_spl/board/sheldon/simpc8313/u-boot.lds
@@ -30,8 +30,8 @@
 	.text : {
 		*(.text*)
 		. = ALIGN(16);
-		*(.rodata*)
 		*(.eh_frame)
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
 	}
 
 	. = ALIGN(8);
diff --git a/net/bootp.c b/net/bootp.c
index 83465e4..3dea70aa 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -271,17 +271,11 @@
 
 #ifdef DEBUG_BOOTP_EXT
 	puts ("[BOOTP] Received fields: \n");
-	if (NetOurSubnetMask) {
-		puts ("NetOurSubnetMask : ");
-		print_IPaddr (NetOurSubnetMask);
-		putc ('\n');
-	}
+	if (NetOurSubnetMask)
+		printf ("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
 
-	if (NetOurGatewayIP) {
-		puts ("NetOurGatewayIP	: ");
-		print_IPaddr (NetOurGatewayIP);
-		putc ('\n');
-	}
+	if (NetOurGatewayIP)
+		printf ("NetOurGatewayIP	: %pI4", &NetOurGatewayIP);
 
 	if (NetBootFileSize) {
 		printf ("NetBootFileSize : %d\n", NetBootFileSize);
@@ -579,21 +573,12 @@
 #ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
 	unsigned char bi_enetaddr[6];
 	int   reg;
-	char  *e,*s;
-	char tmp[64];
 	ulong tst1, tst2, sum, m_mask, m_value = 0;
 
 	if (BootpTry ==0) {
 		/* get our mac */
-		reg = getenv_r ("ethaddr", tmp, sizeof(tmp));
-		s = (reg > 0) ? tmp : NULL;
+		eth_getenv_enetaddr("ethaddr", bi_enetaddr);
 
-		for (reg=0; reg<6; ++reg) {
-			bi_enetaddr[reg] = s ? simple_strtoul(s, &e, 16) : 0;
-			if (s) {
-				s = (*e) ? e+1 : e;
-			}
-		}
 #ifdef DEBUG
 		puts ("BootpRequest => Our Mac: ");
 		for (reg=0; reg<6; reg++) {
@@ -942,9 +927,7 @@
 				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
 			BootpCopyNetParams(bp); /* Store net params from reply */
 			dhcp_state = BOUND;
-			puts ("DHCP client bound to address ");
-			print_IPaddr(NetOurIP);
-			putc ('\n');
+			printf ("DHCP client bound to address %pI4\n", &NetOurIP);
 
 			/* Obey the 'autoload' setting */
 			if ((s = getenv("autoload")) != NULL) {
diff --git a/net/eth.c b/net/eth.c
index ec2ef1a..4bbf84b 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -26,8 +26,40 @@
 #include <net.h>
 #include <miiphy.h>
 
+#ifdef CONFIG_CMD_NET
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+	char *end;
+	int i;
+
+	for (i = 0; i < 6; ++i) {
+		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+		if (addr)
+			addr = (*end) ? end + 1 : end;
+	}
+}
+
+int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+{
+	eth_parse_enetaddr(getenv(name), enetaddr);
+	return is_valid_ether_addr(enetaddr);
+}
+
+int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+{
+	char buf[20];
+
+	sprintf(buf, "%pM", enetaddr);
+
+	return setenv(name, buf);
+}
+#endif
+
 #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI)
 
+static char *act = NULL;
+static int  env_changed_id = 0;
+
 /*
  * CPU and board-specific Ethernet initializations.  Aliased function
  * signals caller to move on
@@ -153,8 +185,7 @@
 {
 	char enetvar[32];
 	unsigned char env_enetaddr[6];
-	int i, eth_number = 0;
-	char *tmp, *end;
+	int eth_number = 0;
 
 	eth_devices = NULL;
 	eth_current = NULL;
@@ -194,13 +225,7 @@
 			}
 
 			sprintf(enetvar, eth_number ? "eth%daddr" : "ethaddr", eth_number);
-			tmp = getenv (enetvar);
-
-			for (i=0; i<6; i++) {
-				env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
-				if (tmp)
-					tmp = (*end) ? end+1 : end;
-			}
+			eth_getenv_enetaddr(enetvar, env_enetaddr);
 
 			if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
 				if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
@@ -208,16 +233,10 @@
 				{
 					printf ("\nWarning: %s MAC addresses don't match:\n",
 						dev->name);
-					printf ("Address in SROM is         "
-					       "%02X:%02X:%02X:%02X:%02X:%02X\n",
-					       dev->enetaddr[0], dev->enetaddr[1],
-					       dev->enetaddr[2], dev->enetaddr[3],
-					       dev->enetaddr[4], dev->enetaddr[5]);
-					printf ("Address in environment is  "
-					       "%02X:%02X:%02X:%02X:%02X:%02X\n",
-					       env_enetaddr[0], env_enetaddr[1],
-					       env_enetaddr[2], env_enetaddr[3],
-					       env_enetaddr[4], env_enetaddr[5]);
+					printf ("Address in SROM is         %pM\n",
+						dev->enetaddr);
+					printf ("Address in environment is  %pM\n",
+						env_enetaddr);
 				}
 
 				memcpy(dev->enetaddr, env_enetaddr, 6);
@@ -246,19 +265,13 @@
 void eth_set_enetaddr(int num, char *addr) {
 	struct eth_device *dev;
 	unsigned char enetaddr[6];
-	char *end;
-	int i;
 
 	debug ("eth_set_enetaddr(num=%d, addr=%s)\n", num, addr);
 
 	if (!eth_devices)
 		return;
 
-	for (i=0; i<6; i++) {
-		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
-		if (addr)
-			addr = (*end) ? end+1 : end;
-	}
+	eth_parse_enetaddr(addr, enetaddr);
 
 	dev = eth_devices;
 	while(num-- > 0) {
@@ -269,11 +282,8 @@
 	}
 
 	debug ( "Setting new HW address on %s\n"
-		"New Address is             %02X:%02X:%02X:%02X:%02X:%02X\n",
-		dev->name,
-		enetaddr[0], enetaddr[1],
-		enetaddr[2], enetaddr[3],
-		enetaddr[4], enetaddr[5]);
+		"New Address is             %pM\n",
+		dev->name, enetaddr);
 
 	memcpy(dev->enetaddr, enetaddr, 6);
 }
@@ -461,13 +471,17 @@
 #ifdef CONFIG_NET_MULTI
 void eth_set_current(void)
 {
-	char *act;
 	struct eth_device* old_current;
+	int	env_id;
 
 	if (!eth_current)	/* XXX no current */
 		return;
 
-	act = getenv("ethact");
+	env_id = get_env_id();
+	if ((act == NULL) || (env_changed_id != env_id)) {
+		act = getenv("ethact");
+		env_changed_id = env_id;
+	}
 	if (act != NULL) {
 		old_current = eth_current;
 		do {
diff --git a/net/net.c b/net/net.c
index 459baf4..a89f6a0 100644
--- a/net/net.c
+++ b/net/net.c
@@ -209,6 +209,8 @@
 ulong		NetArpWaitTimerStart;
 int		NetArpWaitTry;
 
+int		env_changed_id = 0;
+
 void ArpRequest (void)
 {
 	int i;
@@ -276,70 +278,15 @@
 	}
 }
 
-/**********************************************************************/
-/*
- *	Main network processing loop.
- */
-
 int
-NetLoop(proto_t protocol)
+NetInitLoop(proto_t protocol)
 {
 	bd_t *bd = gd->bd;
+	int env_id = get_env_id ();
 
-#ifdef CONFIG_NET_MULTI
-	NetRestarted = 0;
-	NetDevExists = 0;
-#endif
-
-	/* XXX problem with bss workaround */
-	NetArpWaitPacketMAC = NULL;
-	NetArpWaitTxPacket = NULL;
-	NetArpWaitPacketIP = 0;
-	NetArpWaitReplyIP = 0;
-	NetArpWaitTxPacket = NULL;
-	NetTxPacket = NULL;
-
-	if (!NetTxPacket) {
-		int	i;
-		/*
-		 *	Setup packet buffers, aligned correctly.
-		 */
-		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
-		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
-		for (i = 0; i < PKTBUFSRX; i++) {
-			NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
-		}
-	}
-
-	if (!NetArpWaitTxPacket) {
-		NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
-		NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
-		NetArpWaitTxPacketSize = 0;
-	}
-
-	eth_halt();
-#ifdef CONFIG_NET_MULTI
-	eth_set_current();
-#endif
-	if (eth_init(bd) < 0) {
-		eth_halt();
-		return(-1);
-	}
-
-restart:
-#ifdef CONFIG_NET_MULTI
-	memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
-#else
-	memcpy (NetOurEther, bd->bi_enetaddr, 6);
-#endif
-
-	NetState = NETLOOP_CONTINUE;
-
-	/*
-	 *	Start the ball rolling with the given start function.  From
-	 *	here on, this code is a state machine driven by received
-	 *	packets and timer events.
-	 */
+	/* update only when the environment has changed */
+	if (env_changed_id == env_id)
+		return 0;
 
 	switch (protocol) {
 #if defined(CONFIG_CMD_NFS)
@@ -399,6 +346,75 @@
 	default:
 		break;
 	}
+	env_changed_id = env_id;
+	return 0;
+}
+
+/**********************************************************************/
+/*
+ *	Main network processing loop.
+ */
+
+int
+NetLoop(proto_t protocol)
+{
+	bd_t *bd = gd->bd;
+
+#ifdef CONFIG_NET_MULTI
+	NetRestarted = 0;
+	NetDevExists = 0;
+#endif
+
+	/* XXX problem with bss workaround */
+	NetArpWaitPacketMAC = NULL;
+	NetArpWaitTxPacket = NULL;
+	NetArpWaitPacketIP = 0;
+	NetArpWaitReplyIP = 0;
+	NetArpWaitTxPacket = NULL;
+	NetTxPacket = NULL;
+
+	if (!NetTxPacket) {
+		int	i;
+		/*
+		 *	Setup packet buffers, aligned correctly.
+		 */
+		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
+		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
+		for (i = 0; i < PKTBUFSRX; i++) {
+			NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
+		}
+	}
+
+	if (!NetArpWaitTxPacket) {
+		NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
+		NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
+		NetArpWaitTxPacketSize = 0;
+	}
+
+	eth_halt();
+#ifdef CONFIG_NET_MULTI
+	eth_set_current();
+#endif
+	if (eth_init(bd) < 0) {
+		eth_halt();
+		return(-1);
+	}
+
+restart:
+#ifdef CONFIG_NET_MULTI
+	memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
+#else
+	eth_getenv_enetaddr("ethaddr", NetOurEther);
+#endif
+
+	NetState = NETLOOP_CONTINUE;
+
+	/*
+	 *	Start the ball rolling with the given start function.  From
+	 *	here on, this code is a state machine driven by received
+	 *	packets and timer events.
+	 */
+	NetInitLoop(protocol);
 
 	switch (net_check_prereq (protocol)) {
 	case 1:
@@ -693,8 +709,7 @@
 	}
 
 #ifdef ET_DEBUG
-	printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
-		dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
+	printf("sending UDP to %08lx/%pM\n", dest, ether);
 #endif
 
 	pkt = (uchar *)NetTxPacket;
@@ -915,11 +930,7 @@
 #ifdef CONFIG_CDP_DEVICE_ID
 	*s++ = htons(CDP_DEVICE_ID_TLV);
 	*s++ = htons(CONFIG_CDP_DEVICE_ID);
-	memset(buf, 0, sizeof(buf));
-	sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%02X%02X%02X%02X%02X%02X",
-		NetOurEther[0] & 0xff, NetOurEther[1] & 0xff,
-		NetOurEther[2] & 0xff, NetOurEther[3] & 0xff,
-		NetOurEther[4] & 0xff, NetOurEther[5] & 0xff);
+	sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
 	memcpy((uchar *)s, buf, 16);
 	s += 16 / 2;
 #endif
@@ -1319,10 +1330,8 @@
 			if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
 				break;
 #ifdef ET_DEBUG
-			printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
-				arp->ar_data[0], arp->ar_data[1],
-				arp->ar_data[2], arp->ar_data[3],
-				arp->ar_data[4], arp->ar_data[5]);
+			printf("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
+				arp->ar_data);
 #endif
 
 			tmp = NetReadIP(&arp->ar_data[6]);
@@ -1445,9 +1454,7 @@
 			case ICMP_REDIRECT:
 				if (icmph->code != ICMP_REDIR_HOST)
 					return;
-				puts (" ICMP Host Redirect to ");
-				print_IPaddr(icmph->un.gateway);
-				putc(' ');
+				printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);
 				return;
 #if defined(CONFIG_CMD_PING)
 			case ICMP_ECHO_REPLY:
@@ -1789,15 +1796,6 @@
 	return htons(id);
 }
 
-void print_IPaddr (IPaddr_t x)
-{
-	char tmp[16];
-
-	ip_to_string (x, tmp);
-
-	puts (tmp);
-}
-
 IPaddr_t getenv_IPaddr (char *var)
 {
 	return (string_to_ip(getenv(var)));
diff --git a/net/nfs.c b/net/nfs.c
index f290014..0101629 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -741,18 +741,16 @@
 	printf ("Using %s device\n", eth_get_name());
 #endif
 
-	puts ("File transfer via NFS from server "); print_IPaddr (NfsServerIP);
-	puts ("; our IP address is ");		    print_IPaddr (NetOurIP);
+	printf("File transfer via NFS from server %pI4"
+		"; our IP address is %pI4", &NfsServerIP, &NetOurIP);
 
 	/* Check if we need to send across this subnet */
 	if (NetOurGatewayIP && NetOurSubnetMask) {
 		IPaddr_t OurNet	    = NetOurIP	  & NetOurSubnetMask;
 		IPaddr_t ServerNet  = NetServerIP & NetOurSubnetMask;
 
-		if (OurNet != ServerNet) {
-			puts ("; sending through gateway ");
-			print_IPaddr (NetOurGatewayIP) ;
-		}
+		if (OurNet != ServerNet)
+			printf("; sending through gateway %pI4", &NetOurGatewayIP);
 	}
 	printf ("\nFilename '%s/%s'.", nfs_path, nfs_filename);
 
diff --git a/net/tftp.c b/net/tftp.c
index 3dac3d8..b0f1cca 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -508,18 +508,16 @@
 #if defined(CONFIG_NET_MULTI)
 	printf ("Using %s device\n", eth_get_name());
 #endif
-	puts ("TFTP from server ");	print_IPaddr (TftpServerIP);
-	puts ("; our IP address is ");	print_IPaddr (NetOurIP);
+	printf("TFTP from server %pI4"
+		"; our IP address is %pI4", &TftpServerIP, &NetOurIP);
 
 	/* Check if we need to send across this subnet */
 	if (NetOurGatewayIP && NetOurSubnetMask) {
 	    IPaddr_t OurNet	= NetOurIP    & NetOurSubnetMask;
 	    IPaddr_t ServerNet	= TftpServerIP & NetOurSubnetMask;
 
-	    if (OurNet != ServerNet) {
-		puts ("; sending through gateway ");
-		print_IPaddr (NetOurGatewayIP) ;
-	    }
+	    if (OurNet != ServerNet)
+		printf("; sending through gateway %pI4", &NetOurGatewayIP);
 	}
 	putc ('\n');
 
diff --git a/onenand_ipl/board/apollon/u-boot.onenand.lds b/onenand_ipl/board/apollon/u-boot.onenand.lds
index c8b00a1..0960c12 100644
--- a/onenand_ipl/board/apollon/u-boot.onenand.lds
+++ b/onenand_ipl/board/apollon/u-boot.onenand.lds
@@ -38,7 +38,7 @@
 	}
 
 	. = ALIGN(4);
-	.rodata : { *(.rodata) }
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 	. = ALIGN(4);
 	.data : { *(.data) }
diff --git a/post/cpu/mpc8xx/ether.c b/post/cpu/mpc8xx/ether.c
index 5622cb7..fe6c39e 100644
--- a/post/cpu/mpc8xx/ether.c
+++ b/post/cpu/mpc8xx/ether.c
@@ -110,6 +110,7 @@
 static void scc_init (int scc_index)
 {
 	bd_t *bd = gd->bd;
+	uchar ea[6];
 
 	static int proff[] =
 			{ PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 };
@@ -296,11 +297,10 @@
 	pram_ptr->sen_gaddr3 = 0x0;	/* Group Address Filter 3 (unused) */
 	pram_ptr->sen_gaddr4 = 0x0;	/* Group Address Filter 4 (unused) */
 
-#define ea bd->bi_enetaddr
+	eth_getenv_enetaddr("ethaddr", ea);
 	pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
 	pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
 	pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
-#undef ea
 
 	pram_ptr->sen_pper = 0x0;	/* Persistence (unused) */
 	pram_ptr->sen_iaddr1 = 0x0;	/* Individual Address Filter 1 (unused) */