summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Waters <justin.waters@timesys.com>2012-04-17 13:43:17 -0400
committerJustin Waters <justin.waters@timesys.com>2012-04-17 13:43:17 -0400
commit4f60d7e7027af17ceffc1a38e6dbe4e3e95c71ec (patch)
treedd33f3760e08226d5c05036d664d2d68fb3765dc
parentb1af6f532e0d348b153d5c148369229d24af361a (diff)
LogicPD Support for OMAP3/DM3/AM3 boards
From Logic BSP-2.0-5-01
-rw-r--r--Makefile25
-rw-r--r--README6
-rw-r--r--arch/arm/cpu/armv7/omap-common/timer.c54
-rw-r--r--arch/arm/cpu/armv7/omap3/Makefile2
-rw-r--r--arch/arm/cpu/armv7/omap3/board.c47
-rw-r--r--arch/arm/cpu/armv7/omap3/sdrc.c41
-rw-r--r--arch/arm/cpu/armv7/start.S10
-rw-r--r--arch/arm/cpu/armv7/u-boot.lds6
-rw-r--r--arch/arm/include/asm/arch-omap3/cpu.h8
-rw-r--r--arch/arm/include/asm/arch-omap3/dss.h213
-rw-r--r--arch/arm/include/asm/arch-omap3/mmc_host_def.h1
-rw-r--r--arch/arm/include/asm/arch-omap3/omap3.h22
-rw-r--r--arch/arm/include/asm/arch-omap3/omap_gpmc.h19
-rw-r--r--arch/arm/include/asm/arch-omap3/sys_proto.h11
-rw-r--r--arch/arm/include/asm/arch-omap3/timer.h25
-rw-r--r--arch/arm/include/asm/global_data.h11
-rw-r--r--arch/arm/include/asm/u-boot-arm.h4
-rw-r--r--arch/arm/lib/board.c18
-rw-r--r--board/ti/logic/Makefile50
-rw-r--r--board/ti/logic/config.mk33
-rw-r--r--board/ti/logic/logic-at24.c149
-rw-r--r--board/ti/logic/logic-at24.h24
-rw-r--r--board/ti/logic/logic-at88.c117
-rw-r--r--board/ti/logic/logic-at88.h23
-rw-r--r--board/ti/logic/logic-data.c643
-rw-r--r--board/ti/logic/logic-data.h23
-rw-r--r--board/ti/logic/logic-display.c889
-rw-r--r--board/ti/logic/logic-gpio.c161
-rw-r--r--board/ti/logic/logic-gpio.h28
-rw-r--r--board/ti/logic/logic-i2c.c242
-rw-r--r--board/ti/logic/logic-i2c.h48
-rw-r--r--board/ti/logic/logic-id-data.h156
-rw-r--r--board/ti/logic/logic-product-id.c285
-rw-r--r--board/ti/logic/logic-product-id.h27
-rw-r--r--board/ti/logic/logic-proto.h26
-rw-r--r--board/ti/logic/logic.c1300
-rw-r--r--board/ti/logic/logic.h412
-rw-r--r--board/ti/logic/prod-id/crc-15.c31
-rw-r--r--board/ti/logic/prod-id/crc-15.h3
-rw-r--r--board/ti/logic/prod-id/debug.h12
-rw-r--r--board/ti/logic/prod-id/dict.c47
-rw-r--r--board/ti/logic/prod-id/extract.c70
-rw-r--r--board/ti/logic/prod-id/id-errno.h10
-rw-r--r--board/ti/logic/prod-id/interface.h105
-rw-r--r--board/ti/logic/prod-id/internals.h19
-rw-r--r--board/ti/logic/prod-id/keys.h95
-rw-r--r--board/ti/logic/prod-id/query.c184
-rw-r--r--board/ti/logic/prod-id/size.c49
-rw-r--r--board/ti/logic/prod-id/startup.c185
-rw-r--r--board/ti/logic/prod-id/type.c20
-rw-r--r--board/ti/logic/product_id.h160
-rw-r--r--board/ti/logic/splash-332x57.h367
-rw-r--r--board/ti/logic/splash-480x272.h408
-rw-r--r--boards.cfg1
-rw-r--r--common/Makefile1
-rw-r--r--common/cmd_bdinfo.c20
-rw-r--r--common/cmd_cache.c14
-rw-r--r--common/cmd_flash.c15
-rw-r--r--common/cmd_jffs2.c6
-rw-r--r--common/cmd_mem.c47
-rw-r--r--common/cmd_misc.c43
-rw-r--r--common/cmd_mtdparts.c91
-rw-r--r--common/cmd_nand.c34
-rw-r--r--common/cmd_nvedit.c12
-rw-r--r--common/cmd_yaffs2.c153
-rw-r--r--common/env_common.c17
-rw-r--r--common/env_nand.c161
-rw-r--r--common/lcd.c500
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/twl4030-gpio.c105
-rw-r--r--drivers/gpio/twl4030-pwm.c126
-rw-r--r--drivers/i2c/omap24xx_i2c.c4
-rw-r--r--drivers/mmc/omap3_mmc.c82
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/mtd_debug.c18
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/nand_base.c239
-rw-r--r--drivers/mtd/nand/nand_bch.c287
-rw-r--r--drivers/mtd/nand/nand_util.c32
-rw-r--r--drivers/mtd/nand/omap_gpmc.c425
-rw-r--r--drivers/power/twl4030.c517
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/omap3_dss.c343
-rw-r--r--fs/Makefile1
-rw-r--r--fs/fat/fat.c70
-rw-r--r--fs/yaffs2-new/Makefile63
-rw-r--r--fs/yaffs2-new/devextras.h113
-rw-r--r--fs/yaffs2-new/yaffs_allocator.c357
-rw-r--r--fs/yaffs2-new/yaffs_allocator.h30
-rw-r--r--fs/yaffs2-new/yaffs_attribs.c124
-rw-r--r--fs/yaffs2-new/yaffs_attribs.h28
-rw-r--r--fs/yaffs2-new/yaffs_bitmap.c97
-rw-r--r--fs/yaffs2-new/yaffs_bitmap.h33
-rw-r--r--fs/yaffs2-new/yaffs_checkptrw.c408
-rw-r--r--fs/yaffs2-new/yaffs_checkptrw.h33
-rw-r--r--fs/yaffs2-new/yaffs_direct.h8
-rw-r--r--fs/yaffs2-new/yaffs_ecc.c281
-rw-r--r--fs/yaffs2-new/yaffs_ecc.h44
-rw-r--r--fs/yaffs2-new/yaffs_getblockinfo.h35
-rw-r--r--fs/yaffs2-new/yaffs_guts.c4991
-rw-r--r--fs/yaffs2-new/yaffs_guts.h938
-rw-r--r--fs/yaffs2-new/yaffs_malloc.h39
-rw-r--r--fs/yaffs2-new/yaffs_mtdif.c53
-rw-r--r--fs/yaffs2-new/yaffs_mtdif.h23
-rw-r--r--fs/yaffs2-new/yaffs_mtdif2.h29
-rw-r--r--fs/yaffs2-new/yaffs_mtdif2_single.c209
-rw-r--r--fs/yaffs2-new/yaffs_nameval.c207
-rw-r--r--fs/yaffs2-new/yaffs_nameval.h28
-rw-r--r--fs/yaffs2-new/yaffs_nand.c120
-rw-r--r--fs/yaffs2-new/yaffs_nand.h38
-rw-r--r--fs/yaffs2-new/yaffs_packedtags2.c181
-rw-r--r--fs/yaffs2-new/yaffs_packedtags2.h47
-rw-r--r--fs/yaffs2-new/yaffs_qsort.c163
-rw-r--r--fs/yaffs2-new/yaffs_summary.c252
-rw-r--r--fs/yaffs2-new/yaffs_summary.h37
-rw-r--r--fs/yaffs2-new/yaffs_tagscompat.c407
-rw-r--r--fs/yaffs2-new/yaffs_tagscompat.h36
-rw-r--r--fs/yaffs2-new/yaffs_trace.h57
-rw-r--r--fs/yaffs2-new/yaffs_uboot.c258
-rw-r--r--fs/yaffs2-new/yaffs_verify.c525
-rw-r--r--fs/yaffs2-new/yaffs_verify.h43
-rw-r--r--fs/yaffs2-new/yaffs_yaffs1.c424
-rw-r--r--fs/yaffs2-new/yaffs_yaffs1.h22
-rw-r--r--fs/yaffs2-new/yaffs_yaffs2.c1532
-rw-r--r--fs/yaffs2-new/yaffs_yaffs2.h39
-rw-r--r--fs/yaffs2-new/yaffscfg.h45
-rw-r--r--fs/yaffs2-new/yaffsfs.c1741
-rw-r--r--fs/yaffs2-new/yaffsfs.h64
-rw-r--r--fs/yaffs2-new/yaffsfs_errno.c119
-rw-r--r--fs/yaffs2-new/yaffsfs_errno.h120
-rw-r--r--fs/yaffs2-new/ydirectenv.h97
-rw-r--r--fs/yaffs2-new/yportenv.h239
-rw-r--r--fs/yaffs2/devextras.h164
-rw-r--r--fs/yaffs2/yaffs_guts.c50
-rw-r--r--fs/yaffs2/yaffs_guts.h6
-rw-r--r--fs/yaffs2/yaffs_malloc.h6
-rw-r--r--fs/yaffs2/yaffs_mtdif2.c2
-rw-r--r--fs/yaffs2/yaffs_mtdif2.h2
-rw-r--r--fs/yaffs2/yaffs_nand.c2
-rw-r--r--fs/yaffs2/yaffs_nand.h2
-rw-r--r--fs/yaffs2/yaffs_tagscompat.c2
-rw-r--r--fs/yaffs2/yaffs_tagscompat.h2
-rw-r--r--fs/yaffs2/yaffscfg.c238
-rw-r--r--fs/yaffs2/yaffsfs.c211
-rw-r--r--fs/yaffs2/ydirectenv.h10
-rw-r--r--fs/yaffs2/yportenv.h2
-rw-r--r--include/common.h15
-rw-r--r--include/configs/omap3logic.h633
-rw-r--r--include/environment.h3
-rw-r--r--include/jffs2/load_kernel.h2
-rw-r--r--include/lcd.h38
-rw-r--r--include/linux/bch.h79
-rw-r--r--include/linux/mtd/compat.h10
-rw-r--r--include/linux/mtd/mtd.h4
-rw-r--r--include/linux/mtd/nand.h32
-rw-r--r--include/linux/mtd/nand_bch.h72
-rw-r--r--include/mtd_parts.h35
-rw-r--r--include/nand.h4
-rw-r--r--include/twl4030.h87
-rw-r--r--lib/Makefile1
-rw-r--r--lib/bch.c1409
-rwxr-xr-xmkconfig37
-rw-r--r--tools/Makefile6
-rw-r--r--tools/sign-nand-image.c80
164 files changed, 27564 insertions, 753 deletions
diff --git a/Makefile b/Makefile
index 3454db62d7..1440c06ba0 100644
--- a/Makefile
+++ b/Makefile
@@ -88,7 +88,7 @@ endif
ifdef O
ifeq ("$(origin O)", "command line")
-BUILD_DIR := $(O)
+export BUILD_DIR := $(O)
endif
endif
@@ -99,7 +99,7 @@ saved-output := $(BUILD_DIR)
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})
# Verify if it was successful.
-BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
+export BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)
@@ -225,7 +225,7 @@ LIBS += arch/arm/cpu/ixp/npe/libnpe.o
endif
LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
- fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
+ fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2-new/libyaffs2-new.o \
fs/ubifs/libubifs.o
LIBS += net/libnet.o
LIBS += disk/libdisk.o
@@ -356,6 +356,10 @@ ifeq ($(CONFIG_MMC_U_BOOT),y)
ALL += $(obj)mmc_spl/u-boot-mmc-spl.bin
endif
+ifeq ($(CONFIG_TOOL_SIGNGP),y)
+ALL += $(obj)u-boot.bin.ift
+endif
+
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
@@ -368,6 +372,9 @@ $(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(BOARD_SIZE_CHECK)
+$(obj)u-boot.bin.ift: $(obj)u-boot.bin
+ tools/sign-nand-image u-boot.bin $(CONFIG_SYS_TEXT_BASE)
+
$(obj)u-boot.ldr: $(obj)u-boot
$(CREATE_LDR_ENV)
$(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS)
@@ -539,8 +546,8 @@ $(VERSION_FILE):
@( localvers='$(shell $(TOPDIR)/tools/setlocalversion $(TOPDIR))' ; \
printf '#define PLAIN_VERSION "%s%s"\n' \
"$(U_BOOT_VERSION)" "$${localvers}" ; \
- printf '#define U_BOOT_VERSION "U-Boot %s%s"\n' \
- "$(U_BOOT_VERSION)" "$${localvers}" ; \
+ printf '#define U_BOOT_VERSION "U-Boot %s%s %s"\n' \
+ "$(U_BOOT_VERSION)" "$${localvers}" "$(BSP_RELEASE_LEVEL)"; \
) > $@.tmp
@( printf '#define CC_VERSION_STRING "%s"\n' \
'$(shell $(CC) --version | head -n 1)' )>> $@.tmp
@@ -565,9 +572,7 @@ include/license.h: tools/bin2header COPYING
#########################################################################
unconfig:
- @rm -f $(obj)include/config.h $(obj)include/config.mk \
- $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
- $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep
+ @rm -f $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp
%_config:: unconfig
@$(MKCONFIG) -A $(@:_config=)
@@ -1120,6 +1125,10 @@ clobber: clean
@[ ! -d $(obj)nand_spl ] || find $(obj)nand_spl -name "*" -type l -print | xargs rm -f
@[ ! -d $(obj)onenand_ipl ] || find $(obj)onenand_ipl -name "*" -type l -print | xargs rm -f
@[ ! -d $(obj)mmc_spl ] || find $(obj)mmc_spl -name "*" -type l -print | xargs rm -f
+ @rm -f $(obj)include/config.h $(obj)include/config.mk \
+ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
+ $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep
+
ifeq ($(OBJTREE),$(SRCTREE))
mrproper \
diff --git a/README b/README
index 446966dc16..9637ea405e 100644
--- a/README
+++ b/README
@@ -2408,6 +2408,12 @@ Configuration Settings:
Enables allocating and saving a kernel copy of the bd_info in
space between "bootm_low" and "bootm_low" + BOOTMAPSZ.
+- CONFIG_SYS_FLASH_PRESENCE
+ If defined is checked and if zero then board_init_r
+ skips calling flash_init. Used in cases where board
+ has optional NOR flash (and when not present does not
+ setup chip select to allow access).
+
- CONFIG_SYS_MAX_FLASH_BANKS:
Max number of Flash memory banks
diff --git a/arch/arm/cpu/armv7/omap-common/timer.c b/arch/arm/cpu/armv7/omap-common/timer.c
index 9beebb1e74..c4f245492f 100644
--- a/arch/arm/cpu/armv7/omap-common/timer.c
+++ b/arch/arm/cpu/armv7/omap-common/timer.c
@@ -33,18 +33,21 @@
*/
#include <common.h>
+#include <errno.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
static struct gptimer *timer_base = (struct gptimer *)CONFIG_SYS_TIMERBASE;
+
/*
* Nothing really to do with interrupts, just starts up a counter.
*/
#define TIMER_CLOCK (V_SCLK / (2 << CONFIG_SYS_PTV))
-#define TIMER_LOAD_VAL 0xffffffff
+#define TIMER_OVERFLOW_VAL 0xffffffff
+#define TIMER_LOAD_VAL 0
int timer_init(void)
{
@@ -86,7 +89,7 @@ void __udelay(unsigned long usec)
while (tmo > 0) {
now = readl(&timer_base->tcrr);
if (last > now) /* count up timer overflow */
- tmo -= TIMER_LOAD_VAL - last + now;
+ tmo -= TIMER_OVERFLOW_VAL - last + now;
else
tmo -= now - last;
last = now;
@@ -132,3 +135,50 @@ ulong get_tbclk(void)
{
return CONFIG_SYS_HZ;
}
+
+int init_gpt_timer(u32 timer, u32 value, u32 range)
+{
+ struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+ struct gptimer *timer_base;
+ u32 reg;
+
+ switch(timer) {
+ case 10:
+ writel(readl(&prcm_base->clksel_core) | (1 << 6), &prcm_base->clksel_core);
+ writel(readl(&prcm_base->fclken1_core) | (1 << 11), &prcm_base->fclken1_core);
+ writel(readl(&prcm_base->iclken1_core) | (1 << 11), &prcm_base->iclken1_core);
+ timer_base = (struct gptimer *)OMAP34XX_GPT10;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ /* dm_timer_set_load */
+ reg = readl(&timer_base->tclr);
+ reg |= TCLR_AR;
+ writel(reg, &timer_base->tclr);
+ writel(0xffff0000, &timer_base->tldr);
+ writel(0, &timer_base->ttgr);
+
+ /* dm_set_pwm */
+ reg = readl(&timer_base->tclr);
+ reg &= ~(TCLR_GPO_CFG | TCLR_SCPWM | TCLR_PT | (0x03 << 10));
+ reg |= TCLR_PT;
+ reg |= (0x2 << 10); /* OVERFLOW_AND_COMPARE */
+ writel(reg, &timer_base->tclr);
+
+ /* dm_set_match */
+ reg = readl(&timer_base->tclr);
+ reg |= TCLR_CE;
+ writel(reg, &timer_base->tclr);
+ writel(0xffff0000 | (((value * 0xff) / range) << 8), &timer_base->tmar);
+
+ /* dm_timer_start */
+ reg = readl(&timer_base->tclr);
+ if (!(reg & TCLR_ST)) {
+ reg |= TCLR_ST;
+ writel(reg | TCLR_ST, &timer_base->tclr);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/cpu/armv7/omap3/Makefile b/arch/arm/cpu/armv7/omap3/Makefile
index 7164d505b9..1a540b545a 100644
--- a/arch/arm/cpu/armv7/omap3/Makefile
+++ b/arch/arm/cpu/armv7/omap3/Makefile
@@ -37,7 +37,7 @@ COBJS += sys_info.o
COBJS-$(CONFIG_EMIF4) += emif4.o
COBJS-$(CONFIG_SDRC) += sdrc.o
-SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS) $(COBJS-y) $(SOBJS))
all: $(obj).depend $(LIB)
diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c
index 6c2a132b63..18133d876d 100644
--- a/arch/arm/cpu/armv7/omap3/board.c
+++ b/arch/arm/cpu/armv7/omap3/board.c
@@ -37,6 +37,7 @@
#include <asm/arch/sys_proto.h>
#include <asm/arch/mem.h>
#include <asm/cache.h>
+#include <nand.h>
extern omap3_sysinfo sysinfo;
@@ -249,12 +250,48 @@ void abort(void)
*****************************************************************************/
static int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
+ struct mtd_info *mtd;
+ struct nand_chip *nand;
+
+ /* the following commands operat on the current device */
+ if (nand_curr_device > 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[nand_curr_device].name) {
+ printf("\nno NAND devices available\n");
+ return 1;
+ }
+ mtd = &nand_info[nand_curr_device];
+ nand = mtd->priv;
+
+ if (argc == 1) {
+ switch (nand->ecc.mode) {
+ case NAND_ECC_SOFT:
+ printf("Software ECC\n");
+ break;
+ case NAND_ECC_HW:
+ printf("Hardware ECC\n");
+ break;
+ case NAND_ECC_CHIP:
+ printf("Internal to NAND Hardware ECC\n");
+ break;
+ case NAND_ECC_SOFT_BCH:
+ printf("Software BCH ECC\n");
+ break;
+ default:
+ printf("Unknown ECC method %d!\n", nand->ecc.mode);
+ return -1;
+ }
+ return 0;
+ }
if (argc != 2)
goto usage;
- if (strncmp(argv[1], "hw", 2) == 0)
- omap_nand_switch_ecc(1);
- else if (strncmp(argv[1], "sw", 2) == 0)
- omap_nand_switch_ecc(0);
+ if (strcmp(argv[1], "hw") == 0)
+ omap_nand_switch_ecc(OMAP_ECC_HW);
+ else if (strcmp(argv[1], "sw") == 0)
+ omap_nand_switch_ecc(OMAP_ECC_SOFT);
+ else if (strcmp(argv[1], "chip") == 0)
+ omap_nand_switch_ecc(OMAP_ECC_CHIP);
+ else if (strcmp(argv[1], "bch") == 0)
+ omap_nand_switch_ecc(OMAP_ECC_SOFT_BCH);
else
goto usage;
@@ -268,7 +305,7 @@ usage:
U_BOOT_CMD(
nandecc, 2, 1, do_switch_ecc,
"switch OMAP3 NAND ECC calculation algorithm",
- "[hw/sw] - Switch between NAND hardware (hw) or software (sw) ecc algorithm"
+ "[hw/sw/chip] - Switch between NAND hardware (hw), software (sw),\n in-chip (chip) ecc algorithm, or BCH (bch) ecc algorithm"
);
#endif /* CONFIG_NAND_OMAP_GPMC */
diff --git a/arch/arm/cpu/armv7/omap3/sdrc.c b/arch/arm/cpu/armv7/omap3/sdrc.c
index 2a7970b4d0..f592388e86 100644
--- a/arch/arm/cpu/armv7/omap3/sdrc.c
+++ b/arch/arm/cpu/armv7/omap3/sdrc.c
@@ -215,3 +215,44 @@ void mem_init(void)
/* only init up first bank here */
do_sdrc_init(CS0, EARLY_INIT);
}
+
+#ifdef CONFIG_CMD_SDRC_CONFIG
+static void dump_sdrc_config(int cs)
+{
+ struct sdrc_actim *sdrc_actim_base;
+
+ if(cs)
+ sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL1_BASE;
+ else
+ sdrc_actim_base = (struct sdrc_actim *)SDRC_ACTIM_CTRL0_BASE;
+
+ printf("cs%d: mcfg %08x mr %08x rfr_ctrl %08x emr2 %08x\n",
+ cs, readl(&sdrc_base->cs[cs].mcfg),
+ readl(&sdrc_base->cs[cs].mr),
+ readl(&sdrc_base->cs[cs].rfr_ctrl),
+ readl(&sdrc_base->cs[cs].emr2));
+ printf("cs%d: ctrla %08x ctrlb %08x\n",
+ cs,
+ readl(&sdrc_actim_base->ctrla),
+ readl(&sdrc_actim_base->ctrlb));
+}
+
+int do_dump_sdrc_config(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("sysconfig %08x sharing %08x dlla_ctrl %08x",
+ readl(&sdrc_base->sysconfig),
+ readl(&sdrc_base->sharing),
+ readl(&sdrc_base->dlla_ctrl));
+ printf(" cs_cfg %08x\n",
+ readl(&sdrc_base->cs_cfg));
+
+ dump_sdrc_config(0);
+ dump_sdrc_config(1);
+ return 0;
+}
+
+U_BOOT_CMD(sdrc_config, 1, 1, do_dump_sdrc_config,
+ "sdrc_config - dump SDRC registers",
+ ""
+);
+#endif
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index d91ae12cb9..35e1031e7e 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -97,6 +97,16 @@ _bss_end_ofs:
_end_ofs:
.word _end - _start
+#ifdef CONFIG_GDB_SECTION_STARTS
+.globl _data_start_ofs
+_data_start_ofs:
+ .word __data_start - _start
+
+.globl _rodata_start_ofs
+_rodata_start_ofs:
+ .word __rodata_start - _start
+#endif
+
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
diff --git a/arch/arm/cpu/armv7/u-boot.lds b/arch/arm/cpu/armv7/u-boot.lds
index dbae54d4f8..31abfbcb3c 100644
--- a/arch/arm/cpu/armv7/u-boot.lds
+++ b/arch/arm/cpu/armv7/u-boot.lds
@@ -39,10 +39,14 @@ SECTIONS
}
. = ALIGN(4);
- .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+ .rodata : {
+ __rodata_start = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
. = ALIGN(4);
.data : {
+ __data_start = .;
*(.data)
}
diff --git a/arch/arm/include/asm/arch-omap3/cpu.h b/arch/arm/include/asm/arch-omap3/cpu.h
index e944de7192..def013768c 100644
--- a/arch/arm/include/asm/arch-omap3/cpu.h
+++ b/arch/arm/include/asm/arch-omap3/cpu.h
@@ -454,9 +454,13 @@ struct prm {
#define RESETDONE (0x1 << 0)
-#define TCLR_ST (0x1 << 0)
-#define TCLR_AR (0x1 << 1)
+#define TCLR_GPO_CFG (0x1 << 14)
+#define TCLR_PT (0x1 << 12)
+#define TCLR_SCPWM (0x1 << 7)
+#define TCLR_CE (0x1 << 6)
#define TCLR_PRE (0x1 << 5)
+#define TCLR_AR (0x1 << 1)
+#define TCLR_ST (0x1 << 0)
/* SMX-APE */
#define PM_RT_APE_BASE_ADDR_ARM (SMX_APE_BASE + 0x10000)
diff --git a/arch/arm/include/asm/arch-omap3/dss.h b/arch/arm/include/asm/arch-omap3/dss.h
new file mode 100644
index 0000000000..4a3db1abb4
--- /dev/null
+++ b/arch/arm/include/asm/arch-omap3/dss.h
@@ -0,0 +1,213 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Syed Mohammed Khasim <khasim <at> ti.com>
+ *
+ * Referred to Linux Kernel DSS driver files for OMAP3 by
+ * Tomi Valkeinen from drivers/video/omap2/dss/
+ *
+ * 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's version 2 and any
+ * later version the License.
+ *
+ * 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 DSS_H
+#define DSS_H
+
+/*
+ * DSS Base Registers
+ */
+#define OMAP3_DSS_BASE 0x48050040
+#define OMAP3_DISPC_BASE 0x48050440
+#define OMAP3_VENC_BASE 0x48050C00
+
+/* DSS Registers */
+struct dss_regs {
+ u32 control; /* 0x40 */
+ u32 sdi_control; /* 0x44 */
+ u32 pll_control; /* 0x48 */
+};
+
+/* DISPC Registers */
+struct dispc_regs {
+ u32 control; /* 0x40 */
+ u32 config; /* 0x44 */
+ u32 reserve_2; /* 0x48 */
+ u32 default_color0; /* 0x4C */
+ u32 default_color1; /* 0x50 */
+ u32 trans_color0; /* 0x54 */
+ u32 trans_color1; /* 0x58 */
+ u32 line_status; /* 0x5C */
+ u32 line_number; /* 0x60 */
+ u32 timing_h; /* 0x64 */
+ u32 timing_v; /* 0x68 */
+ u32 pol_freq; /* 0x6C */
+ u32 divisor; /* 0x70 */
+ u32 global_alpha; /* 0x74 */
+ u32 size_dig; /* 0x78 */
+ u32 size_lcd; /* 0x7C */
+ u32 gfx_ba0; /* 0x80 */
+ u32 gfx_ba1; /* 0x84 */
+ u32 gfx_position; /* 0x88 */
+ u32 gfx_size; /* 0x8C */
+ u32 padding1; /* 0x90 */
+ u32 padding2; /* 0x94 */
+ u32 padding3; /* 0x98 */
+ u32 padding4; /* 0x9C */
+ u32 gfx_attributes; /* 0xA0 */
+ u32 gfx_fifo_threashold; /* 0xA4 */
+ u32 gfx_fifo_size_status; /* 0xA8 */
+ u32 gfx_row_inc; /* 0xAC */
+ u32 gfx_pixel_inc; /* 0xB0 */
+ u32 gfx_window_skip; /* 0xB4 */
+ u32 gfx_table_ba; /* 0xB8 */
+};
+
+/* VENC Registers */
+struct venc_regs {
+ u32 rev_id; /* 0x00 */
+ u32 status; /* 0x04 */
+ u32 f_control; /* 0x08 */
+ u32 reserve_1; /* 0x0C */
+ u32 vidout_ctrl; /* 0x10 */
+ u32 sync_ctrl; /* 0x14 */
+ u32 reserve_2; /* 0x18 */
+ u32 llen; /* 0x1C */
+ u32 flens; /* 0x20 */
+ u32 hfltr_ctrl; /* 0x24 */
+ u32 cc_carr_wss_carr; /* 0x28 */
+ u32 c_phase; /* 0x2C */
+ u32 gain_u; /* 0x30 */
+ u32 gain_v; /* 0x34 */
+ u32 gain_y; /* 0x38 */
+ u32 black_level; /* 0x3C */
+ u32 blank_level; /* 0x40 */
+ u32 x_color; /* 0x44 */
+ u32 m_control; /* 0x48 */
+ u32 bstamp_wss_data; /* 0x4C */
+ u32 s_carr; /* 0x50 */
+ u32 line21; /* 0x54 */
+ u32 ln_sel; /* 0x58 */
+ u32 l21__wc_ctl; /* 0x5C */
+ u32 htrigger_vtrigger; /* 0x60 */
+ u32 savid__eavid; /* 0x64 */
+ u32 flen__fal; /* 0x68 */
+ u32 lal__phase_reset; /* 0x6C */
+ u32 hs_int_start_stop_x; /* 0x70 */
+ u32 hs_ext_start_stop_x; /* 0x74 */
+ u32 vs_int_start_x; /* 0x78 */
+ u32 vs_int_stop_x__vs_int_start_y; /* 0x7C */
+ u32 vs_int_stop_y__vs_ext_start_x; /* 0x80 */
+ u32 vs_ext_stop_x__vs_ext_start_y; /* 0x84 */
+ u32 vs_ext_stop_y; /* 0x88 */
+ u32 reserve_3; /* 0x8C */
+ u32 avid_start_stop_x; /* 0x90 */
+ u32 avid_start_stop_y; /* 0x94 */
+ u32 reserve_4; /* 0x98 */
+ u32 reserve_5; /* 0x9C */
+ u32 fid_int_start_x__fid_int_start_y; /* 0xA0 */
+ u32 fid_int_offset_y__fid_ext_start_x; /* 0xA4 */
+ u32 fid_ext_start_y__fid_ext_offset_y; /* 0xA8 */
+ u32 reserve_6; /* 0xAC */
+ u32 tvdetgp_int_start_stop_x; /* 0xB0 */
+ u32 tvdetgp_int_start_stop_y; /* 0xB4 */
+ u32 gen_ctrl; /* 0xB8 */
+ u32 reserve_7; /* 0xBC */
+ u32 reserve_8; /* 0xC0 */
+ u32 output_control; /* 0xC4 */
+ u32 dac_b__dac_c; /* 0xC8 */
+ u32 height_width; /* 0xCC */
+};
+
+enum omap_panel_config {
+ OMAP_DSS_LCD_IVS = 1<<0,
+ OMAP_DSS_LCD_IHS = 1<<1,
+ OMAP_DSS_LCD_IPC = 1<<2,
+ OMAP_DSS_LCD_IEO = 1<<3,
+ OMAP_DSS_LCD_RF = 1<<4,
+ OMAP_DSS_LCD_ONOFF = 1<<5,
+
+ OMAP_DSS_LCD_TFT = 1<<20,
+};
+
+/* Few Register Offsets */
+#define FRAME_MODE_SHIFT 1
+#define TFTSTN_SHIFT 3
+#define DATALINES_SHIFT 8
+
+/* Enabling Display controller */
+#define LCD_ENABLE 1
+#define DIG_ENABLE (1 << 1)
+#define GO_LCD (1 << 5)
+#define GO_DIG (1 << 6)
+#define GP_OUT0 (1 << 15)
+#define GP_OUT1 (1 << 16)
+
+#define DISPC_ENABLE (LCD_ENABLE | \
+ DIG_ENABLE | \
+ GO_LCD | \
+ GO_DIG | \
+ GP_OUT0| \
+ GP_OUT1)
+
+/* Configure VENC DSS Params */
+#define VENC_CLK_ENABLE (1 << 3)
+#define DAC_DEMEN (1 << 4)
+#define DAC_POWERDN (1 << 5)
+#define VENC_OUT_SEL (1 << 6)
+#define DIG_LPP_SHIFT 16
+#define VENC_DSS_CONFIG (VENC_CLK_ENABLE | \
+ DAC_DEMEN | \
+ DAC_POWERDN | \
+ VENC_OUT_SEL)
+/*
+ * Panel Configuration
+ */
+struct panel_config {
+ u32 timing_h;
+ u32 timing_v;
+ u32 pol_freq;
+#if 1
+ u32 pixel_clock;
+#else
+ u32 divisor;
+#endif
+ u32 lcd_size;
+ u32 panel_type;
+ u32 data_lines;
+ u32 load_mode;
+ u32 panel_color;
+};
+
+/*
+ * Generic DSS Functions
+ */
+void omap3_dss_venc_config(const struct venc_regs *venc_cfg,
+ u32 height, u32 width);
+void omap3_dss_panel_config(const struct panel_config *panel_cfg);
+void omap3_dss_enable(void);
+
+#define CONFIG_DSS_DUMP
+#ifdef CONFIG_DSS_DUMP
+extern void omap3_dss_dump(void);
+#endif
+
+extern int omap3_dss_calc_divisor(int is_tft, unsigned int req_pck,
+ unsigned int *dispc_divisor,
+ unsigned int *result_fck_div);
+
+#endif /* DSS_H */
diff --git a/arch/arm/include/asm/arch-omap3/mmc_host_def.h b/arch/arm/include/asm/arch-omap3/mmc_host_def.h
index ba1c2ffc06..5f0342354c 100644
--- a/arch/arm/include/asm/arch-omap3/mmc_host_def.h
+++ b/arch/arm/include/asm/arch-omap3/mmc_host_def.h
@@ -188,6 +188,7 @@ typedef struct {
unsigned int mode;
unsigned int size;
unsigned int RCA;
+ unsigned int max_freq; /* max frequency of MMC device (if !0) */
} mmc_card_data;
#define RSP_TYPE_NONE (RSP_TYPE_NORSP | CCCE_NOCHECK | CICE_NOCHECK)
#define MMC_CMD0 (INDEX(0) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
diff --git a/arch/arm/include/asm/arch-omap3/omap3.h b/arch/arm/include/asm/arch-omap3/omap3.h
index cc2b5415c1..8c91b9aac9 100644
--- a/arch/arm/include/asm/arch-omap3/omap3.h
+++ b/arch/arm/include/asm/arch-omap3/omap3.h
@@ -69,6 +69,24 @@ struct control_prog_io {
#define OMAP34XX_UART2 (OMAP34XX_L4_IO_BASE + 0x6c000)
#define OMAP34XX_UART3 (OMAP34XX_L4_PER + 0x20000)
+/* OTG */
+#define OMAP34XX_OTG_BASE (OMAP34XX_L4_IO_BASE + 0xab000)
+#define OTG_SYSCONFIG (OMAP34XX_OTG_BASE + 0x404)
+#define OTG_SYSCONFIG_MIDLEMODE_SHIFT 12
+#define OTG_SYSCONFIG_MIDLEMODE_MASK (0x3 << OTG_SYSCONFIG_MIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_MIDLEMODE_FORCE_STDBY (0x0 << OTG_SYSCONFIG_MIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_MIDLEMODE_NO_STDBY (0x1 << OTG_SYSCONFIG_MIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_MIDLEMODE_SMART_STDBY (0x2 << OTG_SYSCONFIG_MIDLEMODE_SHIFT)
+
+#define OTG_SYSCONFIG_SIDLEMODE_SHIFT 3
+#define OTG_SYSCONFIG_SIDLEMODE_MASK (0x3 << OTG_SYSCONFIG_SIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_SIDLEMODE_FORCE_IDLE (0x0 << OTG_SYSCONFIG_SIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_SIDLEMODE_NO_IDLE (0x1 << OTG_SYSCONFIG_SIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_SIDLEMODE_SMART_IDLE (0x2 << OTG_SYSCONFIG_SIDLEMODE_SHIFT)
+#define OTG_SYSCONFIG_ENABLEWKUP (1 << 0x2)
+#define OTG_SYSCONFIG_SOFTRESET (1 << 0x1)
+#define OTG_SYSCONFIG_AUTOIDLE (1 << 0x0)
+
/* General Purpose Timers */
#define OMAP34XX_GPT1 0x48318000
#define OMAP34XX_GPT2 0x49032000
@@ -159,6 +177,8 @@ struct gpio {
#define SRAM_VECT_CODE (SRAM_OFFSET0 | SRAM_OFFSET1 | \
SRAM_OFFSET2)
+#define SRAM_BASE (SRAM_OFFSET0 | SRAM_OFFSET1)
+
#define LOW_LEVEL_SRAM_STACK 0x4020FFFC
#define DEBUG_LED1 149 /* gpio */
@@ -195,6 +215,8 @@ struct gpio {
#define CPU_3XX_ID_SHIFT 28
+#define TYPE_READTYPE 0x20000000 /* Readtype, 1 == sync in GPMC */
+
#define WIDTH_8BIT 0x0000
#define WIDTH_16BIT 0x1000 /* bit pos for 16 bit in gpmc */
diff --git a/arch/arm/include/asm/arch-omap3/omap_gpmc.h b/arch/arm/include/asm/arch-omap3/omap_gpmc.h
index bd22bce837..c86448baa8 100644
--- a/arch/arm/include/asm/arch-omap3/omap_gpmc.h
+++ b/arch/arm/include/asm/arch-omap3/omap_gpmc.h
@@ -58,6 +58,25 @@
}
#endif
+/* Micron MT29F4G16ABBDA internal-to-NAND ECC layout */
+#define GPMC_NAND_CHIP_ECC_LAYOUT {\
+ .eccbytes = 32,\
+ .eccpos = {8, 9, 10, 11, 12, 13, 14, 15, \
+ 24, 25, 26, 27, 28, 19, 30, 31, \
+ 40, 41, 42, 43, 44, 45, 46, 47, \
+ 56, 57, 58, 59, 60, 61, 62, 63}, \
+ .oobfree = {\
+ {.offset = 4,\
+ .length = 4 },\
+ {.offset = 20,\
+ .length = 4 },\
+ {.offset = 36,\
+ .length = 4 },\
+ {.offset = 52,\
+ .length = 4 },\
+ } \
+};
+
/* Small Page x8 NAND device Layout */
#ifdef GPMC_NAND_ECC_SP_x8_LAYOUT
#define GPMC_NAND_HW_ECC_LAYOUT {\
diff --git a/arch/arm/include/asm/arch-omap3/sys_proto.h b/arch/arm/include/asm/arch-omap3/sys_proto.h
index 4a28ba1c4a..cb45504c22 100644
--- a/arch/arm/include/asm/arch-omap3/sys_proto.h
+++ b/arch/arm/include/asm/arch-omap3/sys_proto.h
@@ -63,7 +63,16 @@ void sr32(void *, u32, u32, u32);
u32 wait_on_value(u32, u32, void *, u32);
void sdelay(unsigned long);
void make_cs1_contiguous(void);
-void omap_nand_switch_ecc(int);
+enum omap_nand_ecc_mode {
+ OMAP_ECC_SOFT = 1,
+ OMAP_ECC_HW,
+ OMAP_ECC_CHIP,
+ OMAP_ECC_SOFT_BCH,
+};
+extern void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode);
+extern enum omap_nand_ecc_mode omap_nand_current_ecc_method(void);
+int omap_nand_chip_has_ecc(void);
+
void power_init_r(void);
void dieid_num_r(void);
diff --git a/arch/arm/include/asm/arch-omap3/timer.h b/arch/arm/include/asm/arch-omap3/timer.h
new file mode 100644
index 0000000000..c3dd72ce08
--- /dev/null
+++ b/arch/arm/include/asm/arch-omap3/timer.h
@@ -0,0 +1,25 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development, Inc.
+ * Peter Barada <peter.barada@logicpd.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
+ */
+
+extern int init_gpt_timer(u32 timer, u32 value, u32 range);
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index ef9959e6ee..3fa72af0ff 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -64,6 +64,17 @@ typedef struct global_data {
#ifdef CONFIG_IXP425
unsigned long timestamp;
#endif
+#ifdef CONFIG_GDB_SECTION_STARTS
+ /* Section start information. Used with GDB command:
+ * add-symbol-file u-boot $relocaddr \
+ * -s .data $data_start \
+ * -s .bss $bss_start \
+ * -s .rodata $rodata_start
+ */
+ unsigned long bss_start;
+ unsigned long data_start;
+ unsigned long rodata_start;
+#endif
unsigned long relocaddr; /* Start address of U-Boot in RAM */
phys_size_t ram_size; /* RAM size */
unsigned long mon_len; /* monitor len */
diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index 3904027016..49a5aa50b4 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -33,6 +33,10 @@
extern ulong _bss_start_ofs; /* BSS start relative to _start */
extern ulong _bss_end_ofs; /* BSS end relative to _start */
extern ulong _end_ofs; /* end of image relative to _start */
+#ifdef CONFIG_GDB_SECTION_STARTS
+extern ulong _data_start_ofs; /* .data start relative to _start */
+extern ulong _rodata_start_ofs; /* .rodata start relative to _start */
+#endif
extern ulong IRQ_STACK_START; /* top of IRQ stack */
extern ulong FIQ_STACK_START; /* top of FIQ stack */
extern ulong _TEXT_BASE; /* code start */
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 169dfebcf1..2e22319947 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -47,6 +47,7 @@
#include <net.h>
#include <serial.h>
#include <nand.h>
+#include <asm/arch/sys_proto.h>
#include <onenand_uboot.h>
#include <mmc.h>
@@ -413,6 +414,11 @@ void board_init_f (ulong bootflag)
gd->relocaddr = addr;
gd->start_addr_sp = addr_sp;
gd->reloc_off = addr - _TEXT_BASE;
+#ifdef CONFIG_GDB_SECTION_STARTS
+ gd->bss_start = addr + _bss_start_ofs;
+ gd->data_start = addr + _data_start_ofs;
+ gd->rodata_start = addr + _rodata_start_ofs;
+#endif
debug ("relocation Offset is: %08lx\n", gd->reloc_off);
memcpy (id, (void *)gd, sizeof (gd_t));
@@ -471,6 +477,10 @@ void board_init_r (gd_t *id, ulong dest_addr)
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
#if !defined(CONFIG_SYS_NO_FLASH)
+#ifdef CONFIG_SYS_FLASH_PRESENCE
+ if (!CONFIG_SYS_FLASH_PRESENCE)
+ goto skip_flash;
+#endif
puts ("Flash: ");
if ((flash_size = flash_init ()) > 0) {
@@ -495,6 +505,10 @@ void board_init_r (gd_t *id, ulong dest_addr)
puts (failed);
hang ();
}
+#ifdef CONFIG_SYS_FLASH_PRESENCE
+skip_flash:
+ ;
+#endif
#endif
#if defined(CONFIG_CMD_NAND)
@@ -506,6 +520,10 @@ void board_init_r (gd_t *id, ulong dest_addr)
onenand_init();
#endif
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_setup_default_ecc_method(); /* Set the default ECC method */
+#endif
+
#ifdef CONFIG_GENERIC_MMC
puts("MMC: ");
mmc_initialize(bd);
diff --git a/board/ti/logic/Makefile b/board/ti/logic/Makefile
new file mode 100644
index 0000000000..67c7fd3f92
--- /dev/null
+++ b/board/ti/logic/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000, 2001, 2002
+# Wolfgang Denk, DENX Software Engineering, wd@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 $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(BOARD).o
+
+PROD_ID_OBJS := prod-id/query.o prod-id/startup.o prod-id/crc-15.o \
+ prod-id/extract.o prod-id/type.o prod-id/size.o
+
+COBJS := logic.o logic-data.o logic-at88.o logic-at24.o logic-i2c.o logic-gpio.o logic-display.o logic-product-id.o $(PROD_ID_OBJS)
+
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/board/ti/logic/config.mk b/board/ti/logic/config.mk
new file mode 100644
index 0000000000..897b252b07
--- /dev/null
+++ b/board/ti/logic/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2006 - 2008
+# Texas Instruments, <www.ti.com>
+#
+# EVM uses OMAP3 (ARM-CortexA8) cpu
+# see http://www.ti.com/ for more information on Texas Instruments
+#
+# 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
+#
+# Physical Address:
+# 8000'0000 (bank0)
+# A000/0000 (bank1)
+# Linux-Kernel is expected to be at 8000'8000, entry 8000'8000
+# (mem base + reserved)
+
+# For use with external or internal boots.
+CONFIG_SYS_TEXT_BASE = 0x80400000
diff --git a/board/ti/logic/logic-at24.c b/board/ti/logic/logic-at24.c
new file mode 100644
index 0000000000..e1f03db2ce
--- /dev/null
+++ b/board/ti/logic/logic-at24.c
@@ -0,0 +1,149 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 <command.h>
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clocks.h>
+#include <asm/arch/mem.h>
+#include <i2c.h>
+#include <asm/mach-types.h>
+#include "logic-i2c.h"
+
+#define AT24_CHIP_ID 0xA0
+#define AT24_ACCESS_WRITE 0
+#define AT24_ACCESS_READ 1
+
+#define AT24_DEVICE_ADDRESS(rw) (AT24_CHIP_ID | (rw & 1))
+#define AT24_SIZE_MASK 0x7FF /* 2048 byte AT24C16 */
+int at24_wakeup(void)
+{
+ int i;
+ gpio_i2c_init(100000);
+
+ /* Need 9 clocks to wake up AT24 chips */
+ gpio_i2c_config_pin(GPIO_I2C_SCLK, GPIO_I2C_OUTPUT);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ for (i=0; i<10; ++i) {
+ udelay(100);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ udelay(100);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ }
+
+ /* We can't identify AT24 chips... */
+
+ return 0;
+
+}
+
+int at24_shutdown(void)
+{
+ /* Restore GPIO_OE registers back to reset state (All input) */
+ gpio_i2c_config_pin(GPIO_I2C_SDATA, GPIO_I2C_INPUT);
+ gpio_i2c_config_pin(GPIO_I2C_SCLK, GPIO_I2C_INPUT);
+ /* Restore pins back to their intended use */
+ gpio_i2c_restore_pins();
+}
+
+/* Send the offset to the AT24 chip */
+static int at24_send_offset(u32 offset)
+{
+ int sleeps = 100;
+ int timeout = 1000;
+ int err, i;
+ u32 byteoffset, sizemask, sentoffset;
+
+ do {
+ while (gpio_i2c_busy() && timeout--)
+ udelay(100);
+ sleeps--;
+
+ gpio_i2c_tx_start();
+
+ err = gpio_i2c_tx_byte(AT24_DEVICE_ADDRESS(AT24_ACCESS_WRITE));
+
+ /* If the eeprom is busy, reset the bus an start over */
+ if (err)
+ gpio_i2c_tx_stop();
+
+ if (err && !sleeps) {
+ /* NACK, return error */
+ return err;
+ }
+ } while (err);
+
+ /* Write the destination offset to the AT24 */
+ sizemask = AT24_SIZE_MASK;
+ sentoffset = offset & sizemask;
+
+ for (i=0; i<4; ++i) {
+ byteoffset = (sentoffset & 0xFF000000) >> 24;
+ if (sizemask & 0xFF000000) {
+ err = gpio_i2c_tx_byte(byteoffset);
+ if (err)
+ return err;
+ }
+ sentoffset <<= 8;
+ sizemask <<= 8;
+ }
+ return 0;
+}
+
+/* Read 'size' bytes from the AT88 at offset 'offset'; return 0 if good */
+int at24_read(u32 offset, u8 *buf, u32 size)
+{
+ int rx_mode;
+ int err, idx;
+
+ err = at24_send_offset(offset);
+ if (err)
+ return err;
+ gpio_i2c_tx_stop();
+
+ gpio_i2c_tx_start();
+ err = gpio_i2c_tx_byte(AT24_DEVICE_ADDRESS(AT24_ACCESS_READ));
+ if (err)
+ return err;
+
+ for (idx = 0; idx < size; ++idx) {
+ if (size == 1)
+ rx_mode = RX_MODE_ONE_BYTE;
+ else if (idx == (size - 1))
+ rx_mode = RX_MODE_LAST_BYTE;
+ else if (idx == (size - 2))
+ rx_mode = RX_MODE_NEXT_TO_LAST_BYTE;
+ else if (idx == 0)
+ rx_mode = RX_MODE_FIRST_BYTE;
+ else
+ rx_mode = RX_MODE_MIDDLE_BYTE;
+
+ err = gpio_i2c_rx_byte(&buf[idx], rx_mode);
+ if (err)
+ printf("%s:%d err idx %d\n", __FUNCTION__, __LINE__, idx);
+ }
+
+ gpio_i2c_tx_stop();
+ return err;
+}
diff --git a/board/ti/logic/logic-at24.h b/board/ti/logic/logic-at24.h
new file mode 100644
index 0000000000..43c8b1bc97
--- /dev/null
+++ b/board/ti/logic/logic-at24.h
@@ -0,0 +1,24 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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
+ */
+
+extern int at24_read(u32 offset, u8 *buf, u32 size);
+extern int at24_wakeup(void);
+extern int at24_shutdown(void);
diff --git a/board/ti/logic/logic-at88.c b/board/ti/logic/logic-at88.c
new file mode 100644
index 0000000000..21299cadc8
--- /dev/null
+++ b/board/ti/logic/logic-at88.c
@@ -0,0 +1,117 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 <command.h>
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clocks.h>
+#include <asm/arch/mem.h>
+#include <i2c.h>
+#include <asm/mach-types.h>
+#include "product_id.h"
+#include "logic-gpio.h"
+#include "logic-i2c.h"
+#include "logic-at88.h"
+#include "logic-data.h"
+
+int at88_send_packet(uint8_t *data, int len, uint8_t *rxbuf, int rxlen)
+{
+ int timeout = 1000;
+ int retry;
+ int rx_mode;
+ int tick, err, idx;
+
+ if (DEBUG_PRODUCTION_DATA) {
+ char buf[3 * len + 2];
+ int i, offset;
+ for (offset = 0, i=0; i<len; ++i) {
+ if (!i)
+ offset = sprintf(buf, "%02x", data[i]);
+ else
+ offset += sprintf(&buf[offset], " %02x", data[i]);
+ }
+ printf("%s: %s\n", __FUNCTION__, buf);
+ }
+
+ /* Wait for bus */
+ while (gpio_i2c_busy() && timeout--)
+ udelay(100);
+
+ if (!timeout)
+ printf("%s:%d i2c_busy never return zero!\n", __FUNCTION__, __LINE__);
+
+ retry = 0;
+ do {
+ tick = 0;
+ do {
+ gpio_i2c_tx_stop();
+ gpio_i2c_tx_start();
+
+ /* send cmd */
+ err = gpio_i2c_tx_byte(data[0]);
+ tick++;
+ } while (err && tick < 100);
+
+ if (tick > 3)
+ printf("I2C ACK polling tick %d!\n", tick);
+
+ for (idx = 1; idx<len; ++idx) {
+ err = gpio_i2c_tx_byte(data[idx]);
+ if (err) {
+ printf("%s:%d NACK idx %d\n", __FUNCTION__, __LINE__, idx);
+ }
+ }
+ } while (err && (retry++ < 5));
+
+ if (err)
+ return err;
+
+ /* Are we expecting a response? */
+ if (rxbuf) {
+ for (idx = 0; idx < rxlen; ++idx) {
+ if (rxlen == 1)
+ rx_mode = RX_MODE_ONE_BYTE;
+ else if (idx == (rxlen - 1))
+ rx_mode = RX_MODE_LAST_BYTE;
+ else if (idx == (rxlen - 2))
+ rx_mode = RX_MODE_NEXT_TO_LAST_BYTE;
+ else if (idx == 0)
+ rx_mode = RX_MODE_FIRST_BYTE;
+ else
+ rx_mode = RX_MODE_MIDDLE_BYTE;
+
+ err = gpio_i2c_rx_byte(&rxbuf[idx], rx_mode);
+ if (DEBUG_PRODUCTION_DATA) {
+ if (err)
+ printf("%s:%d err idx %d\n", __FUNCTION__, __LINE__, idx);
+ }
+ }
+ }
+
+ gpio_i2c_tx_stop();
+ return err;
+}
+
+
+
diff --git a/board/ti/logic/logic-at88.h b/board/ti/logic/logic-at88.h
new file mode 100644
index 0000000000..6f66f8a0c8
--- /dev/null
+++ b/board/ti/logic/logic-at88.h
@@ -0,0 +1,23 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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
+ */
+
+
+extern int at88_send_packet(uint8_t *data, int len, uint8_t *rxbuf, int rxlen);
diff --git a/board/ti/logic/logic-data.c b/board/ti/logic/logic-data.c
new file mode 100644
index 0000000000..ba4633bf89
--- /dev/null
+++ b/board/ti/logic/logic-data.c
@@ -0,0 +1,643 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 <command.h>
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clocks.h>
+#include <asm/arch/mem.h>
+#include <i2c.h>
+#include <asm/mach-types.h>
+#include "product_id.h"
+#include "logic-gpio.h"
+#include "logic-i2c.h"
+#include "logic-at88.h"
+#include "logic-product-id.h"
+#include "logic-data.h"
+
+static int header_version = -1;
+
+
+/*
+ * Identify the device
+ */
+struct device_param {
+ char *name;
+ unsigned char reset[8]; /* ATR for part */
+ unsigned int zones; /* number of zones */
+ unsigned int zonesize; /* bytes per zone */
+};
+
+static const struct device_param answers[] = {
+ {
+ .name = "AT88SC0104C",
+ .reset = {0x3B, 0xB2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x01},
+ .zones = 4,
+ .zonesize = 32
+ },
+ {
+ .name = "AT88SC0204C",
+ .reset = {0x3B, 0xB2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x02},
+ .zones = 4,
+ .zonesize = 64
+ },
+ {
+ .name = "AT88SC0404C",
+ .reset = {0x3B, 0xB2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x04},
+ .zones = 4,
+ .zonesize = 128
+ },
+ {
+ .name = "AT88SC0808C",
+ .reset = {0x3B, 0xB2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x08},
+ .zones = 8,
+ .zonesize = 128
+ },
+ {
+ .name = "AT88SC1616C",
+ .reset = {0x3B, 0xB2, 0x11, 0x00, 0x10, 0x80, 0x00, 0x16},
+ .zones = 16,
+ .zonesize = 128
+ },
+ {
+ .name = "AT88SC3216C",
+ .reset = {0x3B, 0xB3, 0x11, 0x00, 0x00, 0x00, 0x00, 0x32},
+ .zones = 16,
+ .zonesize = 256
+ },
+ {
+ .name = "AT88SC6416C",
+ .reset = {0x3B, 0xB3, 0x11, 0x00, 0x00, 0x00, 0x00, 0x64},
+ .zones = 16,
+ .zonesize = 512
+ },
+ {
+ .name = "AT88SC12816C",
+ .reset = {0x3B, 0xB3, 0x11, 0x00, 0x00, 0x00, 0x01, 0x28},
+ .zones = 16,
+ .zonesize = 1024
+ },
+ {
+ .name = "AT88SC25616C",
+ .reset = {0x3B, 0xB3, 0x11, 0x00, 0x00, 0x00, 0x02, 0x56},
+ .zones = 16,
+ .zonesize = 2048
+ },
+};
+
+static const struct device_param *devptr; /* pointer to ID'd device */
+
+#define CMD_SYSTEM_READ 0xB6
+
+static int
+identify_device(void)
+{
+ const struct device_param *p;
+ unsigned char cmd[] = { CMD_SYSTEM_READ, 0x00, 0x00, 0x00 };
+ unsigned char buf[8];
+ int err;
+ int i,j;
+
+ err = at88_send_packet(cmd, sizeof(cmd), buf, sizeof(buf));
+ if (err)
+ return err;
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: ident %02x %02x %02x %02x %02x %02x %02x %02x\n", __FUNCTION__,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+ for (p=answers,i=0; i<sizeof(answers)/sizeof(answers[0]); ++i,++p) {
+ for (j=0; j<8 && (p->reset[j] == buf[j]); ++j)
+ ;
+ if (j==8) {
+ devptr = p;
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: device %s zones %u zonesize %u\n", __FUNCTION__,
+ devptr->name, devptr->zones, devptr->zonesize);
+
+ return 0;
+ }
+ }
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: Huh? couldn't ID productID device\n", __FUNCTION__);
+
+ return -1;
+}
+
+#define CMD_SYSTEM_WRITE 0xB4
+
+static int
+set_user_zone(int zone)
+{
+ unsigned char cmd[] = { CMD_SYSTEM_WRITE, 0x03, 0x00, 0x00 };
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: zone %d\n", __FUNCTION__, zone);
+ cmd[2] = zone;
+ return at88_send_packet(cmd, sizeof(cmd), NULL, 0);
+}
+
+#define CMD_READ_USER_ZONE 0xB2
+
+static int
+read_user_zone(unsigned int startzone, unsigned int offset,unsigned char *buf, int len)
+{
+ unsigned char cmd[] = { CMD_READ_USER_ZONE, 0x00, 0x00, 0x00 };
+ int ret;
+ unsigned int endzone;
+ unsigned int nbytes, zone_offset;
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: offset %u len %d\n", __FUNCTION__, offset, len);
+
+ /* If zone is non-zero, then we use zone/offset addressing, not
+ offset from start of chip */
+
+ /* abort if we'll go past the end of the device */
+ if (startzone) {
+ if (offset > devptr->zonesize) {
+ printf("%s: offset %u > zonesize %u\n", __FUNCTION__, offset, devptr->zonesize);
+ return -1;
+ }
+ if (startzone > devptr->zones) {
+ printf("%s: startzone %u > numzones %u\n", __FUNCTION__, startzone, devptr->zones);
+ return -1;
+ }
+ } else {
+ startzone = offset / devptr->zonesize;
+ }
+ endzone = (offset + (len - 1)) / devptr->zonesize;
+ if (endzone > devptr->zones) {
+ printf("%s: endzone %u > numzones %u\n", __FUNCTION__, endzone, devptr->zones);
+ return -1;
+ }
+
+ do {
+ /* Set the zone */
+ if (set_user_zone(startzone))
+ return -1;
+
+ zone_offset = offset % devptr->zonesize;
+ nbytes = devptr->zonesize - zone_offset;
+ if (nbytes > len)
+ nbytes = len;
+
+ cmd[2] = zone_offset;
+ cmd[3] = nbytes;
+ ret = at88_send_packet(cmd, sizeof(cmd), buf, nbytes);
+ if (DEBUG_PRODUCTION_DATA_BUF) {
+ char obuf[128];
+ int i,j,offset;
+ for (i = 0, offset=0; i<len; i+=16) {
+ for (j = 0; j<16 && i+j<len; ++j)
+ if (!j)
+ offset = sprintf(obuf, "%02x", buf[i+j]);
+ else
+ offset += sprintf(&obuf[offset], " %02x", buf[i+j]);
+ printf("%s\n", obuf);
+ }
+ }
+
+ buf += nbytes;
+ len -= nbytes;
+ offset += nbytes;
+ startzone++;
+ } while (len);
+ return ret;
+}
+
+#define XMK_STR(x) #x
+#define MK_STR(x) XMK_STR(x)
+int production_data_valid;
+
+static struct product_id_data product_id_data;
+
+static int valid_mac_address(unsigned char mac[3])
+{
+ if (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff)
+ return 0;
+ if (mac[0] == 0x00 && mac[1] == 0x00 && mac[2] == 0x00)
+ return 0;
+ return !0;
+}
+
+static int valid_full_mac_address(unsigned char mac[6])
+{
+ return (valid_mac_address(&mac[0]) && valid_mac_address(&mac[3]));
+}
+
+int extract_mac_address(struct product_id_data *p, int position, unsigned char mac[6])
+{
+ unsigned char *m = NULL;
+ if (!production_data_valid)
+ return -1;
+
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: position %d\n", __FUNCTION__, position);
+ switch(position) {
+ case 0:
+ if (header_version >= 2) {
+ if (valid_full_mac_address(p->d.u_zone0.pz_0r2.full_mac)) {
+ memcpy(mac, p->d.u_zone0.pz_0r2.full_mac, 6);
+ goto out;
+ }
+ }
+ m = p->d.zone2.pz_2r0.mac0;
+ break;
+ case 1:
+ m = p->d.zone2.pz_2r0.mac1;
+ break;
+ case 2:
+ m = p->d.zone2.pz_2r0.mac2;
+ break;
+ case 3:
+ m = p->d.zone2.pz_2r0.mac3;
+ break;
+ default:
+ return -1;
+ }
+ if (valid_mac_address(m)) {
+ mac[0] = 0x00;
+ mac[1] = 0x08;
+ mac[2] = 0xee;
+ mac[3] = m[0];
+ mac[4] = m[1];
+ mac[5] = m[2];
+ } else {
+ return -1;
+ }
+
+out:
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s:%d valid %d position %d %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, __LINE__,
+ production_data_valid, position,
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return 0;
+}
+
+/*
+ * Extract/set an ethernet address.
+ * Which is the address in the environment, position is which MAC address
+ * in the product ID data
+ */
+void board_get_nth_enetaddr (unsigned char *enetaddr, int which, int position)
+{
+ unsigned char mac[6];
+ char buf[32];
+ char *s = NULL, *e;
+ int i;
+ char ethbuf[18];
+ int ret;
+
+ /* We only handle the first two interfaces (LAN/WiFi)... */
+ if (which >= 2)
+ return;
+
+ memset(mac, 0, sizeof(mac));
+ ret = extract_mac_address(&product_id_data, position, mac);
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: ret %d valid %d which %d position %d %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
+ ret, production_data_valid, which, position,
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ memset(enetaddr, '\0', 6);
+ if (!production_data_valid ||
+ !valid_full_mac_address(mac)) {
+ if (DEBUG_PRODUCTION_DATA)
+ printf("%s: no valid address\n", __FUNCTION__);
+ s = getenv("ethaddr");
+
+#ifdef CONFIG_ETHADDR
+ if (!s)
+ s = MK_STR(CONFIG_ETHADDR);
+#endif
+
+ /* If no ethaddr found in productID or environment, then punt*/
+ if (!s)
+ return;
+
+ for (i = 0; i < 6; ++i) {
+ enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
+ if (s)
+ s = (*e) ? e + 1 : e;
+ }
+ goto set_it;
+ }
+
+ memcpy(enetaddr, mac, 6);
+
+set_it:
+ if (which == 0) {
+ sprintf(ethbuf, "%02x:%02x:%02x:%02x:%02x:%02x", enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3], enetaddr[4], enetaddr[5]);
+ sprintf(buf, "ethaddr");
+ } else {
+ sprintf(ethbuf, "%02x:%02x:%02x:%02x:%02x:%02x", enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3], enetaddr[4], enetaddr[5]);
+ sprintf(buf, "eth%daddr", which);
+ }
+ if (DEBUG_PRODUCTION_DATA)
+ printf("setenv '%s' '%s'\n", __FUNCTION__, ethbuf);
+
+ /* If already set, then don't change it */
+ s = getenv(buf);
+ if (s) {
+ if (strcmp(s, ethbuf) != 0)
+ printf("Overriding %s productID value %s with environment value\n", buf, ethbuf);
+ return;
+ }
+ setenv(buf, ethbuf);
+}
+
+static int extract_product_id_part_number(struct product_id_data *p, char *buf, int buflen)
+{
+ int size;
+
+ if (!production_data_valid)
+ return -1;
+
+ buf[0] = '\0';
+ if (header_version == LOGIC_HEADER_VERSION_0) {
+ size = sizeof(p->d.u_zone0.pz_0r0.part_number);
+ if (buflen < sizeof(p->d.u_zone0.pz_0r0.part_number))
+ size = buflen;
+ strncpy(buf, p->d.u_zone0.pz_0r0.part_number, sizeof(p->d.u_zone0.pz_0r0.part_number));
+ buf[sizeof(p->d.u_zone0.pz_0r0.part_number)] = '\0';
+ return 0;
+ }
+
+ if (header_version == LOGIC_HEADER_VERSION_1) {
+ size = sizeof(p->d.u_zone0.pz_0r1.part_number);
+ if (buflen < sizeof(p->d.u_zone0.pz_0r1.part_number))
+ size = buflen;
+ strncpy(buf, p->d.u_zone0.pz_0r1.part_number, sizeof(p->d.u_zone0.pz_0r1.part_number));
+ buf[sizeof(p->d.u_zone0.pz_0r1.part_number)] = '\0';
+ return 0;
+ }
+
+ if (p->d.u_zone0.pz_0r0.header_version == LOGIC_HEADER_VERSION_2
+ || p->d.u_zone0.pz_0r0.header_version == LOGIC_HEADER_VERSION_3) {
+ size = sizeof(p->d.u_zone0.pz_0r2.part_number);
+ if (buflen < sizeof(p->d.u_zone0.pz_0r2.part_number))
+ size = buflen;
+ strncpy(buf, p->d.u_zone0.pz_0r2.part_number, sizeof(p->d.u_zone0.pz_0r2.part_number));
+ buf[sizeof(p->d.u_zone0.pz_0r2.part_number)] = '\0';
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int extract_header_version(struct product_id_data *p, int *header_version)
+{
+ if (p->d.u_zone0.pz_0r0.header_version == LOGIC_HEADER_VERSION_0) {
+ *header_version = p->d.u_zone0.pz_0r0.header_version;
+ return 0;
+ }
+
+ if (p->d.u_zone0.pz_0r1.header_version == LOGIC_HEADER_VERSION_1) {
+ *header_version = p->d.u_zone0.pz_0r1.header_version;
+ return 0;
+ }
+
+ if (p->d.u_zone0.pz_0r2.header_version == LOGIC_HEADER_VERSION_2
+ || p->d.u_zone0.pz_0r2.header_version == LOGIC_HEADER_VERSION_3) {
+ *header_version = p->d.u_zone0.pz_0r2.header_version;
+ return 0;
+ }
+
+ *header_version = -1;
+ return -1;
+
+}
+
+static int extract_serial_number(struct product_id_data *p, char *buf, int buflen)
+{
+ buf[0] = '\0';
+
+ if (!production_data_valid)
+ return -1;
+
+ if (header_version == LOGIC_HEADER_VERSION_0) {
+ sprintf(buf, "%02d%02d%c%05d", p->d.u_zone0.pz_0r0.sn_week,
+ p->d.u_zone0.pz_0r0.sn_year, p->d.u_zone0.pz_0r0.sn_site,
+ p->d.u_zone0.pz_0r0.sn_cnt);
+ return 0;
+ }
+ if (header_version == LOGIC_HEADER_VERSION_1) {
+ sprintf(buf, "%02d%02d%c%05d", p->d.u_zone0.pz_0r1.sn_week,
+ p->d.u_zone0.pz_0r1.sn_year, p->d.u_zone0.pz_0r1.sn_site,
+ p->d.u_zone0.pz_0r1.sn_cnt);
+ return 0;
+ }
+ if (header_version == LOGIC_HEADER_VERSION_2
+ || header_version == LOGIC_HEADER_VERSION_3) {
+ sprintf(buf, "%02d%02d%c%05d", p->d.u_zone0.pz_0r2.sn_week,
+ p->d.u_zone0.pz_0r2.sn_year, p->d.u_zone0.pz_0r2.sn_site,
+ p->d.u_zone0.pz_0r2.sn_cnt);
+ return 0;
+ }
+ return -1;
+}
+
+static void extract_model_number_revision(struct product_id_data *p, char *buf, int buflen)
+{
+ int i;
+
+ strncpy(buf, product_id_data.d.zone1.model_number, buflen);
+ buf[buflen-1] = '\0';
+ if (header_version < LOGIC_HEADER_VERSION_2) {
+ i = strlen(buf);
+ if (i + 3 < buflen) {
+ buf[i] = '-';
+ buf[i+1] = product_id_data.d.zone1.model_revision;
+ buf[i+2] = '\0';
+ }
+ }
+}
+
+int _fetch_production_data(void)
+{
+ int err = 0;
+ int checksum;
+ int i;
+
+ production_data_valid = 0;
+
+ /* Make sure voltage is to productID chip! */
+ gpio_i2c_init(50000);
+
+ /* The productID chip wants at least 5 clocks to wake it up... */
+ gpio_i2c_config_pin(GPIO_I2C_SCLK, GPIO_I2C_OUTPUT);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ for (i=0; i<10; ++i) {
+ udelay(100);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ udelay(100);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ }
+
+ printf("Read production data: ");
+
+ if (identify_device()) {
+ printf("failed to identify device!\n");
+ err = -1;
+ goto out;
+ }
+
+ if (read_user_zone(0, 0, (unsigned char *)&product_id_data.d.u_zone0, sizeof(product_id_data.d.u_zone0))) {
+ printf("failed!\n");
+ err = -1;
+ goto out;
+ }
+
+ /* If the header doesn't match, we can't map any of the data */
+ if (extract_header_version(&product_id_data, &header_version)) {
+ printf("failed - invalid header version %d!\n", header_version);
+ err = -2;
+ goto out;
+ }
+
+ if (read_user_zone(0, 32, (unsigned char *)&product_id_data.d.zone1, sizeof(product_id_data.d.zone1))) {
+ printf("failed reading zone1 data!\n");
+ err = -3;
+ goto out;
+ }
+
+ if (read_user_zone(0, 64, (unsigned char *)&product_id_data.d.zone2, sizeof(product_id_data.d.zone2))) {
+ printf("failed reading zone2 data!\n");
+ err = -4;
+ goto out;
+ }
+
+ printf("done\n");
+
+ production_data_valid = 1;
+ /* Correct endianess issues */
+ product_id_data.d.zone2.pz_2r0.processor_type = le16_to_cpu(product_id_data.d.zone2.pz_2r0.processor_type);
+
+ if (header_version < 2)
+ product_id_data.d.zone2.pz_2r0.feature_bits = le32_to_cpu(product_id_data.d.zone2.pz_2r0.feature_bits);
+
+ product_id_data.d.zone2.pz_2r0.platform_bits = le32_to_cpu(product_id_data.d.zone2.pz_2r0.platform_bits);
+
+ /* WiFi config data starts at begining of zone 2. Don't bother
+ reading it if we know it can't fit in the productID chip */
+ if (2 + sizeof(product_id_data.d.wifi_config_data.data) / devptr->zonesize < devptr->zones) {
+ if (read_user_zone(2, 0, (unsigned char *)&product_id_data.d.wifi_config_data.data, sizeof(product_id_data.d.wifi_config_data.data))) {
+ printf("failed reading wifi_config data!\n");
+ } else
+ product_id_data.d.wifi_config_data.valid = 1;
+ }
+
+out:
+
+ /* Restore GPIO_OE registers back to reset state (All input) */
+ gpio_i2c_config_pin(GPIO_I2C_SDATA, GPIO_I2C_INPUT);
+ gpio_i2c_config_pin(GPIO_I2C_SCLK, GPIO_I2C_INPUT);
+
+ /* Restore pins back to their intended use */
+ gpio_i2c_restore_pins();
+
+ /* Calculate a checksum for the data and copy the
+ * production data to the start of SRAM */
+ checksum = calculate_checksum(&product_id_data.d,
+ sizeof(product_id_data.d));
+ product_id_data.checksum = checksum;
+
+ *(struct product_id_data *)(SRAM_BASE) = product_id_data;
+
+ return err;
+}
+
+void _dump_production_data(void)
+{
+ /* DECLARE_GLOBAL_DATA_PTR; */
+ char buf[36];
+ unsigned char mac[6];
+ int ret;
+ int i;
+
+ if (!production_data_valid)
+ return;
+
+ /* Print out the name, model number, and set MAC addresses */
+ extract_product_id_part_number(&product_id_data, buf, sizeof(buf));
+ printf("Part Number : %s\n", buf);
+
+ extract_model_number_revision(&product_id_data, buf, sizeof(buf));
+ if (strlen(buf))
+ printf("Model Name : %s\n", buf);
+
+ extract_serial_number(&product_id_data, buf, sizeof(buf));
+ printf("Serial Number: %s\n", buf);
+
+ ret = extract_mac_address(&product_id_data, 0, mac);
+ if (!ret) {
+ printf("LAN ethaddr : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ }
+
+ for (i=1; i<4; ++i) {
+ if (!extract_mac_address(&product_id_data, i, mac))
+ printf("LAN[%d] = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ }
+}
+
+#ifdef CONFIG_OMAP3_LOGIC_USE_NEW_PRODUCT_ID
+static int has_new_product_id_data;
+#endif
+
+/* Stub functions that call into current AT88 product ID code.
+ * Need to add tests for *new* product ID data before looking for older
+ * data device/format. */
+int fetch_production_data(void)
+{
+#ifdef CONFIG_OMAP3_LOGIC_USE_NEW_PRODUCT_ID
+
+ /* This makes first pass through the EEPROM so we have to initialize
+ * software i2c before reading and clean up after we are done */
+
+ if (logic_has_new_product_id()) {
+ has_new_product_id_data = 1;
+ return 0;
+ }
+#endif
+ return _fetch_production_data();
+}
+
+void dump_production_data(void)
+{
+#ifdef CONFIG_OMAP3_LOGIC_USE_NEW_PRODUCT_ID
+
+ if (has_new_product_id_data) {
+ logic_dump_serialization_info();
+ return;
+ }
+#endif
+ _dump_production_data();
+
+}
diff --git a/board/ti/logic/logic-data.h b/board/ti/logic/logic-data.h
new file mode 100644
index 0000000000..b296d2c4d0
--- /dev/null
+++ b/board/ti/logic/logic-data.h
@@ -0,0 +1,23 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 DEBUG_PRODUCTION_DATA 0
+#define DEBUG_PRODUCTION_DATA_BUF 0
diff --git a/board/ti/logic/logic-display.c b/board/ti/logic/logic-display.c
new file mode 100644
index 0000000000..3c0d17c188
--- /dev/null
+++ b/board/ti/logic/logic-display.c
@@ -0,0 +1,889 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/dss.h>
+#include <asm/arch/timer.h>
+#include <twl4030.h>
+#include <lcd.h>
+#include "splash-332x57.h"
+#include "logic-proto.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* LCD-required members */
+int lcd_line_length; /* initialized in lcd.c */
+int lcd_color_fg;
+int lcd_color_bg;
+void *lcd_base; /* initialized in lcd.c */
+void *lcd_console_address; /* where is this initialized? */
+short console_col = 0;
+short console_row = 0;
+
+vidinfo_t panel_info; /* Filled in by find_screen */
+
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+ /* Empty */
+}
+
+void lcd_initcolregs(void)
+{
+ /* Empty */
+}
+
+struct omap_video_timings {
+ /* Unit: pixels */
+ u16 x_res;
+ /* Unit: pixels */
+ u16 y_res;
+ /* Unit: KHz */
+ u32 pixel_clock;
+ /* Unit: pixel clocks */
+ u16 hsw; /* Horizontal synchronization pulse width */
+ /* Unit: pixel clocks */
+ u16 hfp; /* Horizontal front porch */
+ /* Unit: pixel clocks */
+ u16 hbp; /* Horizontal back porch */
+ /* Unit: line clocks */
+ u16 vsw; /* Vertical synchronization pulse width */
+ /* Unit: line clocks */
+ u16 vfp; /* Vertical front porch */
+ /* Unit: line clocks */
+ u16 vbp; /* Vertical back porch */
+};
+
+struct logic_panel {
+ char *name;
+ int config;
+ int acb;
+ char data_lines;
+ struct omap_video_timings timing;
+};
+
+
+static struct logic_panel default_panel;
+
+static struct omap_custom_lcd_fields {
+ char *field;
+ char *format;
+ void *ptr;
+ int len;
+} omap_custom_lcd_fields[] = {
+ { "xres", "%u", &default_panel.timing.x_res , 2},
+ { "yres", "%u", &default_panel.timing.y_res , 2},
+ { "left margin", "%u", &default_panel.timing.hbp, 2 },
+ { "right margin", "%u", &default_panel.timing.hfp, 2 },
+ { "top margin", "%u", &default_panel.timing.vbp, 2 },
+ { "bottom margin", "%u", &default_panel.timing.vfp, 2 },
+ { "hsync length", "%u", &default_panel.timing.hsw, 2 },
+ { "vsync length", "%u", &default_panel.timing.vsw, 2 },
+ { "pixclock", "%u", &default_panel.timing.pixel_clock, 4 },
+ { "config", "%u", &default_panel.config, 4 },
+ { "data_lines", "%u", &default_panel.data_lines, 1 },
+};
+
+ulong calc_fbsize(void) {
+ ulong size;
+ if (!default_panel.timing.x_res || !default_panel.timing.y_res)
+ return 0;
+
+ size = default_panel.timing.x_res * default_panel.timing.y_res;
+ size *= (default_panel.data_lines / 8);
+
+ return size;
+}
+
+
+struct logic_panel logic_panels[] = {
+ {
+ .name = "15",
+ .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS
+ | OMAP_DSS_LCD_ONOFF | OMAP_DSS_LCD_RF | OMAP_DSS_LCD_IEO
+ | OMAP_DSS_LCD_IHS,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 480 x 272, LQ043T1DG01 */
+ .x_res = 480,
+ .y_res = 272,
+ .pixel_clock = 9000,
+ .hfp = 3,
+ .hsw = 42,
+ .hbp = 2,
+ .vfp = 4,
+ .vsw = 11,
+ .vbp = 3,
+ },
+ },
+ {
+ .name = "3",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 320 x 240, LQ036Q1DA01 */
+ .x_res = 320,
+ .y_res = 240,
+ .pixel_clock = 24500,
+ .hfp = 20,
+ .hsw = 20,
+ .hbp = 20,
+ .vfp = 3,
+ .vsw = 3,
+ .vbp = 4,
+ },
+ },
+ {
+ .name = "7",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 640 x 480, LQ10D368 */
+ .x_res = 640,
+ .y_res = 480,
+ .pixel_clock = 27000,
+ .hfp = 24,
+ .hsw = 48,
+ .hbp = 135,
+ .vfp = 34,
+ .vsw = 1,
+ .vbp = 34,
+ },
+ },
+ {
+ .name = "5",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 640 x 240, LQ036Q1DA01 */
+ .x_res = 640,
+ .y_res = 480,
+ .pixel_clock = 27000,
+ .hfp = 24,
+ .hsw = 48,
+ .hbp = 135,
+ .vfp = 34,
+ .vsw = 1,
+ .vbp = 34,
+ },
+ },
+ {
+ .name = "2",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 800 x 600, LQ121S1DG31 */
+ .x_res = 800,
+ .y_res = 600,
+ .pixel_clock = 42000,
+ .hfp = 120,
+ .hsw = 5,
+ .hbp = 88-4-2,
+ .vfp = 100,
+ .vsw = 4,
+ .vbp = 21-1,
+ },
+ },
+ {
+ .name = "vga",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 640 x 480, VGA on DVI */
+ .x_res = 640,
+ .y_res = 480,
+ .pixel_clock = 24685,
+ .hfp = 16,
+ .hsw = 96,
+ .hbp = 48,
+ .vfp = 10,
+ .vsw = 2,
+ .vbp = 33,
+ },
+ },
+ {
+ .name = "svga",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 800 x 600, SVGA on DVI */
+ .x_res = 800,
+ .y_res = 600,
+ .pixel_clock = 42000,
+ .hfp = 120,
+ .hsw = 5,
+ .hbp = 88-4-2,
+ .vfp = 100,
+ .vsw = 4,
+ .vbp = 21-1,
+ },
+ },
+ {
+ .name = "xga",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 1024 x 769, XGA on DVI */
+ .x_res = 1024,
+ .y_res = 768,
+ .pixel_clock = 61714,
+ .hfp = 24,
+ .hsw = 41,
+ .hbp = 160,
+ .vfp = 3,
+ .vsw = 6,
+ .vbp = 29,
+ },
+ },
+ {
+ .name = "720p",
+ .config = OMAP_DSS_LCD_TFT,
+ .acb = 0x28,
+ .data_lines = 16,
+ .timing = {
+ /* 1280 x 720, 720P on DVI */
+ .x_res = 1280,
+ .y_res = 720,
+ .pixel_clock = 72000,
+ .hfp = 110,
+ .hsw = 40,
+ .hbp = 220,
+ .vfp = 5,
+ .vsw = 5,
+ .vbp = 20,
+ },
+ },
+};
+
+
+
+struct logic_panel *logic_find_panel(void)
+{
+ char *p, *q, *r;
+ struct omap_custom_lcd_fields *f;
+ char *panel;
+ char panel_name[128];
+ unsigned int val;
+ int err = 0, i;
+ int last, data_lines;
+ int found = 0;
+
+ panel = getenv("display");
+ if (!panel) {
+ printf("No 'display' variable found in environment; suppress splashimage\n");
+ return NULL;
+ }
+
+ if (strchr(panel, ':')) {
+ default_panel = logic_panels[0];
+ default_panel.name = "custom";
+ default_panel.data_lines = 16;
+ strcpy(panel_name, panel);
+ found = 1;
+ last = 0;
+ p = panel_name;
+ for (i=0, f=omap_custom_lcd_fields; !last && i<ARRAY_SIZE(omap_custom_lcd_fields); ++i, ++f) {
+ q = strchr(p, ':');
+ if (q)
+ *q = '\0';
+ else
+ last = 1;
+
+ val = simple_strtoul(p, &r, 0);
+
+ if (q && (r != q)) {
+ printf("Custom display field '%s' value of '%s' invalid\n", f->field, p);
+ err = 1;
+ break;
+ }
+ switch(f->len) {
+ case 1: {
+ u8 *ptr = f->ptr;
+ *ptr = val;
+ }
+ break;
+ case 2: {
+ u16 *ptr = f->ptr;
+ *ptr = val;
+ }
+ break;
+ default:
+ case 4: {
+ u32 *ptr = f->ptr;
+ *ptr = val;
+ }
+ break;
+ }
+ p = q+1;
+ }
+ strcpy(panel_name, default_panel.name);
+ if (calc_fbsize() > board_lcd_setmem(0)) {
+ printf("Custom screen definition too large!\n");
+ found = 0;
+ }
+ } else {
+ /* Copy panel name and null-terminate it */
+ strncpy(panel_name, panel, sizeof(panel_name));
+ panel_name[sizeof(panel_name)-1] = '\0';
+
+ /* Search for trailing "-dvi" or "-hdmi", if found
+ * set data_lines and strip off trailing specifier */
+ data_lines = 16;
+ if ((p = strrchr(panel_name, '-')) != NULL) {
+ if (!strcmp(p+1, "dvi")) {
+ data_lines = 16;
+ *p='\0';
+ } else if (!strcmp(p+1, "hdmi")) {
+ data_lines = 24;
+ *p='\0';
+ }
+ }
+
+ for (i=0; i<ARRAY_SIZE(logic_panels); ++i)
+ if (!strcmp(panel_name, logic_panels[i].name)) {
+ default_panel = logic_panels[i];
+ default_panel.data_lines = data_lines;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ printf("Found '%s' display panel\n", panel_name);
+ panel_info.vl_col = default_panel.timing.x_res;
+ panel_info.vl_row = default_panel.timing.y_res;
+ if (default_panel.data_lines == 16)
+ panel_info.vl_bpix = LCD_COLOR16;
+ else
+ panel_info.vl_bpix = LCD_COLOR24;
+ lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+ return &default_panel;
+ }
+ printf("display='%s' does not describe a valid screen!\n", panel);
+ return NULL;
+}
+
+/* Return size of largest framebuffer (so system can reserve memory on start) */
+ulong board_lcd_setmem(ulong addr)
+{
+ return 1600*1200*4; /* sxga at 24bpp(w 8bits of alpha) */
+}
+
+void touchup_display_env(void)
+{
+ // enable the splash screen
+ char splash_bmp_gz_str[12];
+
+ sprintf(splash_bmp_gz_str, "0x%08X", (unsigned int)splash_bmp_gz);
+ setenv("splashimage", splash_bmp_gz_str);
+ setenv("splashpos", "m,m");
+}
+
+void lcd_setup_pinmux(int data_lines)
+{
+ u32 arch_number;
+
+ arch_number = gd->bd->bi_arch_number;
+
+ /* Setup common pins */
+ MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | DIS | M0)); /*DSS_PCLK*/
+ MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | DIS | M0)); /*DSS_HSYNC*/
+ MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | DIS | M0)); /*DSS_VSYNC*/
+ MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | DIS | M0)); /*DSS_ACBIAS*/
+ MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | DIS | M0)); /*DSS_DATA6*/
+
+ /* omap35x use DSS_DATA0:15
+ * dm37x SOM uses DSS_DATA0:15
+ * dm37x Torpedo uses DSS_DATA18:23 as DSS_DATA0:5 */
+
+ if (arch_number == MACH_TYPE_DM3730_TORPEDO) {
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | DIS | M3)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | DIS | M3)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | DIS | M3)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | DIS | M3)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | DIS | M3)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | DIS | M3)); /*DSS_DATA5*/
+ } else {
+ MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | DIS | M0)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | DIS | M0)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | DIS | M0)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | DIS | M0)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | DIS | M0)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | DIS | M0)); /*DSS_DATA5*/
+ }
+
+ /* No need to mux the top 8 pins if not using them */
+ if (data_lines <= 16)
+ return;
+
+ MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | DIS | M0)); /*DSS_DATA16*/
+ MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | DIS | M0)); /*DSS_DATA17*/
+
+ if (arch_number == MACH_TYPE_DM3730_TORPEDO) {
+ MUX_VAL(CP(SYS_BOOT0), (IDIS | PTD | DIS | M3)); /*DSS_DATA18*/
+ MUX_VAL(CP(SYS_BOOT1), (IDIS | PTD | DIS | M3)); /*DSS_DATA19*/
+ MUX_VAL(CP(SYS_BOOT3), (IDIS | PTD | DIS | M3)); /*DSS_DATA20*/
+ MUX_VAL(CP(SYS_BOOT4), (IDIS | PTD | DIS | M3)); /*DSS_DATA21*/
+ MUX_VAL(CP(SYS_BOOT5), (IDIS | PTD | DIS | M3)); /*DSS_DATA22*/
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | DIS | M3)); /*DSS_DATA23*/
+ } else {
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | DIS | M0)); /*DSS_DATA18*/
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | DIS | M0)); /*DSS_DATA19*/
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | DIS | M0)); /*DSS_DATA20*/
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | DIS | M0)); /*DSS_DATA21*/
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | DIS | M0)); /*DSS_DATA22*/
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | DIS | M0)); /*DSS_DATA23*/
+ }
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+ struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
+ struct logic_panel *panel;
+ struct panel_config dss_panel;
+
+ memset(&panel_info, 0, sizeof(panel_info));
+ panel = logic_find_panel();
+ if (!panel)
+ return;
+
+ /* Convert from timings into panel_config structure */
+ dss_panel.panel_color = 0x0; /* black */
+ dss_panel.load_mode = 0x2; /* Frame Mode */
+ dss_panel.panel_type = 1; /* Active TFT */
+
+ dss_panel.timing_h = panel->timing.hsw - 1;
+ dss_panel.timing_h |= ((panel->timing.hfp - 1) << 8);
+ dss_panel.timing_h |= ((panel->timing.hbp - 1) << 20);
+ dss_panel.timing_v = panel->timing.vsw - 1;
+ dss_panel.timing_v |= ((panel->timing.vfp - 1) << 8);
+ dss_panel.timing_v |= ((panel->timing.vbp - 1) << 20);
+ dss_panel.pol_freq = panel->acb;
+ dss_panel.pol_freq |= ((panel->config & 0x3f) << 12);
+ dss_panel.lcd_size = panel->timing.x_res - 1;
+ dss_panel.lcd_size |= (panel->timing.y_res - 1) << 16;
+ if (panel->data_lines == 16)
+ dss_panel.data_lines = 1;
+ else if (panel->data_lines == 24)
+ dss_panel.data_lines = 3;
+ else {
+ printf("%s: Invalid data_lines!\n", __FUNCTION__);
+ memset(&panel_info, 0, sizeof(panel_info));
+ return;
+ }
+
+ dss_panel.pixel_clock = panel->timing.pixel_clock;
+
+ lcd_setup_pinmux(panel->data_lines);
+
+ /* configure DSS for single graphics layer */
+ omap3_dss_panel_config(&dss_panel);
+
+ writel((ulong)lcdbase, &dispc->gfx_ba0); /* frame buffer address */
+ writel((ulong)lcdbase, &dispc->gfx_ba1); /* frame buffer address */
+ writel(dss_panel.lcd_size, &dispc->gfx_size); /* size - same as LCD */
+ if (panel->data_lines == 16)
+ writel((1<<0)|(6<<1), &dispc->gfx_attributes); /* 6=RGB16,8=RGB24 */
+ else
+ writel(0x91, &dispc->gfx_attributes); /* 6=RGB16,8=RGB24 */
+
+
+ if (panel->data_lines == 16) {
+ lcd_color_fg = 0xffff;
+ lcd_color_bg = 0x0000;
+ } else {
+ lcd_color_fg = 0x00ffffff;
+ lcd_color_bg = 0x00000000;
+ }
+}
+
+void lcd_enable(void)
+{
+ int mSec;
+ u32 arch_number;
+ int gpio_backlight_pwr;
+ int gpio_panel_pwr;
+
+ arch_number = gd->bd->bi_arch_number;
+ if (arch_number == MACH_TYPE_DM3730_TORPEDO
+ || arch_number == MACH_TYPE_OMAP3_TORPEDO) {
+ gpio_backlight_pwr = 154;
+ gpio_panel_pwr = 155;
+ MUX_VAL(CP(MCBSP4_DX), (IDIS | PTD | EN | M4)); /*GPIO_154*/
+
+ } else {
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTU | DIS | M4)); /*GPIO_8 */
+ gpio_backlight_pwr = 8;
+ gpio_panel_pwr = 155;
+ }
+ MUX_VAL(CP(MCBSP4_FSX), (IDIS | PTD | EN | M4)); /*GPIO_155*/
+
+ /* Kill LCD_BACKLIGHT_PWR */
+ if (!omap_request_gpio(gpio_backlight_pwr)) {
+ omap_set_gpio_direction(gpio_backlight_pwr, 0);
+ omap_set_gpio_dataout(gpio_backlight_pwr, 0);
+ }
+
+ lcd_is_enabled = 0; /* keep console messages on the serial port */
+
+ /* Start clocks */
+ omap3_dss_enable();
+
+ /* Delay 300mS to allow 4.3" panel to initialize */
+ for (mSec=0; mSec<300; ++mSec)
+ udelay(1000);
+
+ /*
+ * panel_enable = 155
+ * backlight 154 (torpedo); 8 (som)
+ */
+
+ /* turn on LCD_PANEL_PWR */
+ if (!omap_request_gpio(gpio_panel_pwr)) {
+ omap_set_gpio_direction(gpio_panel_pwr, 0);
+ omap_set_gpio_dataout(gpio_panel_pwr, 1);
+ } else
+ printf("%s:%d fail!\n", __FUNCTION__, __LINE__);
+
+
+ /* Torpedo-20 boards uses GPIO_56 as their backlight SOM
+ * use GPIO.6 on TWL4030 */
+
+ if (arch_number == MACH_TYPE_DM3730_TORPEDO
+ || arch_number == MACH_TYPE_OMAP3_TORPEDO) {
+
+ MUX_VAL(CP(GPMC_NCS5), (IEN | PTD | EN | M3)); /*GPT10 backlight */
+ init_gpt_timer(10, 70, 100);
+ } else {
+ twl4030_set_pwm0(70, 100); /* 70% backlight brighntess */
+ }
+
+ /* Sleep 300mS to allow panel to stabilize */
+ for (mSec=0; mSec < 300; ++mSec)
+ udelay(1000);
+
+ /* turn on LCD_BACKLIGHT_PWR SOM LV */
+ if (!omap_request_gpio(gpio_backlight_pwr)) {
+ omap_set_gpio_direction(gpio_backlight_pwr, 0);
+ omap_set_gpio_dataout(gpio_backlight_pwr, 1);
+ } else
+ printf("%s:%d fail!\n", __FUNCTION__, __LINE__);
+
+}
+
+int do_backlight(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ u32 arch_number;
+ ulong level;
+
+ level = simple_strtoul(argv[1], NULL, 10);
+
+ arch_number = gd->bd->bi_arch_number;
+ if (arch_number == MACH_TYPE_DM3730_TORPEDO
+ || arch_number == MACH_TYPE_OMAP3_TORPEDO) {
+
+ /* Adjust Torpedo GPT10 timer (used for LCD_PWM0) */
+ init_gpt_timer(10, level, 100);
+ } else {
+ /* Adjust SOM LV TWL4030 PWM0 (used for LCD_PWM0) */
+ twl4030_set_pwm0(level, 100);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(backlight, 2, 1, do_backlight,
+ "backlight - change backlight level",
+ "<level>"
+);
+
+int do_dump_pwm0(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ twl4030_dump_pwm0();
+ return 0;
+}
+
+U_BOOT_CMD(dump_pwm0, 1, 1, do_dump_pwm0,
+ " - dump TWL PWM registers",
+ ""
+);
+
+struct fb_bitfield {
+ u8 length;
+ u8 offset;
+};
+static struct fb_var_screeninfo {
+ int bits_per_pixel;
+ u32 xres, yres;
+ struct fb_bitfield red, green, blue;
+ u32 line_length; /* bytes/line */
+} fb_var;
+
+void *fb_ptr;
+unsigned int fb_stride;
+unsigned int fb_size;
+int fb_max_x, fb_max_y;
+
+typedef struct {
+ unsigned int x,y;
+} point_t;
+
+typedef unsigned int color_t;
+
+void
+draw_pixel_32(point_t *p, color_t c)
+{
+ unsigned int offset;
+
+ if (p->x >= fb_max_x || p->y >= fb_max_y)
+ printf("%s: point [%u:%u] out of range\n", __FUNCTION__, p->x, p->y);
+
+ offset = p->y * fb_stride + p->x*sizeof(int);
+ *((unsigned int *)((unsigned char *)fb_ptr + offset)) = c;
+}
+
+void
+draw_pixel_16(point_t *p, color_t c)
+{
+ unsigned int offset;
+
+ if (p->x >= fb_max_x || p->y >= fb_max_y)
+ printf("%s: point [%u:%u] out of range\n", __FUNCTION__, p->x, p->y);
+
+ offset = p->y * fb_stride + p->x*sizeof(short);
+ *((unsigned short *)((unsigned char *)fb_ptr + offset)) = c;
+}
+
+void
+draw_pixel_8(point_t *p, color_t c)
+{
+ unsigned int offset;
+
+ if (p->x >= fb_max_x || p->y >= fb_max_y)
+ printf("%s: point [%u:%u] out of range\n", __FUNCTION__, p->x, p->y);
+
+ offset = p->y * fb_stride + p->x*sizeof(char);
+ *((unsigned char *)((unsigned char *)fb_ptr + offset)) = c;
+}
+
+void (*draw_pixel)(point_t *p, color_t c);
+
+void draw_rect(point_t *p1, point_t *p2, color_t c, int fill)
+{
+ point_t p;
+
+ if (fill) {
+ for (p.y = p1->y; p.y <= p2->y; ++p.y)
+ for (p.x = p1->x; p.x <= p2->x; ++p.x)
+ (*draw_pixel)(&p, c);
+ } else {
+ for (p.x = p1->x; p.x <= p2->x; ++p.x) {
+ p.y = p1->y;
+ (*draw_pixel)(&p, c);
+ p.y = p2->y;
+ (*draw_pixel)(&p, c);
+ }
+ for (p.y = p1->y; p.y <= p2->y; ++p.y) {
+ p.x = p1->x;
+ (*draw_pixel)(&p, c);
+ p.x = p2->x;
+ (*draw_pixel)(&p, c);
+ }
+ }
+}
+
+void draw_test_frame(int x, int y, int margin, color_t c)
+{
+ point_t start, end;
+
+ start.x = margin;
+ end.x = x - margin - 1;
+ start.y = margin;
+ end.y = y - margin - 1;
+
+ draw_rect(&start, &end, c, 0);
+}
+
+void
+clear_video_frame(void)
+{
+ memset(fb_ptr, 0, fb_size);
+}
+
+/* Draw a ramp, [l,r] to [l+w,r+h], in color *color */
+void draw_ramp (point_t *start, point_t *end, struct fb_bitfield *fb_bits, struct fb_var_screeninfo *fb_var)
+{
+ point_t ul, br;
+ int i, width_round_up;
+ int colors;
+
+ ul = *start;
+ br = *end;
+
+ colors = 1<<fb_bits->length;
+ width_round_up = (end->x % colors) ? 1 : 0;
+
+ for (i=0; i<colors; ++i) {
+ draw_rect(&ul, &br, i<<fb_bits->offset, 1);
+ ul.x = br.x;
+ br.x += fb_var->xres / colors + ((i % 2) * width_round_up);
+ if (br.x >= fb_var->xres)
+ br.x = fb_var->xres-1;
+ }
+}
+
+void scribble_frame_buffer(void)
+{
+ unsigned int x,y;
+ color_t color_white, color_black, color_blue, color_red;
+ unsigned int colorbitwidth, width_round_up;
+ point_t start, end;
+
+ if (fb_var.bits_per_pixel == 8)
+ draw_pixel = draw_pixel_8;
+ else if (fb_var.bits_per_pixel == 16)
+ draw_pixel = draw_pixel_16;
+ else
+ draw_pixel = draw_pixel_32;
+
+ printf("%s:%d draw_pixel %p\n", __FUNCTION__, __LINE__, draw_pixel);
+
+ // white is all bits on
+ color_white = (((1<<fb_var.red.length)-1) << fb_var.red.offset)
+ | (((1<<fb_var.green.length)-1) << fb_var.green.offset)
+ | (((1<<fb_var.blue.length)-1) << fb_var.blue.offset);
+
+ // black is all bits off
+ color_black = 0;
+
+ color_blue = (((1 << fb_var.blue.length) - 1) << fb_var.blue.offset);
+
+ color_red = (((1 << fb_var.red.length) - 1) << fb_var.red.offset);
+
+
+
+ x = fb_var.xres;
+ y = fb_var.yres;
+ colorbitwidth = 32;
+
+ start.x = 0;
+ width_round_up = (x % colorbitwidth) ? 1 : 0;
+ end.x = x / colorbitwidth + width_round_up;
+
+ end.y = y/4;
+ start.y = 0;
+ draw_ramp(&start, &end, &fb_var.red, &fb_var);
+ start.y = end.y;
+ end.y += y/4;
+ draw_ramp(&start, &end, &fb_var.green, &fb_var);
+ start.y = end.y;
+ end.y += y/4;
+ draw_ramp(&start, &end, &fb_var.blue, &fb_var);
+ /* draw stipple, stop test when error is encountered */
+ for (start.y = 3 * (y / 4); start.y < y; start.y++) {
+ for (start.x = 0; start.x < (x / 3); start.x++) {
+ draw_rect(&start, &start,
+ (start.x ^ start.y) & 1 ? color_white : color_black,
+ 0);
+ }
+ }
+
+ /* draw vert-lines, stop test when error is encountered */
+ start.y = 3 * (y / 4);
+ end.y = y-1;
+ for (start.x = x / 3; start.x < 2 * (x / 3); start.x++) {
+ end.x = start.x;
+ draw_rect(&start, &end,
+ start.x & 1 ? color_white : color_black, 0);
+ }
+
+ /* draw horiz-lines, stop test when error is encountered */
+ start.x = 2 * (x / 3);
+ end.x = x-1;
+ for (start.y = 3 * (y / 4); start.y < y; start.y++) {
+ end.y = start.y;
+ draw_rect(&start, &end,
+ start.y & 1 ? color_white : color_black, 0);
+ }
+
+
+ // Draw some frames
+ draw_test_frame(x, y, 0, color_white);
+ draw_test_frame(x, y, 1, color_red);
+ draw_test_frame(x, y, 2, color_blue);
+}
+
+int do_draw_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ if (panel_info.vl_col && panel_info.vl_row) {
+ fb_var.xres = panel_info.vl_col;
+ fb_var.yres = panel_info.vl_row;
+ if (panel_info.vl_bpix == LCD_COLOR16) {
+ fb_var.bits_per_pixel = 16;
+ fb_var.red.offset = 11;
+ fb_var.red.length = 5;
+ fb_var.blue.offset = 5;
+ fb_var.blue.length = 6;
+ fb_var.green.offset = 0;
+ fb_var.green.length = 5;
+ } else if (panel_info.vl_bpix == LCD_COLOR24) {
+ fb_var.bits_per_pixel = 32;
+ fb_var.red.offset = 16;
+ fb_var.red.length = 8;
+ fb_var.blue.offset = 8;
+ fb_var.blue.length = 8;
+ fb_var.green.offset = 0;
+ fb_var.green.length = 8;
+ }
+ fb_var.line_length = fb_var.xres * (fb_var.bits_per_pixel / 8);
+ fb_ptr = (void *)gd->fb_base;
+ fb_stride = fb_var.line_length;
+ fb_size = fb_stride * fb_var.yres;
+ fb_max_x = fb_var.xres;
+ fb_max_y = fb_var.yres;
+ scribble_frame_buffer();
+ }
+ return 0;
+}
+
+U_BOOT_CMD(draw_test, 1, 1, do_draw_test,
+ " - Draw ramps/stipples/boarders on LCD",
+ ""
+);
diff --git a/board/ti/logic/logic-gpio.c b/board/ti/logic/logic-gpio.c
new file mode 100644
index 0000000000..1b63183978
--- /dev/null
+++ b/board/ti/logic/logic-gpio.c
@@ -0,0 +1,161 @@
+/*
+ * (C) Copyright 2008
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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/cpu.h>
+#include <asm/io.h>
+// #include <asm/arch/bits.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+// #include <asm/arch/sys_info.h>
+#include <asm/arch/clocks.h>
+#include <asm/arch/mem.h>
+#include <i2c.h>
+#include <asm/mach-types.h>
+#include "logic-gpio.h"
+
+#define NUM_OF_BITS_IN_REG 32
+#define MAX_GPIO_PINS 192
+#define GPIO_PIN 1
+#define GPIO_MAX_MODULES 6
+
+/* GPIO base address */
+#define GPIO1_MODULE_BA 0x48310000
+#define GPIO2_MODULE_BA 0x49050000
+#define GPIO3_MODULE_BA 0x49052000
+#define GPIO4_MODULE_BA 0x49054000
+#define GPIO5_MODULE_BA 0x49056000
+#define GPIO6_MODULE_BA 0x49058000
+
+#define GPIO_DATAIN ((uint32_t)0x038)
+#define GPIO_DATAOUT ((uint32_t)0x03C)
+#define GPIO_OE ((uint32_t)0x034)
+
+/* int and long both fit to 32 bits */
+typedef volatile uint32_t* PREG_U32;
+typedef volatile int32_t* PREG_S32;
+
+#define in_regl(offSet) (*(PREG_U32)(offSet))
+#define out_regl(offSet, value) (*(PREG_U32)(offSet) = (uint32_t)(value))
+
+static uint32_t g_gpio_module_base_address[GPIO_MAX_MODULES]
+ = {GPIO1_MODULE_BA, GPIO2_MODULE_BA, GPIO3_MODULE_BA,
+ GPIO4_MODULE_BA, GPIO5_MODULE_BA, GPIO6_MODULE_BA};
+
+uint32_t check_gpio_pin_num(uint32_t pin_num)
+{
+ return (pin_num > MAX_GPIO_PINS);
+}
+
+uint32_t get_module_pin_mask(uint32_t pin_num, uint32_t *module_num, uint32_t *offset, uint32_t *pinmask)
+{
+ uint32_t snum, ret_val;
+
+ *module_num = pin_num / NUM_OF_BITS_IN_REG + 1;
+ snum = (*module_num-1)*NUM_OF_BITS_IN_REG;
+ *offset = pin_num - snum;
+ ret_val = check_gpio_pin_num(pin_num);
+ if (ret_val)
+ return ret_val;
+
+ *pinmask = GPIO_PIN<<*offset;
+ return 0;
+}
+
+
+void gpio_write_output_pin(int module_num, uint32_t pin_mask, uint32_t data)
+{
+ uint32_t temp, gpio_data_out_reg;
+
+ gpio_data_out_reg = (g_gpio_module_base_address[module_num-1]+GPIO_DATAOUT);
+
+ temp = in_regl(gpio_data_out_reg);
+ temp = temp & ~pin_mask;
+
+ out_regl(gpio_data_out_reg, (temp | (data & pin_mask)));
+}
+
+void gpio_read_input_pin(uint32_t module_num, uint32_t pin_mask, uint32_t *data)
+{
+ uint32_t gpio_data_in_reg, temp;
+
+ gpio_data_in_reg = (g_gpio_module_base_address[module_num-1]+GPIO_DATAIN);
+
+ temp = in_regl(gpio_data_in_reg);
+ *data = temp & pin_mask;
+}
+
+uint32_t pin_get_gpio_input(uint32_t pin_num)
+{
+ uint32_t module_num, pinmask, offset, data;
+
+ get_module_pin_mask(pin_num, &module_num, &offset, &pinmask);
+
+ gpio_read_input_pin(module_num, (1<<offset), &data);
+ data >>= offset;
+
+ // printf("%s:%d pin %d data %d\n", __FUNCTION__, __LINE__, pin_num, data);
+
+ return data;
+}
+
+
+uint32_t pin_set_gpio_dataout(uint32_t pin_num, uint32_t set)
+{
+ uint32_t module_num, pinmask, offset, ret_val;
+
+ // printf("%s:%d pin %d set %d\n", __FUNCTION__, __LINE__, pin_num, set);
+
+ ret_val = get_module_pin_mask(pin_num, &module_num, &offset, &pinmask);
+
+ if (set)
+ gpio_write_output_pin(module_num, (1<<offset), (1<<offset));
+ else
+ gpio_write_output_pin(module_num, (1<<offset), (0<<offset));
+
+ return ret_val;
+}
+
+uint32_t set_gpio_in_out(uint32_t module_num, uint32_t pin_mask, uint32_t io_mask)
+{
+ uint32_t temp_oe, gpio_pin_output_en_reg;
+
+ gpio_pin_output_en_reg = (g_gpio_module_base_address[module_num-1]+GPIO_OE);
+
+ temp_oe = in_regl(gpio_pin_output_en_reg);
+ temp_oe &= ~pin_mask;
+ temp_oe |= io_mask;
+
+ out_regl(gpio_pin_output_en_reg, temp_oe);
+
+ return 0;
+}
+
+uint32_t pin_init_gpio(uint32_t pin_num, uint32_t in_out)
+{
+ uint32_t module_num, pinmask, offset, ret_val;
+
+ ret_val = get_module_pin_mask(pin_num, &module_num, &offset, &pinmask);
+
+ set_gpio_in_out(module_num, pinmask, in_out<<offset);
+
+ return ret_val;
+}
diff --git a/board/ti/logic/logic-gpio.h b/board/ti/logic/logic-gpio.h
new file mode 100644
index 0000000000..fca023f93f
--- /dev/null
+++ b/board/ti/logic/logic-gpio.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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
+ */
+
+// GPIO
+extern unsigned int pin_get_gpio_input(unsigned int pin);
+extern unsigned int pin_set_gpio_dataout(unsigned int pin, unsigned int set);
+extern unsigned int pin_init_gpio(unsigned int pin_num, unsigned int in_out);
+
+// Turn on VAUX1 voltage for Product ID
+extern void init_vaux1_voltage(void);
diff --git a/board/ti/logic/logic-i2c.c b/board/ti/logic/logic-i2c.c
new file mode 100644
index 0000000000..0ff463afcf
--- /dev/null
+++ b/board/ti/logic/logic-i2c.c
@@ -0,0 +1,242 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 <command.h>
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clocks.h>
+#include <asm/arch/mem.h>
+#include <i2c.h>
+#include <asm/mach-types.h>
+#include "logic-i2c.h"
+#include "product_id.h"
+#include "logic-gpio.h"
+#include "logic-data.h"
+
+static enum {
+ GPIO_I2C_UNINIT,
+ GPIO_I2C_STOPPED,
+ GPIO_I2C_STARTED,
+} gpio_i2c_bus_state;
+
+static int gpio_i2c_clock_high_width, gpio_i2c_clock_low_width;
+static int gpio_i2c_coarse_delay;
+
+/*
+ * IEN - Input Enable
+ * IDIS - Input Disable
+ * PTD - Pull type Down
+ * PTU - Pull type Up
+ * DIS - Pull type selection is inactive
+ * EN - Pull type selection is active
+ * M0 - Mode 0
+ * The commented string gives the final mux configuration for that pin
+ */
+
+/* Put SCLK/SDA pins connected to the product ID into GPIO mode */
+static void gpio_i2c_config_pins(void)
+{
+ MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M4)); /*I2C3_SCL*/
+ MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M4)); /*I2C3_SDA*/
+}
+
+/* Restore SCLK/SDA pins connected to the product ID back to I2C mode */
+
+void gpio_i2c_restore_pins(void)
+{
+ MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M0)); /*I2C3_SCL*/
+ MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M0)); /*I2C3_SDA*/
+}
+
+#define GPIO_I2C_GPIO_SCLK 184
+#define GPIO_I2C_GPIO_SDATA 185
+
+void gpio_i2c_config_pin(GPIO_I2C_PIN pin, GPIO_I2C_DIRECTION dir)
+{
+ if (dir == GPIO_I2C_INPUT) {
+ if (pin == GPIO_I2C_SCLK)
+ pin_init_gpio(GPIO_I2C_GPIO_SCLK, 1);
+ else
+ pin_init_gpio(GPIO_I2C_GPIO_SDATA, 1);
+ } else if (dir == GPIO_I2C_OUTPUT) {
+ if (pin == GPIO_I2C_SCLK)
+ pin_init_gpio(GPIO_I2C_GPIO_SCLK, 0);
+ else
+ pin_init_gpio(GPIO_I2C_GPIO_SDATA, 0);
+ }
+}
+
+static int gpio_i2c_read_pin(GPIO_I2C_PIN pin)
+{
+ if (pin == GPIO_I2C_SCLK)
+ return pin_get_gpio_input(GPIO_I2C_GPIO_SCLK);
+ else
+ return pin_get_gpio_input(GPIO_I2C_GPIO_SDATA);
+ return 0;
+}
+
+void gpio_i2c_set_pin_level(GPIO_I2C_PIN pin, int level)
+{
+ uint8_t pin_level;
+
+ if (pin == GPIO_I2C_SCLK) {
+ pin_level = pin_get_gpio_input(GPIO_I2C_GPIO_SCLK);
+ if (((level == 1) && (pin_level == 0)) ||
+ ((level == 0) && (pin_level == 1)))
+ pin_set_gpio_dataout(GPIO_I2C_GPIO_SCLK, level);
+ } else if (pin == GPIO_I2C_SDATA) {
+ if (level == 0) {
+ gpio_i2c_config_pin(pin, GPIO_I2C_OUTPUT);
+ pin_set_gpio_dataout(GPIO_I2C_GPIO_SDATA, 0);
+ } else {
+ gpio_i2c_config_pin(pin, GPIO_I2C_INPUT);
+ }
+ }
+}
+
+
+void gpio_i2c_init(int bps)
+{
+ gpio_i2c_bus_state = GPIO_I2C_UNINIT;
+
+ /* Config SCLK, SDATA pins */
+ gpio_i2c_config_pin(GPIO_I2C_SCLK, GPIO_I2C_OUTPUT);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+
+ gpio_i2c_config_pin(GPIO_I2C_SDATA, GPIO_I2C_INPUT);
+
+ gpio_i2c_config_pins();
+
+ /* Assume 1:1 clock duty cycle */
+ gpio_i2c_clock_high_width = gpio_i2c_clock_low_width
+ = 1000000 / bps / 2;
+
+ gpio_i2c_coarse_delay = gpio_i2c_clock_high_width;
+}
+
+int gpio_i2c_busy(void)
+{
+ return (gpio_i2c_bus_state == GPIO_I2C_STARTED);
+}
+
+void gpio_i2c_tx_stop(void)
+{
+ if (gpio_i2c_bus_state == GPIO_I2C_STARTED) {
+ udelay(gpio_i2c_coarse_delay);
+
+ /* Pull SDATA low */
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 0);
+ udelay(gpio_i2c_coarse_delay);
+
+ /* Push SCLK high */
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_coarse_delay);
+
+ /* Now drive SDATA high - thats a STOP. */
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 1);
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_bus_state = GPIO_I2C_STOPPED;
+ }
+}
+
+void gpio_i2c_tx_start(void)
+{
+ if (gpio_i2c_bus_state == GPIO_I2C_UNINIT
+ || gpio_i2c_bus_state == GPIO_I2C_STOPPED) {
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 1);
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 0);
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ udelay(gpio_i2c_coarse_delay);
+ gpio_i2c_bus_state = GPIO_I2C_STARTED;
+ }
+}
+
+/* Return !0 if NACK */
+int gpio_i2c_tx_byte(uint8_t data)
+{
+ uint8_t clock, tx_bit_mask=0x80, nack;
+
+ if (gpio_i2c_bus_state != GPIO_I2C_STARTED)
+ printf("%s: Unexpected I2C bus state!\n", __FUNCTION__);
+
+ udelay(gpio_i2c_coarse_delay);
+
+ for (clock=0; clock <= 7; ++clock) {
+ if (data & tx_bit_mask)
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 1);
+ else
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 0);
+ udelay(gpio_i2c_clock_low_width);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_clock_high_width);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ tx_bit_mask >>= 1;
+ }
+ gpio_i2c_config_pin(GPIO_I2C_SDATA, GPIO_I2C_INPUT);
+ udelay(gpio_i2c_clock_low_width);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_clock_high_width);
+ nack = gpio_i2c_read_pin(GPIO_I2C_SDATA);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ return (nack != 0);
+}
+
+int gpio_i2c_rx_byte(uint8_t *data, int rx_mode)
+{
+ uint8_t clock, data_bit;
+
+ *data = 0;
+
+ gpio_i2c_config_pin(GPIO_I2C_SDATA, GPIO_I2C_INPUT);
+
+ udelay(gpio_i2c_coarse_delay);
+
+ for (clock=0; clock<=8; ++clock) {
+ if (clock < 8) {
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_clock_high_width);
+ data_bit = gpio_i2c_read_pin(GPIO_I2C_SDATA);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ *data = (*data << 1) | data_bit;
+ } else {
+ if ((rx_mode == RX_MODE_LAST_BYTE) || (rx_mode == RX_MODE_ONE_BYTE))
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 1);
+ else
+ gpio_i2c_set_pin_level(GPIO_I2C_SDATA, 0);
+
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 1);
+ udelay(gpio_i2c_clock_high_width);
+ gpio_i2c_set_pin_level(GPIO_I2C_SCLK, 0);
+ }
+ udelay(gpio_i2c_clock_low_width);
+ }
+
+ return 0;
+}
+
diff --git a/board/ti/logic/logic-i2c.h b/board/ti/logic/logic-i2c.h
new file mode 100644
index 0000000000..bd1f01aea0
--- /dev/null
+++ b/board/ti/logic/logic-i2c.h
@@ -0,0 +1,48 @@
+/*
+ * (C) Copyright 2008-2011
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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
+ */
+
+typedef enum {
+ GPIO_I2C_INPUT,
+ GPIO_I2C_OUTPUT,
+} GPIO_I2C_DIRECTION;
+
+typedef enum {
+ RX_MODE_FIRST_BYTE,
+ RX_MODE_MIDDLE_BYTE,
+ RX_MODE_NEXT_TO_LAST_BYTE,
+ RX_MODE_LAST_BYTE,
+ RX_MODE_ONE_BYTE
+} I2C_RX_MODE;
+
+typedef enum {
+ GPIO_I2C_SDATA,
+ GPIO_I2C_SCLK,
+} GPIO_I2C_PIN;
+
+extern int gpio_i2c_busy(void);
+extern void gpio_i2c_tx_stop(void);
+extern void gpio_i2c_tx_start(void);
+extern int gpio_i2c_tx_byte(uint8_t data);
+extern int gpio_i2c_rx_byte(uint8_t *data, int rx_mode);
+extern void gpio_i2c_init(int bps);
+extern void gpio_i2c_config_pin(GPIO_I2C_PIN pin, GPIO_I2C_DIRECTION dir);
+extern void gpio_i2c_set_pin_level(GPIO_I2C_PIN pin, int level);
+extern void gpio_i2c_restore_pins(void);
diff --git a/board/ti/logic/logic-id-data.h b/board/ti/logic/logic-id-data.h
new file mode 100644
index 0000000000..73a7ddaa36
--- /dev/null
+++ b/board/ti/logic/logic-id-data.h
@@ -0,0 +1,156 @@
+const unsigned char id_data_buf[] /* __attribute__ ((section ("id_data"))) */ = {
+/* ID data header: */
+/* offset 0 */ 0x4c, 0x70, 0x49, 0x64, /* Magic key "LpId" */
+/* offset 4 */ 0x04, /* (0x04) one-byte version of id format */
+/* offset 5 */ 0x00, /* (0x00) unused byte */
+/* offset 6 */ 0x94, 0x02, /* (660) LE two-byte length of data following header */
+
+/* ID checksums: */
+/* offset 8 */ 0xf1, 0x4c, /* (0x4cf1) LE CRC-15 of data header */
+/* offset 10 */ 0x0f, 0x29, /* (0x290f) LE CRC-15 of following 660 ID data bytes */
+
+/* ID data: */
+/* offset 12 */ 0xa0|0x12, 0x29, /* (658) dict; size */
+/* offset 14 */ 0xc0|0x00, /* (0) key 'serialization_group' */
+/* offset 15 */ 0xa0|0x19, 0x1e, /* (489) dict; size */
+/* offset 17 */ 0xc0|0x01, /* (1) key 'serial_number' */
+/* offset 18 */ 0x40|0x0a, /* (10) string; len */
+/* offset 19 */ 0x31, 0x31, 0x31, 0x31, 0x4d, 0x30, 0x31, 0x38,
+/* offset 27 */ 0x32, 0x35,
+/* offset 29 */ 0xc0|0x02, /* (2) key 'lan_ethaddr1' */
+/* offset 30 */ 0x60|0x06, /* (6) string; len */
+/* offset 31 */ 0x00, 0x08, 0xee, 0x04, 0xb7, 0xd2,
+/* offset 37 */ 0xc0|0x06, /* (6) key 'nvs' */
+/* offset 38 */ 0x60|0x12, 0x1d, /* (466) string; len */
+/* offset 40 */ 0x01, 0x6d, 0x54, 0x00, 0x00, 0xef, 0xbe, 0x01,
+/* offset 48 */ 0x71, 0x54, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00,
+/* offset 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* offset 64 */ 0x01, 0x99, 0x01, 0xfa, 0xd6, 0xd0, 0xca, 0xc2,
+/* offset 72 */ 0xc9, 0xd6, 0xda, 0x05, 0x00, 0xf8, 0xfc, 0x0c,
+/* offset 80 */ 0x04, 0x00, 0xfb, 0x0c, 0x04, 0x00, 0xfc, 0x0a,
+/* offset 88 */ 0x03, 0xff, 0xfa, 0x0b, 0x02, 0xfe, 0xfb, 0x10,
+/* offset 96 */ 0x04, 0xff, 0xfa, 0x12, 0x04, 0x00, 0xfa, 0x12,
+/* offset 104 */ 0x05, 0x00, 0xfb, 0xea, 0xfc, 0x09, 0x09, 0x0c,
+/* offset 112 */ 0x0c, 0x0e, 0x11, 0x13, 0x17, 0x1a, 0x1d, 0x21,
+/* offset 120 */ 0x26, 0x2c, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3d,
+/* offset 128 */ 0x00, 0x41, 0x00, 0x46, 0x00, 0x4c, 0x00, 0x4f,
+/* offset 136 */ 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x40,
+/* offset 144 */ 0x00, 0x38, 0x00, 0xe9, 0xfc, 0x07, 0x08, 0x09,
+/* offset 152 */ 0x0b, 0x0a, 0x0e, 0x10, 0x13, 0x16, 0x19, 0x1d,
+/* offset 160 */ 0x1f, 0x23, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x31,
+/* offset 168 */ 0x00, 0x37, 0x00, 0x3d, 0x00, 0x44, 0x00, 0x4e,
+/* offset 176 */ 0x00, 0x55, 0x00, 0x5f, 0x00, 0x67, 0x00, 0x6c,
+/* offset 184 */ 0x00, 0x6d, 0x00, 0xeb, 0xfc, 0x07, 0x09, 0x0a,
+/* offset 192 */ 0x0b, 0x0a, 0x0f, 0x11, 0x14, 0x18, 0x1a, 0x1d,
+/* offset 200 */ 0x21, 0x25, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x33,
+/* offset 208 */ 0x00, 0x39, 0x00, 0x3f, 0x00, 0x46, 0x00, 0x4d,
+/* offset 216 */ 0x00, 0x59, 0x00, 0x5d, 0x00, 0x64, 0x00, 0x6a,
+/* offset 224 */ 0x00, 0x69, 0x00, 0xee, 0xfc, 0x08, 0x09, 0x0a,
+/* offset 232 */ 0x0e, 0x10, 0x12, 0x15, 0x18, 0x1d, 0x20, 0x23,
+/* offset 240 */ 0x26, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x3a, 0x00,
+/* offset 248 */ 0x3d, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x57, 0x00,
+/* offset 256 */ 0x5e, 0x00, 0x6c, 0x00, 0x70, 0x00, 0x72, 0x00,
+/* offset 264 */ 0x6c, 0x00, 0xef, 0xfc, 0x08, 0x09, 0x0b, 0x0a,
+/* offset 272 */ 0x0e, 0x10, 0x14, 0x15, 0x18, 0x1e, 0x20, 0x23,
+/* offset 280 */ 0x2a, 0x00, 0x2b, 0x00, 0x32, 0x00, 0x3c, 0x00,
+/* offset 288 */ 0x3e, 0x00, 0x48, 0x00, 0x51, 0x00, 0x5b, 0x00,
+/* offset 296 */ 0x63, 0x00, 0x72, 0x00, 0x75, 0x00, 0x78, 0x00,
+/* offset 304 */ 0x72, 0x00, 0xf2, 0xfc, 0x08, 0x0a, 0x0b, 0x0a,
+/* offset 312 */ 0x10, 0x11, 0x14, 0x17, 0x1a, 0x1e, 0x21, 0x25,
+/* offset 320 */ 0x29, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x3b, 0x00,
+/* offset 328 */ 0x3f, 0x00, 0x49, 0x00, 0x4f, 0x00, 0x5a, 0x00,
+/* offset 336 */ 0x63, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x77, 0x00,
+/* offset 344 */ 0x77, 0x00, 0xf1, 0xfc, 0x08, 0x0a, 0x0c, 0x0c,
+/* offset 352 */ 0x0f, 0x11, 0x14, 0x16, 0x1c, 0x1c, 0x21, 0x25,
+/* offset 360 */ 0x29, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x3b, 0x00,
+/* offset 368 */ 0x41, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x5e, 0x00,
+/* offset 376 */ 0x69, 0x00, 0x70, 0x00, 0x75, 0x00, 0x79, 0x00,
+/* offset 384 */ 0x84, 0x00, 0xef, 0xfc, 0x07, 0x0b, 0x0a, 0x0e,
+/* offset 392 */ 0x10, 0x13, 0x16, 0x19, 0x1d, 0x1f, 0x23, 0x29,
+/* offset 400 */ 0x00, 0x2d, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x40,
+/* offset 408 */ 0x00, 0x4a, 0x00, 0x54, 0x00, 0x62, 0x00, 0x6e,
+/* offset 416 */ 0x00, 0x76, 0x00, 0x81, 0x00, 0x81, 0x00, 0x8c,
+/* offset 424 */ 0x00, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x00,
+/* offset 432 */ 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0a, 0xfe,
+/* offset 440 */ 0x00, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff, 0xff,
+/* offset 448 */ 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0xfe, 0x00,
+/* offset 456 */ 0x00, 0x01, 0x09, 0x04, 0x00, 0xfb, 0xf6, 0x04,
+/* offset 464 */ 0x02, 0x00, 0xfe, 0xfd, 0xfc, 0x03, 0x02, 0x00,
+/* offset 472 */ 0xfd, 0xfb, 0x02, 0x13, 0x00, 0x00, 0x00, 0x00,
+/* offset 480 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* offset 488 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* offset 496 */ 0xaa, 0x03, 0x00, 0x00, 0x01, 0x02, 0xff, 0xff,
+/* offset 504 */ 0x00, 0x00,
+/* offset 506 */ 0xc0|0x07, /* (7) key 'model_group' */
+/* offset 507 */ 0xa0|0x15, 0x02, /* (37) dict; size */
+/* offset 509 */ 0xc0|0x08, /* (8) key 'model_name' */
+/* offset 510 */ 0x40|0x17, 0x01, /* (23) string; len */
+/* offset 512 */ 0x53, 0x4f, 0x4d, 0x44, 0x4d, 0x33, 0x37, 0x33,
+/* offset 520 */ 0x30, 0x2d, 0x31, 0x30, 0x2d, 0x32, 0x37, 0x38,
+/* offset 528 */ 0x32, 0x49, 0x46, 0x43, 0x52, 0x2d, 0x41,
+/* offset 535 */ 0xc0|0x09, /* (9) key 'part_number' */
+/* offset 536 */ 0x20|0x16, 0xde, 0xf0, 0x03, /* (0xf85e6) +num */
+/* offset 540 */ 0xc0|0x0a, /* (10) key 'version_code' */
+/* offset 541 */ 0x20|0x1e, 0x01, /* (0x1e) +num */
+/* offset 543 */ 0xc0|0x0b, /* (11) key 'hardware_platform' */
+/* offset 544 */ 0x40|0x01, /* (1) string; len */
+/* offset 545 */ 0x74,
+/* offset 546 */ 0xc0|0x0c, /* (12) key 'cpu0_group' */
+/* offset 547 */ 0xa0|0x0f, /* (15) dict; size */
+/* offset 548 */ 0xc0|0x0d, /* (13) key 'type' */
+/* offset 549 */ 0x40|0x02, /* (2) string; len */
+/* offset 550 */ 0x64, 0x6d,
+/* offset 552 */ 0xc0|0x0e, /* (14) key 'number' */
+/* offset 553 */ 0x20|0x12, 0xe9, 0x01, /* (0xe92) +num */
+/* offset 556 */ 0xc0|0x0f, /* (15) key 'speed_mhz' */
+/* offset 557 */ 0x20|0x18, 0x3e, /* (0x3e8) +num */
+/* offset 559 */ 0xc0|0x10, 0x01, /* (16) key 'temp_class' */
+/* offset 561 */ 0x40|0x01, /* (1) string; len */
+/* offset 562 */ 0x63,
+/* offset 563 */ 0xc0|0x11, 0x01, /* (17) key 'cpu0_bus_group' */
+/* offset 565 */ 0xa0|0x19, 0x06, /* (105) dict; size */
+/* offset 567 */ 0xc0|0x12, 0x01, /* (18) key 'dram_bus_group' */
+/* offset 569 */ 0xa0|0x16, 0x03, /* (54) dict; size */
+/* offset 571 */ 0xc0|0x13, 0x01, /* (19) key 'sysconfig_reg' */
+/* offset 573 */ 0x20|0x12, 0x01, /* (0x12) +num */
+/* offset 575 */ 0xc0|0x14, 0x01, /* (20) key 'sharing_reg' */
+/* offset 577 */ 0x20|0x10, 0x10, /* (0x100) +num */
+/* offset 579 */ 0xc0|0x1d, 0x01, /* (29) key 'power_reg' */
+/* offset 581 */ 0x20|0x09, /* (0x9) +num */
+/* offset 582 */ 0xc0|0x16, 0x01, /* (22) key 'cs_cfg_reg' */
+/* offset 584 */ 0x20|0x02, /* (0x2) +num */
+/* offset 585 */ 0xc0|0x1f, 0x01, /* (31) key 'cs0_group' */
+/* offset 587 */ 0xa0|0x14, 0x02, /* (36) dict; size */
+/* offset 589 */ 0xc0|0x17, 0x01, /* (23) key 'mcfg_reg' */
+/* offset 591 */ 0x20|0x19, 0x81, 0x90, 0xd6, 0x01, /* (0x3588019) +num */
+/* offset 596 */ 0xc0|0x18, 0x01, /* (24) key 'mr_reg' */
+/* offset 598 */ 0x20|0x12, 0x03, /* (0x32) +num */
+/* offset 600 */ 0xc0|0x19, 0x01, /* (25) key 'rfr_ctrl_reg' */
+/* offset 602 */ 0x20|0x11, 0xf0, 0x92, 0x01, /* (0x49701) +num */
+/* offset 606 */ 0xc0|0x1a, 0x01, /* (26) key 'emr2_reg' */
+/* offset 608 */ 0x20|0x10, 0x02, /* (0x20) +num */
+/* offset 610 */ 0xc0|0x1b, 0x01, /* (27) key 'actim_ctrla_reg' */
+/* offset 612 */ 0x20|0x17, 0xf0, 0xc8, 0xc9, 0x41, /* (0x83264707) +num */
+/* offset 617 */ 0xc0|0x1c, 0x01, /* (28) key 'actim_ctrlb_reg' */
+/* offset 619 */ 0x20|0x13, 0xe2, 0x42, /* (0x21623) +num */
+/* offset 622 */ 0xc0|0x15, 0x01, /* (21) key 'dlla_ctrl_reg' */
+/* offset 624 */ 0x20|0x08, /* (0x8) +num */
+/* offset 625 */ 0xc0|0x1e, 0x01, /* (30) key 'local_bus_group' */
+/* offset 627 */ 0xa0|0x1b, 0x02, /* (43) dict; size */
+/* offset 629 */ 0xc0|0x1f, 0x01, /* (31) key 'cs0_group' */
+/* offset 631 */ 0xa0|0x17, 0x02, /* (39) dict; size */
+/* offset 633 */ 0xc0|0x16, 0x02, /* (38) key 'config1_reg' */
+/* offset 635 */ 0x20|0x10, 0x80, 0x03, /* (0x1800) +num */
+/* offset 638 */ 0xc0|0x17, 0x02, /* (39) key 'config2_reg' */
+/* offset 640 */ 0x20|0x10, 0x90, 0xa1, 0x02, /* (0x90900) +num */
+/* offset 644 */ 0xc0|0x18, 0x02, /* (40) key 'config3_reg' */
+/* offset 646 */ 0x20|0x10, 0x90, 0xa1, 0x02, /* (0x90900) +num */
+/* offset 650 */ 0xc0|0x19, 0x02, /* (41) key 'config4_reg' */
+/* offset 652 */ 0x20|0x10, 0xd0, 0x80, 0x80, 0x03, /* (0x6000500) +num */
+/* offset 657 */ 0xc0|0x1a, 0x02, /* (42) key 'config5_reg' */
+/* offset 659 */ 0x20|0x1a, 0x80, 0xe1, 0x01, /* (0x7080a) +num */
+/* offset 663 */ 0xc0|0x1b, 0x02, /* (43) key 'config6_reg' */
+/* offset 665 */ 0x20|0x1f, 0x2c, /* (0x2cf) +num */
+/* offset 667 */ 0xc0|0x1c, 0x02, /* (44) key 'config7_reg' */
+/* offset 669 */ 0x20|0x1f, 0xf5, 0x01, /* (0xf5f) +num */
+};
diff --git a/board/ti/logic/logic-product-id.c b/board/ti/logic/logic-product-id.c
new file mode 100644
index 0000000000..4f427f94b6
--- /dev/null
+++ b/board/ti/logic/logic-product-id.c
@@ -0,0 +1,285 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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
+ */
+
+/* Code to extract x-loader perntinent data from product ID chip */
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/mem.h>
+
+// #include "dm3730logic-ddr.h"
+// #include "dm3730logic-product-id.h"
+
+#include "prod-id/interface.h"
+#include "prod-id/id-errno.h"
+#include "logic-i2c.h"
+#include "logic-id-data.h"
+#include "logic-at24.h"
+#include "logic-gpio.h"
+
+struct id_data id_data;
+
+/* Fetch a byte of data from the ID data on the i2c bus */
+unsigned char id_fetch_byte(unsigned char *mem_ptr, int offset, int *oor)
+{
+ unsigned char val;
+
+ /* If data is off end of known size then complain */
+ if (id_data.root_size && (offset >= (id_data.root_offset + id_data.root_size))) {
+ id_printf("Attempt to read past end of buffer (offset %u >= size %u)\n", offset, sizeof(id_data_buf));
+ *oor = -ID_ERANGE;
+ return 0; /* Force upper layer to recover */
+ }
+
+ *oor = ID_EOK;
+
+ if (mem_ptr) {
+ val = mem_ptr[offset];
+ return val;
+ } else {
+ if (at24_read(offset, &val, 1) == 0) {
+ return val;
+ }
+ }
+
+ *oor = ID_ENODEV;
+ return 0;
+}
+
+int id_printf(const char *fmt, ...)
+{
+ va_list args;
+ char printbuffer[256];
+
+ va_start (args, fmt);
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ vsprintf (printbuffer, fmt, args);
+ va_end (args);
+ /* Print the string */
+ serial_puts (printbuffer);
+
+ return 0;
+}
+
+void id_error(const char *fmt, ...)
+{
+ va_list args;
+ char printbuffer[256];
+
+ va_start (args, fmt);
+ /* For this to work, printbuffer must be larger than
+ * anything we ever want to print.
+ */
+ vsprintf (printbuffer, fmt, args);
+ va_end (args);
+ /* Print the string */
+ serial_puts (printbuffer);
+
+}
+
+static int found_id_data;
+/* Initialize the product ID data and return 0 if found */
+static int product_id_init(void)
+{
+ int ret;
+
+ memset(&id_data, 0, sizeof(id_data));
+
+ /* id_data.mem_ptr is an address top copy the ID data from the AT24
+ * chip into during startup(since startup codehas to CRC whole data
+ * area). Once its read there we can access the copy instead of
+ * going back to the AT24 to read the data. */
+ id_data.mem_ptr = (void *)SRAM_BASE;
+
+ ret=at24_wakeup();
+ if(ret) {
+ printf("wakeup_err=%d\n", ret);
+ }
+
+ ret = id_startup(&id_data);
+
+
+ at24_shutdown();
+
+ if (ret != ID_EOK) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int logic_has_new_product_id(void)
+{
+ if (!found_id_data) {
+ if (!product_id_init()) {
+ found_id_data = 1;
+ }
+ }
+ return found_id_data;
+}
+
+
+int logic_dump_serialization_info(void)
+{
+ int ret;
+ struct id_cookie cookie;
+ int part_number;
+ u8 model_name[32];
+ u32 model_name_size;
+ u8 serial_number[10];
+ u32 serial_number_size;
+
+ if (!found_id_data) {
+ return -1;
+ }
+
+ ret = id_init_cookie(&id_data, &cookie);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* find /serialization_group from root */
+ ret = id_find_dict(&cookie, ID_KEY_serialization_group, IDENUM_DICT);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* Find serial_number */
+ serial_number_size = sizeof(serial_number);
+ ret = id_find_string(&cookie, ID_KEY_serial_number, serial_number, &serial_number_size);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* Reinitialise cookie back to the root */
+ ret = id_init_cookie(&id_data, &cookie);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* find /model_group from root */
+ ret = id_find_dict(&cookie, ID_KEY_model_group, IDENUM_DICT);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* Find part number */
+ ret = id_find_number(&cookie, ID_KEY_part_number, &part_number);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ /* Find model name */
+ model_name_size = sizeof(model_name);
+ ret = id_find_string(&cookie, ID_KEY_model_name, model_name, &model_name_size);
+ if (ret != ID_EOK) {
+ printf("%s:%d ret %d\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+ }
+
+ printf("Part Number : %u\n", part_number);
+ printf("Model Name : %.*s\n", model_name_size, model_name);
+ printf("Serial Number: %.*s\n", serial_number_size, serial_number);
+ return 0;
+}
+
+/* Extract GPMC timings for particular CS register */
+id_keys_t gpmc_ncs_keys[] = {
+ ID_KEY_cs0_group,
+ ID_KEY_cs1_group,
+ ID_KEY_cs2_group,
+ ID_KEY_cs3_group,
+ ID_KEY_cs4_group,
+ ID_KEY_cs5_group,
+ ID_KEY_cs6_group,
+};
+
+id_keys_t gpmc_config_reg_keys[] = {
+ ID_KEY_config1_reg,
+ ID_KEY_config2_reg,
+ ID_KEY_config3_reg,
+ ID_KEY_config4_reg,
+ ID_KEY_config5_reg,
+ ID_KEY_config6_reg,
+ ID_KEY_config7_reg,
+};
+
+int logic_extract_gpmc_timing(int cs, int *config_regs)
+{
+ int ret;
+ struct id_cookie cookie;
+ // int gpmc_config_values[ARRAY_SIZE(gpmc_config_reg_keys)];
+
+ if (!found_id_data)
+ return -1;
+
+ ret = id_init_cookie(&id_data, &cookie);
+ if (ret != ID_EOK) {
+ return ret;
+ }
+
+ /* find /cpu0_bus_group from root */
+ ret = id_find_dict(&cookie, ID_KEY_cpu0_bus_group, IDENUM_DICT);
+ if (ret != ID_EOK) {
+ return ret;
+ }
+
+ /* find /local_bus_group from /cpu0_bus_group */
+ ret = id_find_dict(&cookie, ID_KEY_local_bus_group, IDENUM_DICT);
+ if (ret != ID_EOK) {
+ return ret;
+ }
+
+ /* Now look for the particular chip select group */
+ ret = id_find_dict(&cookie, gpmc_ncs_keys[cs], IDENUM_DICT);
+ if (ret != ID_EOK) {
+ return ret;
+ }
+
+ /* We have the group, now extract all the config registers */
+ ret = id_find_numbers(&cookie, gpmc_config_reg_keys, ARRAY_SIZE(gpmc_config_reg_keys), config_regs);
+
+ return ret;
+}
+
+int do_dump_id_data(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ printf("id_data: mem_ptr %p root_offset %u root_size %u\n",
+ id_data.mem_ptr, id_data.root_offset, id_data.root_size);
+ return 1;
+}
+
+U_BOOT_CMD(
+ dump_id_data, 1, 1, do_dump_id_data,
+ "dump_id_data - dump product ID data",
+ "dump product ID data in human-readable form"
+);
diff --git a/board/ti/logic/logic-product-id.h b/board/ti/logic/logic-product-id.h
new file mode 100644
index 0000000000..b4af92d606
--- /dev/null
+++ b/board/ti/logic/logic-product-id.h
@@ -0,0 +1,27 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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
+ */
+
+extern int logic_has_new_product_id(void);
+extern void logic_dump_new_product_data(void);
+extern void logic_dump_serialization_info(void);
diff --git a/board/ti/logic/logic-proto.h b/board/ti/logic/logic-proto.h
new file mode 100644
index 0000000000..2e67f76b97
--- /dev/null
+++ b/board/ti/logic/logic-proto.h
@@ -0,0 +1,26 @@
+/*
+ * (C) Copyright 2010
+ * Logic Product Development <peter.barada@logicpd.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
+ */
+
+/* Function to touchup environment variables for display */
+extern void touchup_display_env(void);
+
diff --git a/board/ti/logic/logic.c b/board/ti/logic/logic.c
new file mode 100644
index 0000000000..94562bdd40
--- /dev/null
+++ b/board/ti/logic/logic.c
@@ -0,0 +1,1300 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ *
+ * Author :
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Mohammed Khasim <khasim@ti.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 <netdev.h>
+#include <flash.h>
+#include <nand.h>
+#include <i2c.h>
+#include <twl4030.h>
+#include <asm/io.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+#include "logic.h"
+#include "product_id.h"
+#include "logic-proto.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MUX_LOGIC_HSUSB0_D5_GPIO_MUX() \
+ MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M4)) /*GPIO_189*/
+
+#define MUX_LOGIC_HSUSB0_D5_DATA5() \
+ MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA5*/
+
+/*
+ * Routine: logic_identify
+ * Description: Detect if we are running on a Logic or Torpedo.
+ * This can be done by GPIO_189. If its low after driving it high,
+ * then its a SOM LV, else Torpedo.
+ */
+unsigned int logic_identify(void)
+{
+ unsigned int val = 0;
+ u32 cpu_family = get_cpu_family();
+ int i;
+
+ MUX_LOGIC_HSUSB0_D5_GPIO_MUX();
+
+ if (!omap_request_gpio(189)) {
+
+ omap_set_gpio_direction(189, 0);
+ omap_set_gpio_dataout(189, 1);
+
+ /* Let it soak for a bit */
+ for (i=0; i<0x100; ++i)
+ asm("nop");
+
+ omap_set_gpio_direction(189, 1);
+ val = omap_get_gpio_datain(189);
+ omap_free_gpio(189);
+
+ printf("Board:");
+ if (cpu_family == CPU_OMAP36XX) {
+ printf(" DM37xx");
+ if (val) {
+ printf(" Torpedo\n");
+ val = MACH_TYPE_DM3730_TORPEDO;
+ } else {
+ printf(" SOM LV\n");
+ val = MACH_TYPE_DM3730_SOM_LV;
+ }
+ } else {
+ printf(" OMAP35xx");
+ if (val) {
+ printf(" Torpedo\n");
+ val = MACH_TYPE_OMAP3_TORPEDO;
+ } else {
+ printf(" SOM LV\n");
+ val = MACH_TYPE_OMAP3530_LV_SOM;
+ }
+ }
+ }
+
+ MUX_LOGIC_HSUSB0_D5_DATA5();
+
+ return val;
+}
+
+/*
+ * Set the default NAND ECC method used for the environment
+ */
+static int omap3logic_nand_default = -1;
+void nand_setup_default_ecc_method(void)
+{
+ if (omap_nand_chip_has_ecc())
+ omap3logic_nand_default = OMAP_ECC_CHIP;
+ else
+ omap3logic_nand_default = OMAP_ECC_HW;
+
+ omap_nand_switch_ecc(omap3logic_nand_default);
+}
+
+/*
+ * Switch NAND ECC method to that used for the environment,
+ * returning the current ECC method through *method
+ */
+void nand_switch_ecc_default(int *method)
+{
+ enum omap_nand_ecc_mode curr_mode;
+
+ curr_mode = omap_nand_current_ecc_method();
+ *method = (int) curr_mode;
+
+ if (curr_mode != omap3logic_nand_default)
+ omap_nand_switch_ecc(omap3logic_nand_default);
+}
+
+/*
+ * Switch ECC method
+ */
+void nand_switch_ecc_method(int method)
+{
+ enum omap_nand_ecc_mode curr_mode, new_mode;
+
+ curr_mode = omap_nand_current_ecc_method();
+ new_mode = (enum omap_nand_ecc_mode)method;
+ if (curr_mode != new_mode)
+ omap_nand_switch_ecc(new_mode);
+}
+
+/*
+ * Touchup the environment, specificaly to setenv "defaultecc"
+ */
+void touchup_env(void)
+{
+ /* Set the defaultecc environment variable to the "natural"
+ * ECC method supported by the NAND chip */
+ if (omap3logic_nand_default == OMAP_ECC_CHIP)
+ setenv("defaultecc", "chip");
+ else if (omap3logic_nand_default == OMAP_ECC_HW)
+ setenv("defaultecc", "hw");
+ else
+ printf("%s: bad NAND ECC default %d!\n", __FUNCTION__, omap3logic_nand_default);
+
+ /* touchup the display environment variable(s) */
+ touchup_display_env();
+}
+
+/*
+ * If the user tries to 'setenv foo', check if 'foo' is a "reserved" name.
+ * certain system variables should not be changed as they are board-specific
+ * variables
+ */
+int setenv_reserved_name(const char *name)
+{
+ if (!strcmp(name, "defaultecc"))
+ return 1;
+ return 0;
+}
+
+#ifdef CONFIG_USB_OMAP3
+/*
+ * MUSB port on OMAP3EVM Rev >= E requires extvbus programming.
+ */
+u8 omap3_evm_need_extvbus(void)
+{
+ u8 retval = 0;
+
+ retval = 1;
+
+ return retval;
+}
+#endif
+
+static void setup_nand_settings(void);
+static void setup_isp176x_settings(void);
+static void setup_compact_flash_settings(void);
+static void fix_flash_sync(void);
+
+/*
+ * Routine: board_init
+ * Description: Early hardware init.
+ */
+int board_init(void)
+{
+ gpmc_init(); /* in SRAM or SDRAM, finish GPMC */
+
+ /* board id for Linux */
+ gd->bd->bi_arch_number = logic_identify();
+
+ /* boot param addr */
+ gd->bd->bi_boot_params = (OMAP34XX_SDRC_CS0 + 0x100);
+
+ /* Update NAND settings */
+ setup_nand_settings();
+
+ /* Setup ISP176x settings */
+ if (gd->bd->bi_arch_number == MACH_TYPE_DM3730_TORPEDO
+ || gd->bd->bi_arch_number == MACH_TYPE_OMAP3_TORPEDO)
+ setup_isp176x_settings();
+
+ /* Setup ComactFlash GPMC settings */
+ if (gd->bd->bi_arch_number == MACH_TYPE_DM3730_SOM_LV
+ || gd->bd->bi_arch_number == MACH_TYPE_OMAP3530_LV_SOM)
+ setup_compact_flash_settings();
+
+ /* Probe for NOR and if found put into sync mode */
+ fix_flash_sync();
+
+ return 0;
+}
+
+int board_late_init(void)
+{
+ unsigned char enetaddr[6];
+
+ dump_production_data();
+
+ /* Fetch the ethaddr of the LAN */
+ board_get_nth_enetaddr(enetaddr, 0, 0);
+#ifdef CONFIG_HAS_ETH1
+ /* Fetch the ethaddr of the WiFi */
+ board_get_nth_enetaddr(enetaddr, 1, 1);
+#endif
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ nand_unlock(&nand_info[0], 0x0, nand_info[0].size);
+#endif
+
+#ifdef CONFIG_ENABLE_TWL4030_CHARGING
+ /* Enable charging on Torpedo unless $disablecharging == yes */
+ if (gd->bd->bi_arch_number == MACH_TYPE_OMAP3_TORPEDO) {
+ char *str;
+ str = getenv("disablecharging");
+ if (!str || strcmp(str, "yes") != 0) {
+ printf("Torpedo: Enabling battery charging\n");
+ twl4030_enable_charging();
+ }
+ }
+#endif
+
+#ifdef CONFIG_CMD_CACHE
+ dcache_enable();
+ printf ("Data (writethrough) Cache is %s\n",
+ dcache_status() ? "ON" : "OFF");
+#endif
+ return 0;
+}
+
+/* Turn on VAUX1 voltage to 3.0 volts to drive level shifters and
+ * power 3.0v parts (tsc2004 and Product ID chip) */
+#define I2C_TRITON2 0x4b /* Address of Triton power group */
+
+void init_vaux1_voltage(void)
+{
+#ifdef CONFIG_DRIVER_OMAP34XX_I2C
+ unsigned char data;
+ unsigned short msg;
+
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ /* Select the output voltage */
+ data = 0x04;
+ i2c_write(I2C_TRITON2, 0x72, 1, &data, 1);
+ /* Select the Processor resource group */
+ data = 0x20;
+ i2c_write(I2C_TRITON2, 0x72, 1, &data, 1);
+ /* Enable I2C access to the Power bus */
+ data = 0x02;
+ i2c_write(I2C_TRITON2, 0x4a, 1, &data, 1);
+ /* Send message MSB */
+ msg = (1<<13) | (1<<4) | (0xd<<0); /* group(process_grp1):resource(vaux1):res_active; */
+ data = msg >> 8;
+ i2c_write(I2C_TRITON2, 0x4b, 1, &data, 1);
+ /* Send message LSB */
+ data = msg & 0xff;
+ i2c_write(I2C_TRITON2, 0x4c, 1, &data, 1);
+#endif
+}
+
+/*
+ * Check _SYSCONFIG registers and fixup bootrom code leaving them in
+ * non forced-idle/smart-stdby mode
+ */
+
+static void check_sysconfig_regs(void)
+{
+ unsigned int temp, temp2;
+
+ /* Since DM3730Logic boards have bootorder of 0x2f, the bootrom
+ * attempts to boot via USB and leaves OTG_SYSCONFIG in non-idle */
+ temp = *(unsigned int *)OTG_SYSCONFIG;
+ temp2 = OTG_SYSCONFIG_MIDLEMODE_SMART_STDBY
+ | OTG_SYSCONFIG_SIDLEMODE_FORCE_IDLE
+ | OTG_SYSCONFIG_AUTOIDLE;
+ if (temp != temp2) {
+ printf("OTG_SYSCONFIG: %08x - needs to be %08x\n", temp, temp2);
+ *(unsigned int *)OTG_SYSCONFIG = temp2;
+ }
+}
+
+
+
+/*
+ * Routine: misc_init_r
+ * Description: Init ethernet (done here so udelay works)
+ */
+int misc_init_r(void)
+{
+
+#ifdef CONFIG_DRIVER_OMAP34XX_I2C
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
+ /* Turn on vaux1 to make sure voltage is to the product ID chip.
+ * Extract production data from ID chip, used to selectively
+ * initialize portions of the system */
+ init_vaux1_voltage();
+ fetch_production_data();
+
+#if defined(CONFIG_CMD_NET)
+ setup_net_chip();
+#endif
+
+ dieid_num_r();
+
+ check_sysconfig_regs();
+
+ return 0;
+}
+
+
+/* GPMC CS1 settings for Logic SOM LV/Torpedo LAN92xx Ethernet chip */
+#define LOGIC_NET_GPMC_CONFIG1 0x00001000
+#define LOGIC_NET_GPMC_CONFIG2 0x00080801
+#define LOGIC_NET_GPMC_CONFIG3 0x00000000
+#define LOGIC_NET_GPMC_CONFIG4 0x08010801
+#define LOGIC_NET_GPMC_CONFIG5 0x00080a0a
+#define LOGIC_NET_GPMC_CONFIG6 0x03000280
+#define LOGIC_NET_GPMC_CONFIG7 0x00000848
+
+/*
+ * Routine: setup_net_chip
+ * Description: Setting up the configuration GPMC registers specific to the
+ * Ethernet hardware.
+ */
+static void setup_net_chip(void)
+{
+ struct ctrl *ctrl_base = (struct ctrl *)OMAP34XX_CTRL_BASE;
+
+ /* Configure GPMC registers */
+ writel(LOGIC_NET_GPMC_CONFIG1, &gpmc_cfg->cs[1].config1);
+ writel(LOGIC_NET_GPMC_CONFIG2, &gpmc_cfg->cs[1].config2);
+ writel(LOGIC_NET_GPMC_CONFIG3, &gpmc_cfg->cs[1].config3);
+ writel(LOGIC_NET_GPMC_CONFIG4, &gpmc_cfg->cs[1].config4);
+ writel(LOGIC_NET_GPMC_CONFIG5, &gpmc_cfg->cs[1].config5);
+ writel(LOGIC_NET_GPMC_CONFIG6, &gpmc_cfg->cs[1].config6);
+ writel(LOGIC_NET_GPMC_CONFIG7, &gpmc_cfg->cs[1].config7);
+
+ /* Enable off mode for NWE in PADCONF_GPMC_NWE register */
+ writew(readw(&ctrl_base ->gpmc_nwe) | 0x0E00, &ctrl_base->gpmc_nwe);
+ /* Enable off mode for NOE in PADCONF_GPMC_NADV_ALE register */
+ writew(readw(&ctrl_base->gpmc_noe) | 0x0E00, &ctrl_base->gpmc_noe);
+ /* Enable off mode for ALE in PADCONF_GPMC_NADV_ALE register */
+ writew(readw(&ctrl_base->gpmc_nadv_ale) | 0x0E00,
+ &ctrl_base->gpmc_nadv_ale);
+
+}
+
+/* GPMC CS0 settings for Logic SOM LV/Torpedo NAND settings */
+#define LOGIC_NAND_GPMC_CONFIG1 0x00001800
+#define LOGIC_NAND_GPMC_CONFIG2 0x00090900
+#define LOGIC_NAND_GPMC_CONFIG3 0x00090900
+#define LOGIC_NAND_GPMC_CONFIG4 0x06000500
+#define LOGIC_NAND_GPMC_CONFIG5 0x0007080A
+#define LOGIC_NAND_GPMC_CONFIG6 0x000002CF
+#define LOGIC_NAND_GPMC_CONFIG7 0x00000C70
+
+static void setup_nand_settings(void)
+{
+ /* struct ctrl *ctrl_base = (struct ctrl *)OMAP34XX_CTRL_BASE; */
+
+ /* Configure GPMC registers */
+ writel(0x00000000, &gpmc_cfg->cs[0].config7);
+ sdelay(1000);
+ writel(LOGIC_NAND_GPMC_CONFIG1, &gpmc_cfg->cs[0].config1);
+ writel(LOGIC_NAND_GPMC_CONFIG2, &gpmc_cfg->cs[0].config2);
+ writel(LOGIC_NAND_GPMC_CONFIG3, &gpmc_cfg->cs[0].config3);
+ writel(LOGIC_NAND_GPMC_CONFIG4, &gpmc_cfg->cs[0].config4);
+ writel(LOGIC_NAND_GPMC_CONFIG5, &gpmc_cfg->cs[0].config5);
+ writel(LOGIC_NAND_GPMC_CONFIG6, &gpmc_cfg->cs[0].config6);
+ writel(LOGIC_NAND_GPMC_CONFIG7, &gpmc_cfg->cs[0].config7);
+ sdelay(2000);
+}
+
+#define LOGIC_CF_GPMC_CONFIG1 0x00001210
+#define LOGIC_CF_GPMC_CONFIG2 0x00131000
+#define LOGIC_CF_GPMC_CONFIG3 0x001f1f01
+#define LOGIC_CF_GPMC_CONFIG4 0x10030e03
+#define LOGIC_CF_GPMC_CONFIG5 0x010f1411
+#define LOGIC_CF_GPMC_CONFIG6 0x80030600
+#define LOGIC_CF_GPMC_CONFIG7 0x00000f58
+
+static void setup_compact_flash_settings(void)
+{
+ /* Configure GPMC registers */
+ writel(0x00000000, &gpmc_cfg->cs[3].config7);
+ sdelay(1000);
+ writel(LOGIC_CF_GPMC_CONFIG1, &gpmc_cfg->cs[3].config1);
+ writel(LOGIC_CF_GPMC_CONFIG2, &gpmc_cfg->cs[3].config2);
+ writel(LOGIC_CF_GPMC_CONFIG3, &gpmc_cfg->cs[3].config3);
+ writel(LOGIC_CF_GPMC_CONFIG4, &gpmc_cfg->cs[3].config4);
+ writel(LOGIC_CF_GPMC_CONFIG5, &gpmc_cfg->cs[3].config5);
+ writel(LOGIC_CF_GPMC_CONFIG6, &gpmc_cfg->cs[3].config6);
+ writel(LOGIC_CF_GPMC_CONFIG7, &gpmc_cfg->cs[3].config7);
+ sdelay(2000);
+}
+
+/* GPMC CS6 settings for Logic SOM LV/Torpedo ISP176x settings */
+#define LOGIC_ISP176X_GPMC_CONFIG1 0x00001000
+#define LOGIC_ISP176X_GPMC_CONFIG2 0x00090900
+#define LOGIC_ISP176X_GPMC_CONFIG3 0x00000000
+#define LOGIC_ISP176X_GPMC_CONFIG4 0x05000900
+#define LOGIC_ISP176X_GPMC_CONFIG5 0x0007090c
+#define LOGIC_ISP176X_GPMC_CONFIG6 0x04010200
+#define LOGIC_ISP176X_GPMC_CONFIG7 0x00000f5c
+
+static void setup_isp176x_settings(void)
+{
+ /* struct ctrl *ctrl_base = (struct ctrl *)OMAP34XX_CTRL_BASE; */
+
+ /* Configure GPMC registers */
+ writel(0x00000000, &gpmc_cfg->cs[6].config7);
+ sdelay(1000);
+ writel(LOGIC_ISP176X_GPMC_CONFIG1, &gpmc_cfg->cs[6].config1);
+ writel(LOGIC_ISP176X_GPMC_CONFIG2, &gpmc_cfg->cs[6].config2);
+ writel(LOGIC_ISP176X_GPMC_CONFIG3, &gpmc_cfg->cs[6].config3);
+ writel(LOGIC_ISP176X_GPMC_CONFIG4, &gpmc_cfg->cs[6].config4);
+ writel(LOGIC_ISP176X_GPMC_CONFIG5, &gpmc_cfg->cs[6].config5);
+ writel(LOGIC_ISP176X_GPMC_CONFIG6, &gpmc_cfg->cs[6].config6);
+ writel(LOGIC_ISP176X_GPMC_CONFIG7, &gpmc_cfg->cs[6].config7);
+ sdelay(2000);
+}
+
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG1 0x00001210
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG2 0x00101001
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG3 0x00020201
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG4 0x0f031003
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG5 0x000f1111
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG6 0x0f030080
+#define LOGIC_STNOR_ASYNC_GPMC_CONFIG7 0x00000c50
+
+#define LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG1 0x6A411213
+#define LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG2 0x000C1503
+#define LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG3 0x00050503
+#define LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG4 0x0B051506
+
+#define LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG1 0x68411213
+#define LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG2 0x000C1502
+#define LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG3 0x00040402
+#define LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG4 0x0B051505
+
+#define LOGIC_STNOR_SYNC_GPMC_CONFIG5 0x020E0C15
+#define LOGIC_STNOR_SYNC_GPMC_CONFIG6 0x0B0603C3
+#define LOGIC_STNOR_SYNC_GPMC_CONFIG7 0x00000c50
+
+
+#define LOGIC_FLASH_BASE 0x10000000
+
+/* These are bit definitions for the RCR register of the NOR flash */
+/* 28FxxxP30 device. This register sets the bus configration for reads. */
+/* settings, located on address pins A[15:0]. */
+#define FLASH_28FxxxP30_RCR_RM 0x8000
+#define FLASH_28FxxxP30_RCR_R 0x4000
+#define FLASH_28FxxxP30_RCR_LC(x) ((x & 0x7) << 11)
+#define FLASH_28FxxxP30_RCR_WP 0x0400
+#define FLASH_28FxxxP30_RCR_DH 0x0200
+#define FLASH_28FxxxP30_RCR_WD 0x0100
+#define FLASH_28FxxxP30_RCR_BS 0x0080
+#define FLASH_28FxxxP30_RCR_CE 0x0040
+#define FLASH_28FxxxP30_RCR_BW 0x0008
+#define FLASH_28FxxxP30_RCR_BL(x) ((x & 0x7) << 0)
+#define FLASH_28FxxxP30_BL_4 0x1
+#define FLASH_28FxxxP30_BL_8 0x2
+#define FLASH_28FxxxP30_BL_16 0x3
+#define FLASH_28FxxxP30_BL_CONT 0x7
+
+/*
+ * Routine: fix_flash_sync
+ * Description: Setting up the configuration GPMC registers specific to the
+ * NOR flash (and place in sync mode if not done).
+ */
+int omap3logic_flash_exists;
+static void fix_flash_sync(void)
+{
+ int arch_number;
+ u16 rcrval;
+
+ /* Check the arch_number - Torpedo doesn't have NOR flash */
+ arch_number = gd->bd->bi_arch_number;
+ if (!(arch_number == MACH_TYPE_DM3730_SOM_LV
+ || arch_number == MACH_TYPE_OMAP3530_LV_SOM))
+ return;
+
+ /* Check CS2 config, if its not in sync, or not valid, then configure it */
+ if ( !(readl(&gpmc_cfg->cs[2].config1) & TYPE_READTYPE) ||
+ !(readl(&gpmc_cfg->cs[2].config7) & 0x00000040) ) {
+
+ /* Invalidate, in case it is set valid */
+ writel(0x00000000, &gpmc_cfg->cs[2].config7);
+
+ /* clear WAIT1 polarity */
+ writel(readl(&gpmc_cfg->config) & ~0x200, &gpmc_cfg->config);
+
+ /* clear GPMC_TIMEOUT */
+ writel(0x0, &gpmc_cfg->timeout_control);
+
+ /* Configure GPMC registers for async */
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG1, &gpmc_cfg->cs[2].config1);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG2, &gpmc_cfg->cs[2].config2);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG3, &gpmc_cfg->cs[2].config3);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG4, &gpmc_cfg->cs[2].config4);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG5, &gpmc_cfg->cs[2].config5);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG6, &gpmc_cfg->cs[2].config6);
+ writel(LOGIC_STNOR_ASYNC_GPMC_CONFIG7, &gpmc_cfg->cs[2].config7);
+
+ /* Test if this NOR flash is connected */
+ *(volatile u16 *)LOGIC_FLASH_BASE = 0x0070; // Read status reg
+ if (*(volatile u16 *)LOGIC_FLASH_BASE != 0x0080)
+ {
+ writel(0x00000000, &gpmc_cfg->cs[2].config7); /* Invalidate chip select */
+ puts("NOR: no flash device detected\n");
+ return; // fail - no NOR flash detected
+ }
+ *(volatile u16 *)LOGIC_FLASH_BASE = 0x0050; // Restore to read mode
+
+ puts("NOR: initialize in sync mode\n");
+
+ /* 1st NOR cycle, send read config register setup 0x60 */
+ *(volatile u16 *)LOGIC_FLASH_BASE = 0x0060;
+
+ /* 2nd NOR cycle, send 0x03 to latch in read
+ * configuration register setttings, located on A[15:0] */
+ rcrval = FLASH_28FxxxP30_RCR_LC(4) | FLASH_28FxxxP30_RCR_WP |
+ FLASH_28FxxxP30_RCR_BS | FLASH_28FxxxP30_RCR_CE |
+ FLASH_28FxxxP30_RCR_BW | FLASH_28FxxxP30_RCR_BL(FLASH_28FxxxP30_BL_4);
+ *(volatile u16 *)(LOGIC_FLASH_BASE | (rcrval << 1)) = 0x0003;
+
+ /* Give a chance for accesses to finish... */
+ sdelay(2000);
+
+ /* Third, set GPMC for sync. */
+ if (arch_number == MACH_TYPE_DM3730_SOM_LV) {
+ /* Use DM3730 SOM LV NOR timings */
+ writel(LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG1, &gpmc_cfg->cs[2].config1);
+ writel(LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG2, &gpmc_cfg->cs[2].config2);
+ writel(LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG3, &gpmc_cfg->cs[2].config3);
+ writel(LOGIC_STNOR_DM37x_SYNC_GPMC_CONFIG4, &gpmc_cfg->cs[2].config4);
+ }
+ if (arch_number == MACH_TYPE_OMAP3530_LV_SOM) {
+ /* Use DM3730 SOM LV NOR timings */
+ writel(LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG1, &gpmc_cfg->cs[2].config1);
+ writel(LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG2, &gpmc_cfg->cs[2].config2);
+ writel(LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG3, &gpmc_cfg->cs[2].config3);
+ writel(LOGIC_STNOR_OMAP35x_SYNC_GPMC_CONFIG4, &gpmc_cfg->cs[2].config4);
+ }
+ writel(LOGIC_STNOR_SYNC_GPMC_CONFIG5, &gpmc_cfg->cs[2].config5);
+ writel(LOGIC_STNOR_SYNC_GPMC_CONFIG6, &gpmc_cfg->cs[2].config6);
+ writel(LOGIC_STNOR_SYNC_GPMC_CONFIG7, &gpmc_cfg->cs[2].config7);
+ /* And lastly, set the WAIT1 polarity high */
+ writel(readl(&gpmc_cfg->config) | 0x200, &gpmc_cfg->config);
+ } else
+ puts ("NOR: Already initialized in sync mode\n");
+
+ omap3logic_flash_exists = 1;
+}
+
+int board_eth_init(bd_t *bis)
+{
+ int rc = 0;
+#ifdef CONFIG_SMC911X
+ rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+ return rc;
+}
+
+#ifdef CONFIG_CMD_GPMC_CONFIG
+int do_dump_gpmc(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ gpmc_cfg = (struct gpmc *)GPMC_BASE;
+ int i;
+ printf("GPMC_SYSCONFIG: %08x\n", gpmc_cfg->sysconfig);
+ printf("GPMC_CONFIG: %08x\n", gpmc_cfg->config);
+ for (i=0; i<8; ++i) {
+ struct gpmc_cs *p = &gpmc_cfg->cs[i];
+ if (p->config7 & (1<<6)) {
+ printf("GPMC%d: %08x %08x %08x %08x\n", i,
+ p->config1, p->config2, p->config3, p->config4);
+ printf(" %08x %08x %03x\n",
+ p->config5, p->config6, p->config7);
+ }
+ }
+ return 1;
+}
+
+U_BOOT_CMD(
+ gpmc_config, 1, 1, do_dump_gpmc,
+ "gpmc_config - dump GPMC settings",
+ "dump valid GPMC configuration"
+);
+#endif
+
+#ifdef CONFIG_CMD_MUX_CONFIG
+int do_dump_mux_config(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ int i,j;
+ u16 val;
+ struct {
+ u16 start;
+ u16 stop;
+ } mux_offsets[] = {
+ {
+ CONTROL_PADCONF_SDRC_D0, /* 0x0030 */
+ CONTROL_PADCONF_SDRC_CKE1, /* 0x0264 */
+ },
+ {
+ CONTROL_PADCONF_SYS_32K, /* 0x0A04 */
+ CONTROL_PADCONF_D2D_SWAKEUP, /* 0x0A4C */
+ },
+ {
+ CONTROL_PADCONF_ETK_CLK_ES2, /* 0x05D8 */
+ CONTROL_PADCONF_ETK_D15_ES2, /* 0x05FA */
+ },
+ };
+
+ for (i=0; i<ARRAY_SIZE(mux_offsets); ++i) {
+ for (j=mux_offsets[i].start; j<mux_offsets[i].stop; j+= sizeof(u16)) {
+ val = readw(OMAP34XX_CTRL_BASE + j);
+ if ((val & M7) != M7) {
+ printf("%04x: %04x (",
+ j, val);
+ if (val & IEN)
+ printf("IEN ");
+ else
+ printf("IDIS");
+ if (val & PTU)
+ printf(" | PTU");
+ else
+ printf(" | PTD");
+ if (val & EN)
+ printf(" | EN ");
+ else
+ printf(" | DIS");
+ printf(" | M%d)\n", (val & M7));
+ }
+ }
+ }
+ return 0;
+}
+
+U_BOOT_CMD(mux_config, 1, 1, do_dump_mux_config,
+ "mux_config - dump active mux registers",
+ "dump active mux configuration"
+);
+#endif
+
+
+
+/*
+ * IEN - Input Enable
+ * IDIS - Input Disable
+ * PTD - Pull type Down
+ * PTU - Pull type Up
+ * DIS - Pull type selection is inactive
+ * EN - Pull type selection is active
+ * M0 - Mode 0
+ * The commented string gives the final mux configuration for that pin
+ */
+
+/*
+ * Routine: set_muxconf_regs
+ * Description: Setting up the configuration Mux registers specific to the
+ * hardware. Many pins need to be moved from protect to primary
+ * mode.
+ */
+#define SAFE_MODE_PINS_1
+#define SAFE_MODE_PINS_2
+#define SAFE_MODE_PINS_3
+#define SAFE_MODE_PINS_4
+#undef SAFE_MODE_PINS_5
+#define SAFE_MODE_PINS_5A
+#define SAFE_MODE_PINS_6
+void set_muxconf_regs(void)
+{
+ /*SDRC*/
+ MUX_VAL(CP(SDRC_D0), (IEN | PTD | DIS | M0)); /*SDRC_D0*/
+ MUX_VAL(CP(SDRC_D1), (IEN | PTD | DIS | M0)); /*SDRC_D1*/
+ MUX_VAL(CP(SDRC_D2), (IEN | PTD | DIS | M0)); /*SDRC_D2*/
+ MUX_VAL(CP(SDRC_D3), (IEN | PTD | DIS | M0)); /*SDRC_D3*/
+ MUX_VAL(CP(SDRC_D4), (IEN | PTD | DIS | M0)); /*SDRC_D4*/
+ MUX_VAL(CP(SDRC_D5), (IEN | PTD | DIS | M0)); /*SDRC_D5*/
+ MUX_VAL(CP(SDRC_D6), (IEN | PTD | DIS | M0)); /*SDRC_D6*/
+ MUX_VAL(CP(SDRC_D7), (IEN | PTD | DIS | M0)); /*SDRC_D7*/
+ MUX_VAL(CP(SDRC_D8), (IEN | PTD | DIS | M0)); /*SDRC_D8*/
+ MUX_VAL(CP(SDRC_D9), (IEN | PTD | DIS | M0)); /*SDRC_D9*/
+ MUX_VAL(CP(SDRC_D10), (IEN | PTD | DIS | M0)); /*SDRC_D10*/
+ MUX_VAL(CP(SDRC_D11), (IEN | PTD | DIS | M0)); /*SDRC_D11*/
+ MUX_VAL(CP(SDRC_D12), (IEN | PTD | DIS | M0)); /*SDRC_D12*/
+ MUX_VAL(CP(SDRC_D13), (IEN | PTD | DIS | M0)); /*SDRC_D13*/
+ MUX_VAL(CP(SDRC_D14), (IEN | PTD | DIS | M0)); /*SDRC_D14*/
+ MUX_VAL(CP(SDRC_D15), (IEN | PTD | DIS | M0)); /*SDRC_D15*/
+ MUX_VAL(CP(SDRC_D16), (IEN | PTD | DIS | M0)); /*SDRC_D16*/
+ MUX_VAL(CP(SDRC_D17), (IEN | PTD | DIS | M0)); /*SDRC_D17*/
+ MUX_VAL(CP(SDRC_D18), (IEN | PTD | DIS | M0)); /*SDRC_D18*/
+ MUX_VAL(CP(SDRC_D19), (IEN | PTD | DIS | M0)); /*SDRC_D19*/
+ MUX_VAL(CP(SDRC_D20), (IEN | PTD | DIS | M0)); /*SDRC_D20*/
+ MUX_VAL(CP(SDRC_D21), (IEN | PTD | DIS | M0)); /*SDRC_D21*/
+ MUX_VAL(CP(SDRC_D22), (IEN | PTD | DIS | M0)); /*SDRC_D22*/
+ MUX_VAL(CP(SDRC_D23), (IEN | PTD | DIS | M0)); /*SDRC_D23*/
+ MUX_VAL(CP(SDRC_D24), (IEN | PTD | DIS | M0)); /*SDRC_D24*/
+ MUX_VAL(CP(SDRC_D25), (IEN | PTD | DIS | M0)); /*SDRC_D25*/
+ MUX_VAL(CP(SDRC_D26), (IEN | PTD | DIS | M0)); /*SDRC_D26*/
+ MUX_VAL(CP(SDRC_D27), (IEN | PTD | DIS | M0)); /*SDRC_D27*/
+ MUX_VAL(CP(SDRC_D28), (IEN | PTD | DIS | M0)); /*SDRC_D28*/
+ MUX_VAL(CP(SDRC_D29), (IEN | PTD | DIS | M0)); /*SDRC_D29*/
+ MUX_VAL(CP(SDRC_D30), (IEN | PTD | DIS | M0)); /*SDRC_D30*/
+ MUX_VAL(CP(SDRC_D31), (IEN | PTD | DIS | M0)); /*SDRC_D31*/
+ MUX_VAL(CP(SDRC_CLK), (IEN | PTD | DIS | M0)); /*SDRC_CLK*/
+ MUX_VAL(CP(SDRC_DQS0), (IEN | PTD | DIS | M0)); /*SDRC_DQS0*/
+ MUX_VAL(CP(SDRC_DQS1), (IEN | PTD | DIS | M0)); /*SDRC_DQS1*/
+ MUX_VAL(CP(SDRC_DQS2), (IEN | PTD | DIS | M0)); /*SDRC_DQS2*/
+ MUX_VAL(CP(SDRC_DQS3), (IEN | PTD | DIS | M0)); /*SDRC_DQS3*/
+ /*GPMC*/
+ MUX_VAL(CP(GPMC_A1), (IDIS | PTU | EN | M0)); /*GPMC_A1*/
+ MUX_VAL(CP(GPMC_A2), (IDIS | PTU | EN | M0)); /*GPMC_A2*/
+ MUX_VAL(CP(GPMC_A3), (IDIS | PTU | EN | M0)); /*GPMC_A3*/
+ MUX_VAL(CP(GPMC_A4), (IDIS | PTU | EN | M0)); /*GPMC_A4*/
+ MUX_VAL(CP(GPMC_A5), (IDIS | PTU | EN | M0)); /*GPMC_A5*/
+ MUX_VAL(CP(GPMC_A6), (IDIS | PTU | EN | M0)); /*GPMC_A6*/
+ MUX_VAL(CP(GPMC_A7), (IDIS | PTU | EN | M0)); /*GPMC_A7*/
+ MUX_VAL(CP(GPMC_A8), (IDIS | PTU | EN | M0)); /*GPMC_A8*/
+ MUX_VAL(CP(GPMC_A9), (IDIS | PTU | EN | M0)); /*GPMC_A9*/
+ MUX_VAL(CP(GPMC_A10), (IDIS | PTU | EN | M0)); /*GPMC_A10*/
+ MUX_VAL(CP(GPMC_D0), (IEN | PTU | EN | M0)); /*GPMC_D0*/
+ MUX_VAL(CP(GPMC_D1), (IEN | PTU | EN | M0)); /*GPMC_D1*/
+ MUX_VAL(CP(GPMC_D2), (IEN | PTU | EN | M0)); /*GPMC_D2*/
+ MUX_VAL(CP(GPMC_D3), (IEN | PTU | EN | M0)); /*GPMC_D3*/
+ MUX_VAL(CP(GPMC_D4), (IEN | PTU | EN | M0)); /*GPMC_D4*/
+ MUX_VAL(CP(GPMC_D5), (IEN | PTU | EN | M0)); /*GPMC_D5*/
+ MUX_VAL(CP(GPMC_D6), (IEN | PTU | EN | M0)); /*GPMC_D6*/
+ MUX_VAL(CP(GPMC_D7), (IEN | PTU | EN | M0)); /*GPMC_D7*/
+ MUX_VAL(CP(GPMC_D8), (IEN | PTU | EN | M0)); /*GPMC_D8*/
+ MUX_VAL(CP(GPMC_D9), (IEN | PTU | EN | M0)); /*GPMC_D9*/
+ MUX_VAL(CP(GPMC_D10), (IEN | PTU | EN | M0)); /*GPMC_D10*/
+ MUX_VAL(CP(GPMC_D11), (IEN | PTU | EN | M0)); /*GPMC_D11*/
+ MUX_VAL(CP(GPMC_D12), (IEN | PTU | EN | M0)); /*GPMC_D12*/
+ MUX_VAL(CP(GPMC_D13), (IEN | PTU | EN | M0)); /*GPMC_D13*/
+ MUX_VAL(CP(GPMC_D14), (IEN | PTU | EN | M0)); /*GPMC_D14*/
+ MUX_VAL(CP(GPMC_D15), (IEN | PTU | EN | M0)); /*GPMC_D15*/
+ MUX_VAL(CP(GPMC_NCS0), (IDIS | PTU | EN | M0)); /*GPMC_nCS0*/
+ MUX_VAL(CP(GPMC_NCS1), (IDIS | PTU | EN | M0)); /*GPMC_nCS1*/
+ MUX_VAL(CP(GPMC_NCS2), (IDIS | PTU | EN | M0)); /*GPMC_nCS2*/
+ MUX_VAL(CP(GPMC_NCS3), (IDIS | PTD | DIS | M0)); /*GPMC_nCS3*/
+ MUX_VAL(CP(GPMC_NCS4), (IEN | PTU | EN | M0)); /*GPMC_nCS4*/
+#if 1
+ /* Display GPIO */
+ MUX_VAL(CP(GPMC_NCS5), (IDIS | PTU | DIS | M4)); /*GPIO_65 backlight */
+#else
+ MUX_VAL(CP(GPMC_NCS5), (IDIS | PTU | EN | M0)); /*GPMC_nCS5*/
+#endif
+ MUX_VAL(CP(GPMC_NCS6), (IEN | PTD | DIS | M0)); /*GPMC_nCS6*/
+ MUX_VAL(CP(GPMC_NCS7), (IDIS | PTD | DIS | M1)); /*GPMC_IO_DIR*/
+ MUX_VAL(CP(GPMC_CLK), (IEN | PTD | DIS | M0)); /*GPMC_CLK*/
+ MUX_VAL(CP(GPMC_NADV_ALE), (IDIS | PTD | DIS | M0)); /*GPMC_nADV_ALE*/
+ MUX_VAL(CP(GPMC_NOE), (IDIS | PTD | DIS | M0)); /*GPMC_nOE*/
+ MUX_VAL(CP(GPMC_NWE), (IDIS | PTD | DIS | M0)); /*GPMC_nWE*/
+ MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTU | EN | M0)); /*GPMC_nBE0_CLE*/
+ MUX_VAL(CP(GPMC_NBE1), (IEN | PTU | EN | M0)); /*GPMC_nBE1*/
+ MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); /*GPMC_nWP*/
+ MUX_VAL(CP(GPMC_WAIT0), (IEN | PTU | EN | M0)); /*GPMC_WAIT0*/
+ MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); /*GPMC_WAIT1*/
+#ifdef SAFE_MODE_PINS_1
+ MUX_VAL(CP(GPMC_WAIT2), (IEN | PTD | EN | M7)); /*safe mode */
+#else
+ MUX_VAL(CP(GPMC_WAIT2), (IEN | PTU | EN | M4)); /*GPIO_64*/
+ /* - ETH_nRESET*/
+#endif
+ MUX_VAL(CP(GPMC_WAIT3), (IEN | PTU | EN | M0)); /*GPMC_WAIT3*/
+ /*DSS*/
+#ifdef SAFE_MODE_PINS_2
+ MUX_VAL(CP(DSS_PCLK), (IEN | PTD | EN | M7)); /*DSS_PCLK*/
+ MUX_VAL(CP(DSS_HSYNC), (IEN | PTD | EN | M7)); /*DSS_HSYNC*/
+ MUX_VAL(CP(DSS_VSYNC), (IEN | PTD | EN | M7)); /*DSS_VSYNC*/
+ MUX_VAL(CP(DSS_ACBIAS), (IEN | PTD | EN | M7)); /*DSS_ACBIAS*/
+ MUX_VAL(CP(DSS_DATA0), (IEN | PTD | EN | M7)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA1), (IEN | PTD | EN | M7)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA2), (IEN | PTD | EN | M7)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA3), (IEN | PTD | EN | M7)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA4), (IEN | PTD | EN | M7)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA5), (IEN | PTD | EN | M7)); /*DSS_DATA5*/
+ MUX_VAL(CP(DSS_DATA6), (IEN | PTD | EN | M7)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA7), (IEN | PTD | EN | M7)); /*DSS_DATA7*/
+ MUX_VAL(CP(DSS_DATA8), (IEN | PTD | EN | M7)); /*DSS_DATA8*/
+ MUX_VAL(CP(DSS_DATA9), (IEN | PTD | EN | M7)); /*DSS_DATA9*/
+ MUX_VAL(CP(DSS_DATA10), (IEN | PTD | EN | M7)); /*DSS_DATA10*/
+ MUX_VAL(CP(DSS_DATA11), (IEN | PTD | EN | M7)); /*DSS_DATA11*/
+ MUX_VAL(CP(DSS_DATA12), (IEN | PTD | EN | M7)); /*DSS_DATA12*/
+ MUX_VAL(CP(DSS_DATA13), (IEN | PTD | EN | M7)); /*DSS_DATA13*/
+ MUX_VAL(CP(DSS_DATA14), (IEN | PTD | EN | M7)); /*DSS_DATA14*/
+ MUX_VAL(CP(DSS_DATA15), (IEN | PTD | EN | M7)); /*DSS_DATA15*/
+ MUX_VAL(CP(DSS_DATA16), (IEN | PTD | EN | M7)); /*DSS_DATA16*/
+ MUX_VAL(CP(DSS_DATA17), (IEN | PTD | EN | M7)); /*DSS_DATA17*/
+ MUX_VAL(CP(DSS_DATA18), (IEN | PTD | EN | M7)); /*DSS_DATA18*/
+ MUX_VAL(CP(DSS_DATA19), (IEN | PTD | EN | M7)); /*DSS_DATA19*/
+ MUX_VAL(CP(DSS_DATA20), (IEN | PTD | EN | M7)); /*DSS_DATA20*/
+ MUX_VAL(CP(DSS_DATA21), (IEN | PTD | EN | M7)); /*DSS_DATA21*/
+ MUX_VAL(CP(DSS_DATA22), (IEN | PTD | EN | M7)); /*DSS_DATA22*/
+ MUX_VAL(CP(DSS_DATA23), (IEN | PTD | EN | M7)); /*DSS_DATA23*/
+ /*CAMERA*/
+ MUX_VAL(CP(CAM_HS), (IEN | PTD | EN | M7)); /*CAM_HS */
+ MUX_VAL(CP(CAM_VS), (IEN | PTD | EN | M7)); /*CAM_VS */
+ MUX_VAL(CP(CAM_XCLKA), (IEN | PTD | EN | M7)); /*CAM_XCLKA*/
+ MUX_VAL(CP(CAM_PCLK), (IEN | PTD | EN | M7)); /*CAM_PCLK*/
+ MUX_VAL(CP(CAM_FLD), (IEN | PTD | EN | M7)); /*GPIO_98*/
+ /* - CAM_RESET*/
+ MUX_VAL(CP(CAM_D0), (IEN | PTD | EN | M7)); /*CAM_D0*/
+ MUX_VAL(CP(CAM_D1), (IEN | PTD | EN | M7)); /*CAM_D1*/
+ MUX_VAL(CP(CAM_D2), (IEN | PTD | EN | M7)); /*CAM_D2*/
+ MUX_VAL(CP(CAM_D3), (IEN | PTD | EN | M7)); /*CAM_D3*/
+ MUX_VAL(CP(CAM_D4), (IEN | PTD | EN | M7)); /*CAM_D4*/
+ MUX_VAL(CP(CAM_D5), (IEN | PTD | EN | M7)); /*CAM_D5*/
+ MUX_VAL(CP(CAM_D6), (IEN | PTD | EN | M7)); /*CAM_D6*/
+ MUX_VAL(CP(CAM_D7), (IEN | PTD | EN | M7)); /*CAM_D7*/
+ MUX_VAL(CP(CAM_D8), (IEN | PTD | EN | M7)); /*CAM_D8*/
+ MUX_VAL(CP(CAM_D9), (IEN | PTD | EN | M7)); /*CAM_D9*/
+ MUX_VAL(CP(CAM_D10), (IEN | PTD | EN | M7)); /*CAM_D10*/
+ MUX_VAL(CP(CAM_D11), (IEN | PTD | EN | M7)); /*CAM_D11*/
+ MUX_VAL(CP(CAM_XCLKB), (IEN | PTD | EN | M7)); /*CAM_XCLKB*/
+ MUX_VAL(CP(CAM_WEN), (IEN | PTD | EN | M7)); /*GPIO_167*/
+ MUX_VAL(CP(CAM_STROBE), (IEN | PTD | EN | M7)); /*CAM_STROBE*/
+ MUX_VAL(CP(CSI2_DX0), (IEN | PTD | EN | M7)); /*CSI2_DX0*/
+ MUX_VAL(CP(CSI2_DY0), (IEN | PTD | EN | M7)); /*CSI2_DY0*/
+ MUX_VAL(CP(CSI2_DX1), (IEN | PTD | EN | M7)); /*CSI2_DX1*/
+ MUX_VAL(CP(CSI2_DY1), (IEN | PTD | EN | M7)); /*CSI2_DY1*/
+ /*Audio Interface */
+ MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | EN | M7)); /*McBSP2_FSX*/
+ MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | EN | M7)); /*McBSP2_CLKX*/
+ MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | EN | M7)); /*McBSP2_DR*/
+ MUX_VAL(CP(MCBSP2_DX), (IEN | PTD | EN | M7)); /*McBSP2_DX*/
+#else
+ /*CAMERA*/
+ MUX_VAL(CP(CAM_HS), (IEN | PTD | EN | M0)); /*CAM_HS */
+ MUX_VAL(CP(CAM_VS), (IEN | PTD | EN | M0)); /*CAM_VS */
+ MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | EN | M0)); /*CAM_XCLKA*/
+ MUX_VAL(CP(CAM_PCLK), (IEN | PTD | EN | M0)); /*CAM_PCLK*/
+ MUX_VAL(CP(CAM_FLD), (IDIS | PTD | EN | M4)); /*GPIO_98*/
+ /* - CAM_RESET*/
+ MUX_VAL(CP(CAM_D0), (IEN | PTD | EN | M0)); /*CAM_D0*/
+ MUX_VAL(CP(CAM_D1), (IEN | PTD | EN | M0)); /*CAM_D1*/
+ MUX_VAL(CP(CAM_D2), (IEN | PTD | EN | M0)); /*CAM_D2*/
+ MUX_VAL(CP(CAM_D3), (IEN | PTD | EN | M0)); /*CAM_D3*/
+ MUX_VAL(CP(CAM_D4), (IEN | PTD | EN | M0)); /*CAM_D4*/
+ MUX_VAL(CP(CAM_D5), (IEN | PTD | EN | M0)); /*CAM_D5*/
+ MUX_VAL(CP(CAM_D6), (IEN | PTD | EN | M0)); /*CAM_D6*/
+ MUX_VAL(CP(CAM_D7), (IEN | PTD | EN | M0)); /*CAM_D7*/
+ MUX_VAL(CP(CAM_D8), (IEN | PTD | EN | M0)); /*CAM_D8*/
+ MUX_VAL(CP(CAM_D9), (IEN | PTD | EN | M0)); /*CAM_D9*/
+ MUX_VAL(CP(CAM_D10), (IEN | PTD | EN | M0)); /*CAM_D10*/
+ MUX_VAL(CP(CAM_D11), (IEN | PTD | EN | M0)); /*CAM_D11*/
+ MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | EN | M0)); /*CAM_XCLKB*/
+ MUX_VAL(CP(CAM_WEN), (IEN | PTD | EN | M4)); /*GPIO_167*/
+ MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | EN | M0)); /*CAM_STROBE*/
+ MUX_VAL(CP(CSI2_DX0), (IEN | PTD | EN | M0)); /*CSI2_DX0*/
+ MUX_VAL(CP(CSI2_DY0), (IEN | PTD | EN | M0)); /*CSI2_DY0*/
+ MUX_VAL(CP(CSI2_DX1), (IEN | PTD | EN | M0)); /*CSI2_DX1*/
+ MUX_VAL(CP(CSI2_DY1), (IEN | PTD | EN | M0)); /*CSI2_DY1*/
+ /*Audio Interface */
+ MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | EN | M0)); /*McBSP2_FSX*/
+ MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | EN | M0)); /*McBSP2_CLKX*/
+ MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | EN | M0)); /*McBSP2_DR*/
+ MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | EN | M0)); /*McBSP2_DX*/
+#endif
+
+#if 0 /* Setup in lcd_setup_pinmux() */
+ MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | EN | M0)); /*DSS_PCLK*/
+ MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | EN | M0)); /*DSS_HSYNC*/
+ MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | EN | M0)); /*DSS_VSYNC*/
+ MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | EN | M0)); /*DSS_ACBIAS*/
+#if 1
+ /*DSS - with DATA18-23 muxed as DATA0-5 */
+ MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | EN | M0)); /*DSS_PCLK*/
+ MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | EN | M0)); /*DSS_HSYNC*/
+ MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | EN | M0)); /*DSS_VSYNC*/
+ MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | EN | M0)); /*DSS_ACBIAS*/
+#if 1
+ /* SOM used DATA0-5 for output */
+ MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | EN | M0)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | EN | M0)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | EN | M0)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | EN | M0)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | EN | M0)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | EN | M0)); /*DSS_DATA5*/
+#else
+ /* Torpedo doesn't used DATA0-5 for output */
+ MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | EN | M7)); /*SAFE*/
+ MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | EN | M7)); /*SAFE*/
+ MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | EN | M7)); /*SAFE*/
+ MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | EN | M7)); /*SAFE*/
+ MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | EN | M7)); /*SAFE*/
+ MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | EN | M7)); /*SAFE*/
+#endif
+ MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | EN | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | EN | M0)); /*DSS_DATA7*/
+ MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | EN | M0)); /*DSS_DATA8*/
+ MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | EN | M0)); /*DSS_DATA9*/
+ MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | EN | M0)); /*DSS_DATA10*/
+ MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | EN | M0)); /*DSS_DATA11*/
+ MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | EN | M0)); /*DSS_DATA12*/
+ MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | EN | M0)); /*DSS_DATA13*/
+ MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | EN | M0)); /*DSS_DATA14*/
+ MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | EN | M0)); /*DSS_DATA15*/
+ MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | EN | M0)); /*DSS_DATA16*/
+ MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | EN | M0)); /*DSS_DATA17*/
+#if 1
+ /* SOM uses DATA18-23 as they are*/
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | EN | M0)); /*DSS_DATA18*/
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | EN | M0)); /*DSS_DATA19*/
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | EN | M0)); /*DSS_DATA20*/
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | EN | M0)); /*DSS_DATA21*/
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | EN | M0)); /*DSS_DATA22*/
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | EN | M0)); /*DSS_DATA23*/
+#else
+ /* Torpedo uses DATA18-23 as DATA0-5 */
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | EN | M3)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | EN | M3)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | EN | M3)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | EN | M3)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | EN | M3)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | EN | M3)); /*DSS_DATA5*/
+#endif
+#else
+ MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | EN | M0)); /*DSS_DATA0*/
+ MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | EN | M0)); /*DSS_DATA1*/
+ MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | EN | M0)); /*DSS_DATA2*/
+ MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | EN | M0)); /*DSS_DATA3*/
+ MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | EN | M0)); /*DSS_DATA4*/
+ MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | EN | M0)); /*DSS_DATA5*/
+ MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | EN | M0)); /*DSS_DATA6*/
+ MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | EN | M0)); /*DSS_DATA7*/
+ MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | EN | M0)); /*DSS_DATA8*/
+ MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | EN | M0)); /*DSS_DATA9*/
+ MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | EN | M0)); /*DSS_DATA10*/
+ MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | EN | M0)); /*DSS_DATA11*/
+ MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | EN | M0)); /*DSS_DATA12*/
+ MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | EN | M0)); /*DSS_DATA13*/
+ MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | EN | M0)); /*DSS_DATA14*/
+ MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | EN | M0)); /*DSS_DATA15*/
+ MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | EN | M0)); /*DSS_DATA16*/
+ MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | EN | M0)); /*DSS_DATA17*/
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | EN | M0)); /*DSS_DATA18*/
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | EN | M0)); /*DSS_DATA19*/
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | EN | M0)); /*DSS_DATA20*/
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | EN | M0)); /*DSS_DATA21*/
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | EN | M0)); /*DSS_DATA22*/
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | EN | M0)); /*DSS_DATA23*/
+#endif
+#endif
+
+ /*Expansion card */
+ MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)); /*MMC1_CLK*/
+ MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)); /*MMC1_CMD*/
+ MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)); /*MMC1_DAT0*/
+ MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); /*MMC1_DAT1*/
+ MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); /*MMC1_DAT2*/
+ MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); /*MMC1_DAT3*/
+#ifdef SAFE_MODE_PINS_3
+ MUX_VAL(CP(MMC1_DAT4), (IEN | PTD | EN | M7)); /*MMC1_DAT4*/
+ MUX_VAL(CP(MMC1_DAT5), (IEN | PTD | EN | M7)); /*MMC1_DAT5*/
+ MUX_VAL(CP(MMC1_DAT6), (IEN | PTD | EN | M7)); /*MMC1_DAT6*/
+ MUX_VAL(CP(MMC1_DAT7), (IEN | PTD | EN | M7)); /*MMC1_DAT7*/
+ /*Wireless LAN */
+ MUX_VAL(CP(MMC2_CLK), (IEN | PTD | EN | M7)); /*MMC2_CLK*/
+ MUX_VAL(CP(MMC2_CMD), (IEN | PTD | EN | M7)); /*MMC2_CMD*/
+ MUX_VAL(CP(MMC2_DAT0), (IEN | PTD | EN | M7)); /*MMC2_DAT0*/
+ MUX_VAL(CP(MMC2_DAT1), (IEN | PTD | EN | M7)); /*MMC2_DAT1*/
+ MUX_VAL(CP(MMC2_DAT2), (IEN | PTD | EN | M7)); /*MMC2_DAT2*/
+ MUX_VAL(CP(MMC2_DAT3), (IEN | PTD | EN | M7)); /*MMC2_DAT3*/
+ MUX_VAL(CP(MMC2_DAT4), (IEN | PTD | EN | M7)); /*MMC2_DAT4*/
+ MUX_VAL(CP(MMC2_DAT5), (IEN | PTD | EN | M7)); /*MMC2_DAT5*/
+ MUX_VAL(CP(MMC2_DAT6), (IEN | PTD | EN | M7)); /*MMC2_DAT6 */
+ MUX_VAL(CP(MMC2_DAT7), (IEN | PTD | EN | M7)); /*MMC2_DAT7*/
+ /*Bluetooth*/
+ MUX_VAL(CP(MCBSP3_DX), (IEN | PTD | EN | M7)); /*McBSP3_DX*/
+ MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | EN | M7)); /*McBSP3_DR*/
+ MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | EN | M7)); /*McBSP3_CLKX */
+ MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | EN | M7)); /*McBSP3_FSX*/
+ MUX_VAL(CP(UART2_CTS), (IEN | PTD | EN | M7)); /*UART2_CTS*/
+ MUX_VAL(CP(UART2_RTS), (IEN | PTD | EN | M7)); /*UART2_RTS*/
+ MUX_VAL(CP(UART2_TX), (IEN | PTD | EN | M7)); /*UART2_TX*/
+ MUX_VAL(CP(UART2_RX), (IEN | PTD | EN | M7)); /*UART2_RX*/
+#else
+ MUX_VAL(CP(MMC1_DAT4), (IEN | PTU | EN | M0)); /*MMC1_DAT4*/
+ MUX_VAL(CP(MMC1_DAT5), (IEN | PTU | EN | M0)); /*MMC1_DAT5*/
+ MUX_VAL(CP(MMC1_DAT6), (IEN | PTU | EN | M0)); /*MMC1_DAT6*/
+ MUX_VAL(CP(MMC1_DAT7), (IEN | PTU | EN | M0)); /*MMC1_DAT7*/
+ /*Wireless LAN */
+ MUX_VAL(CP(MMC2_CLK), (IEN | PTD | DIS | M0)); /*MMC2_CLK*/
+ MUX_VAL(CP(MMC2_CMD), (IEN | PTU | EN | M0)); /*MMC2_CMD*/
+ MUX_VAL(CP(MMC2_DAT0), (IEN | PTU | EN | M0)); /*MMC2_DAT0*/
+ MUX_VAL(CP(MMC2_DAT1), (IEN | PTU | EN | M0)); /*MMC2_DAT1*/
+ MUX_VAL(CP(MMC2_DAT2), (IEN | PTU | EN | M0)); /*MMC2_DAT2*/
+ MUX_VAL(CP(MMC2_DAT3), (IEN | PTU | EN | M0)); /*MMC2_DAT3*/
+ MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M0)); /*MMC2_DAT4*/
+ MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M0)); /*MMC2_DAT5*/
+ MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M0)); /*MMC2_DAT6 */
+ MUX_VAL(CP(MMC2_DAT7), (IEN | PTU | EN | M0)); /*MMC2_DAT7*/
+ /*Bluetooth*/
+ MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)); /*McBSP3_DX*/
+ MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | DIS | M0)); /*McBSP3_DR*/
+ MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | DIS | M0)); /*McBSP3_CLKX */
+ MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | DIS | M0)); /*McBSP3_FSX*/
+ MUX_VAL(CP(UART2_CTS), (IEN | PTU | EN | M0)); /*UART2_CTS*/
+ MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)); /*UART2_RTS*/
+ MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)); /*UART2_TX*/
+ MUX_VAL(CP(UART2_RX), (IEN | PTD | DIS | M0)); /*UART2_RX*/
+#endif
+ /*Modem Interface */
+ MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); /*UART1_TX*/
+ MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); /*UART1_RTS*/
+ MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); /*UART1_CTS*/
+ MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); /*UART1_RX*/
+#ifdef SAFE_MODE_PINS_4
+ MUX_VAL(CP(MCBSP4_CLKX), (IEN | PTD | EN | M7)); /*GPIO_152*/
+ /* - LCD_INI*/
+ MUX_VAL(CP(MCBSP4_DR), (IEN | PTD | EN | M7)); /*GPIO_153*/
+ /* - LCD_ENVDD */
+#if 1
+#if 1
+ /* SOM doesn't use GPIO_154 for backlight pwr */
+ MUX_VAL(CP(MCBSP4_DX), (IDIS | PTD | EN | M7)); /*GPIO_154*/
+#else
+ MUX_VAL(CP(MCBSP4_DX), (IDIS | PTD | EN | M4)); /*GPIO_154*/
+#endif
+ MUX_VAL(CP(MCBSP4_FSX), (IDIS | PTD | EN | M4)); /*GPIO_155*/
+#else
+ MUX_VAL(CP(MCBSP4_DX), (IEN | PTD | EN | M7)); /*GPIO_154*/
+ /* - LCD_QVGA/nVGA */
+ MUX_VAL(CP(MCBSP4_FSX), (IEN | PTD | EN | M7)); /*GPIO_155*/
+ /* - LCD_RESB */
+#endif
+
+ MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | EN | M7)); /*MCBSP1_CLKR */
+ MUX_VAL(CP(MCBSP1_FSR), (IEN | PTD | EN | M7)); /*MCBSP1_FSR*/
+ MUX_VAL(CP(MCBSP1_DX), (IEN | PTD | EN | M7)); /*MCBSP1_DX*/
+ MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | EN | M7)); /*MCBSP1_DR*/
+ MUX_VAL(CP(MCBSP_CLKS), (IEN | PTD | EN | M7)); /*MCBSP_CLKS */
+ MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | EN | M7)); /*MCBSP1_FSX*/
+ MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | EN | M7)); /*MCBSP1_CLKX */
+ /*Serial Interface*/
+ MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M7)); /*UART3_CTS_*/
+ /* RCTX*/
+ MUX_VAL(CP(UART3_RTS_SD), (IEN | PTD | EN | M7)); /*UART3_RTS_SD */
+ MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | EN | M7)); /*UART3_RX_IRRX*/
+ MUX_VAL(CP(UART3_TX_IRTX), (IEN | PTD | EN | M7)); /*UART3_TX_IRTX*/
+ MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | EN | M7)); /*HSUSB0_CLK*/
+ MUX_VAL(CP(HSUSB0_STP), (IEN | PTD | EN | M7)); /*HSUSB0_STP*/
+ MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | EN | M7)); /*HSUSB0_DIR*/
+ MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | EN | M7)); /*HSUSB0_NXT*/
+ MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | EN | M7)); /*HSUSB0_DATA0*/
+ MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | EN | M7)); /*HSUSB0_DATA1*/
+ MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | EN | M7)); /*HSUSB0_DATA2*/
+ MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | EN | M7)); /*HSUSB0_DATA3*/
+ MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | EN | M7)); /*HSUSB0_DATA4*/
+ MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | EN | M7)); /*HSUSB0_DATA5*/
+ MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | EN | M7)); /*HSUSB0_DATA6*/
+ MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | EN | M7)); /*HSUSB0_DATA7*/
+#else
+ MUX_VAL(CP(MCBSP4_CLKX), (IDIS | PTD | DIS | M4)); /*GPIO_152*/
+ /* - LCD_INI*/
+ MUX_VAL(CP(MCBSP4_DR), (IDIS | PTD | DIS | M4)); /*GPIO_153*/
+ /* - LCD_ENVDD */
+ MUX_VAL(CP(MCBSP4_DX), (IDIS | PTD | DIS | M4)); /*GPIO_154*/
+ /* - LCD_QVGA/nVGA */
+ MUX_VAL(CP(MCBSP4_FSX), (IDIS | PTD | DIS | M4)); /*GPIO_155*/
+ /* - LCD_RESB */
+ MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M0)); /*MCBSP1_CLKR */
+ MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN | M0)); /*MCBSP1_FSR*/
+ MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)); /*MCBSP1_DX*/
+ MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M0)); /*MCBSP1_DR*/
+ MUX_VAL(CP(MCBSP_CLKS), (IEN | PTU | DIS | M0)); /*MCBSP_CLKS */
+ MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | DIS | M0)); /*MCBSP1_FSX*/
+ MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | DIS | M0)); /*MCBSP1_CLKX */
+ /*Serial Interface*/
+ MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); /*UART3_CTS_*/
+ /* RCTX*/
+ MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); /*UART3_RTS_SD */
+ MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); /*UART3_RX_IRRX*/
+ MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); /*UART3_TX_IRTX*/
+ MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); /*HSUSB0_CLK*/
+ MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); /*HSUSB0_STP*/
+ MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); /*HSUSB0_DIR*/
+ MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); /*HSUSB0_NXT*/
+ MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA0*/
+ MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA1*/
+ MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA2*/
+ MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA3*/
+ MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA4*/
+ MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA5*/
+ MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA6*/
+ MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); /*HSUSB0_DATA7*/
+#endif
+ MUX_VAL(CP(I2C1_SCL), (IEN | PTU | EN | M0)); /*I2C1_SCL*/
+ MUX_VAL(CP(I2C1_SDA), (IEN | PTU | EN | M0)); /*I2C1_SDA*/
+#ifdef SAFE_MODE_PINS_5
+ MUX_VAL(CP(I2C2_SCL), (IEN | PTD | EN | M7)); /*I2C2_SCL*/
+ MUX_VAL(CP(I2C2_SDA), (IEN | PTD | EN | M7)); /*I2C2_SDA*/
+ MUX_VAL(CP(I2C3_SCL), (IEN | PTD | EN | M7)); /*I2C3_SCL*/
+ MUX_VAL(CP(I2C3_SDA), (IEN | PTD | EN | M7)); /*I2C3_SDA*/
+ MUX_VAL(CP(I2C4_SCL), (IEN | PTD | EN | M7)); /*I2C4_SCL*/
+ MUX_VAL(CP(I2C4_SDA), (IEN | PTD | EN | M7)); /*I2C4_SDA*/
+#else
+ MUX_VAL(CP(I2C2_SCL), (IEN | PTU | EN | M0)); /*I2C2_SCL*/
+ MUX_VAL(CP(I2C2_SDA), (IEN | PTU | EN | M0)); /*I2C2_SDA*/
+ MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M0)); /*I2C3_SCL*/
+ MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M0)); /*I2C3_SDA*/
+ MUX_VAL(CP(I2C4_SCL), (IEN | PTU | EN | M0)); /*I2C4_SCL*/
+ MUX_VAL(CP(I2C4_SDA), (IEN | PTU | EN | M0)); /*I2C4_SDA*/
+#endif
+ MUX_VAL(CP(HDQ_SIO), (IEN | PTU | EN | M0)); /*HDQ_SIO*/
+#ifdef SAFE_MODE_PINS_5A
+ MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | EN | M7)); /*McSPI1_CLK*/
+ MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | EN | M7)); /*McSPI1_SIMO */
+ MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | EN | M7)); /*McSPI1_SOMI */
+ MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M7)); /*McSPI1_CS0*/
+ MUX_VAL(CP(MCSPI1_CS1), (IEN | PTD | EN | M7)); /*GPIO_175*/
+ /* TS_PEN_IRQ */
+ MUX_VAL(CP(MCSPI1_CS2), (IEN | PTD | EN | M7)); /*GPIO_176*/
+ /* - LAN_INTR*/
+ MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M7)); /*McSPI1_CS3*/
+ MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | EN | M7)); /*McSPI2_CLK*/
+ MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | EN | M7)); /*McSPI2_SIMO*/
+ MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | EN | M7)); /*McSPI2_SOMI*/
+ MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M7)); /*McSPI2_CS0*/
+ MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M7)); /*McSPI2_CS1*/
+#else
+ MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | DIS | M0)); /*McSPI1_CLK*/
+ MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | DIS | M0)); /*McSPI1_SIMO */
+ MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | DIS | M0)); /*McSPI1_SOMI */
+ MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M0)); /*McSPI1_CS0*/
+ MUX_VAL(CP(MCSPI1_CS1), (IEN | PTD | EN | M4)); /*GPIO_175*/
+ /* TS_PEN_IRQ */
+ MUX_VAL(CP(MCSPI1_CS2), (IEN | PTU | DIS | M4)); /*GPIO_176*/
+ /* - LAN_INTR*/
+ MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M0)); /*McSPI1_CS3*/
+ MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | DIS | M0)); /*McSPI2_CLK*/
+ MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | DIS | M0)); /*McSPI2_SIMO*/
+ MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | DIS | M0)); /*McSPI2_SOMI*/
+ MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M0)); /*McSPI2_CS0*/
+ MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M0)); /*McSPI2_CS1*/
+#endif
+ /*Control and debug */
+ MUX_VAL(CP(SYS_32K), (IEN | PTD | DIS | M0)); /*SYS_32K*/
+ MUX_VAL(CP(SYS_CLKREQ), (IEN | PTD | DIS | M0)); /*SYS_CLKREQ*/
+ MUX_VAL(CP(SYS_NIRQ), (IEN | PTU | EN | M0)); /*SYS_nIRQ*/
+#ifdef SAFE_MODE_PINS_6
+ MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | EN | M7)); /*GPIO_2*/
+ /* - PEN_IRQ */
+ MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | EN | M7)); /*GPIO_3 */
+ MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | EN | M7)); /*GPIO_4*/
+ MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | EN | M7)); /*GPIO_5*/
+ MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | EN | M7)); /*GPIO_6*/
+ MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | EN | M7)); /*GPIO_7*/
+#if 1
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTU | DIS | M4)); /*SOM BACKLIGHT PWR*/
+#else
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | EN | M7)); /*GPIO_8*/
+#endif
+#else
+ MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | DIS | M4)); /*GPIO_2*/
+ /* - PEN_IRQ */
+ MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | DIS | M4)); /*GPIO_3 */
+ MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | DIS | M4)); /*GPIO_4*/
+ MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | DIS | M4)); /*GPIO_5*/
+ MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | DIS | M4)); /*GPIO_6*/
+ MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | DIS | M4)); /*GPIO_7*/
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | DIS | M4)); /*GPIO_8*/
+#endif /* - VIO_1V8*/
+ MUX_VAL(CP(SYS_OFF_MODE), (IEN | PTD | DIS | M0)); /*SYS_OFF_MODE*/
+ MUX_VAL(CP(SYS_CLKOUT1), (IEN | PTD | DIS | M0)); /*SYS_CLKOUT1*/
+ MUX_VAL(CP(SYS_CLKOUT2), (IEN | PTU | EN | M0)); /*SYS_CLKOUT2*/
+ MUX_VAL(CP(JTAG_nTRST), (IEN | PTD | DIS | M0)); /*JTAG_nTRST*/
+ MUX_VAL(CP(JTAG_TCK), (IEN | PTD | DIS | M0)); /*JTAG_TCK*/
+ MUX_VAL(CP(JTAG_TMS), (IEN | PTD | DIS | M0)); /*JTAG_TMS*/
+ MUX_VAL(CP(JTAG_TDI), (IEN | PTD | DIS | M0)); /*JTAG_TDI*/
+ MUX_VAL(CP(JTAG_EMU0), (IEN | PTD | DIS | M0)); /*JTAG_EMU0*/
+ MUX_VAL(CP(JTAG_EMU1), (IEN | PTD | DIS | M0)); /*JTAG_EMU1*/
+ MUX_VAL(CP(ETK_CLK_ES2), (IDIS | PTU | EN | M0)); /*ETK_CLK*/
+ MUX_VAL(CP(ETK_CTL_ES2), (IDIS | PTD | DIS | M0)); /*ETK_CTL*/
+ MUX_VAL(CP(ETK_D0_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D0*/
+ MUX_VAL(CP(ETK_D1_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D1*/
+ MUX_VAL(CP(ETK_D2_ES2 ), (IEN | PTD | EN | M0)); /*ETK_D2*/
+ MUX_VAL(CP(ETK_D3_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D3*/
+ MUX_VAL(CP(ETK_D4_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D4*/
+ MUX_VAL(CP(ETK_D5_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D5*/
+ MUX_VAL(CP(ETK_D6_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D6*/
+ MUX_VAL(CP(ETK_D7_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D7*/
+ MUX_VAL(CP(ETK_D8_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D8*/
+ MUX_VAL(CP(ETK_D9_ES2 ), (IEN | PTD | DIS | M0)); /*ETK_D9*/
+ MUX_VAL(CP(ETK_D10_ES2), (IEN | PTD | DIS | M0)); /*ETK_D10*/
+ MUX_VAL(CP(ETK_D11_ES2), (IEN | PTD | DIS | M0)); /*ETK_D11*/
+ MUX_VAL(CP(ETK_D12_ES2), (IEN | PTD | DIS | M0)); /*ETK_D12*/
+ MUX_VAL(CP(ETK_D13_ES2), (IEN | PTD | DIS | M0)); /*ETK_D13*/
+ MUX_VAL(CP(ETK_D14_ES2), (IEN | PTD | DIS | M0)); /*ETK_D14*/
+ MUX_VAL(CP(ETK_D15_ES2), (IEN | PTD | DIS | M0)); /*ETK_D15*/
+ /*Die to Die */
+ MUX_VAL(CP(D2D_MCAD1), (IEN | PTD | EN | M0)); /*d2d_mcad1*/
+ MUX_VAL(CP(D2D_MCAD2), (IEN | PTD | EN | M0)); /*d2d_mcad2*/
+ MUX_VAL(CP(D2D_MCAD3), (IEN | PTD | EN | M0)); /*d2d_mcad3*/
+ MUX_VAL(CP(D2D_MCAD4), (IEN | PTD | EN | M0)); /*d2d_mcad4*/
+ MUX_VAL(CP(D2D_MCAD5), (IEN | PTD | EN | M0)); /*d2d_mcad5*/
+ MUX_VAL(CP(D2D_MCAD6), (IEN | PTD | EN | M0)); /*d2d_mcad6*/
+ MUX_VAL(CP(D2D_MCAD7), (IEN | PTD | EN | M0)); /*d2d_mcad7*/
+ MUX_VAL(CP(D2D_MCAD8), (IEN | PTD | EN | M0)); /*d2d_mcad8*/
+ MUX_VAL(CP(D2D_MCAD9), (IEN | PTD | EN | M0)); /*d2d_mcad9*/
+ MUX_VAL(CP(D2D_MCAD10), (IEN | PTD | EN | M0)); /*d2d_mcad10*/
+ MUX_VAL(CP(D2D_MCAD11), (IEN | PTD | EN | M0)); /*d2d_mcad11*/
+ MUX_VAL(CP(D2D_MCAD12), (IEN | PTD | EN | M0)); /*d2d_mcad12*/
+ MUX_VAL(CP(D2D_MCAD13), (IEN | PTD | EN | M0)); /*d2d_mcad13*/
+ MUX_VAL(CP(D2D_MCAD14), (IEN | PTD | EN | M0)); /*d2d_mcad14*/
+ MUX_VAL(CP(D2D_MCAD15), (IEN | PTD | EN | M0)); /*d2d_mcad15*/
+ MUX_VAL(CP(D2D_MCAD16), (IEN | PTD | EN | M0)); /*d2d_mcad16*/
+ MUX_VAL(CP(D2D_MCAD17), (IEN | PTD | EN | M0)); /*d2d_mcad17*/
+ MUX_VAL(CP(D2D_MCAD18), (IEN | PTD | EN | M0)); /*d2d_mcad18*/
+ MUX_VAL(CP(D2D_MCAD19), (IEN | PTD | EN | M0)); /*d2d_mcad19*/
+ MUX_VAL(CP(D2D_MCAD20), (IEN | PTD | EN | M0)); /*d2d_mcad20*/
+ MUX_VAL(CP(D2D_MCAD21), (IEN | PTD | EN | M0)); /*d2d_mcad21*/
+ MUX_VAL(CP(D2D_MCAD22), (IEN | PTD | EN | M0)); /*d2d_mcad22*/
+ MUX_VAL(CP(D2D_MCAD23), (IEN | PTD | EN | M0)); /*d2d_mcad23*/
+ MUX_VAL(CP(D2D_MCAD24), (IEN | PTD | EN | M0)); /*d2d_mcad24*/
+ MUX_VAL(CP(D2D_MCAD25), (IEN | PTD | EN | M0)); /*d2d_mcad25*/
+ MUX_VAL(CP(D2D_MCAD26), (IEN | PTD | EN | M0)); /*d2d_mcad26*/
+ MUX_VAL(CP(D2D_MCAD27), (IEN | PTD | EN | M0)); /*d2d_mcad27*/
+ MUX_VAL(CP(D2D_MCAD28), (IEN | PTD | EN | M0)); /*d2d_mcad28*/
+ MUX_VAL(CP(D2D_MCAD29), (IEN | PTD | EN | M0)); /*d2d_mcad29*/
+ MUX_VAL(CP(D2D_MCAD30), (IEN | PTD | EN | M0)); /*d2d_mcad30*/
+ MUX_VAL(CP(D2D_MCAD31), (IEN | PTD | EN | M0)); /*d2d_mcad31*/
+ MUX_VAL(CP(D2D_MCAD32), (IEN | PTD | EN | M0)); /*d2d_mcad32*/
+ MUX_VAL(CP(D2D_MCAD33), (IEN | PTD | EN | M0)); /*d2d_mcad33*/
+ MUX_VAL(CP(D2D_MCAD34), (IEN | PTD | EN | M0)); /*d2d_mcad34*/
+ MUX_VAL(CP(D2D_MCAD35), (IEN | PTD | EN | M0)); /*d2d_mcad35*/
+ MUX_VAL(CP(D2D_MCAD36), (IEN | PTD | EN | M0)); /*d2d_mcad36*/
+ MUX_VAL(CP(D2D_CLK26MI), (IEN | PTD | DIS | M0)); /*d2d_clk26mi*/
+ MUX_VAL(CP(D2D_NRESPWRON), (IEN | PTD | EN | M0)); /*d2d_nrespwron*/
+ MUX_VAL(CP(D2D_NRESWARM), (IEN | PTU | EN | M0)); /*d2d_nreswarm */
+ MUX_VAL(CP(D2D_ARM9NIRQ), (IEN | PTD | DIS | M0)); /*d2d_arm9nirq */
+ MUX_VAL(CP(D2D_UMA2P6FIQ), (IEN | PTD | DIS | M0)); /*d2d_uma2p6fiq*/
+ MUX_VAL(CP(D2D_SPINT), (IEN | PTD | EN | M0)); /*d2d_spint*/
+ MUX_VAL(CP(D2D_FRINT), (IEN | PTD | EN | M0)); /*d2d_frint*/
+ MUX_VAL(CP(D2D_DMAREQ0), (IEN | PTD | DIS | M0)); /*d2d_dmareq0*/
+ MUX_VAL(CP(D2D_DMAREQ1), (IEN | PTD | DIS | M0)); /*d2d_dmareq1*/
+ MUX_VAL(CP(D2D_DMAREQ2), (IEN | PTD | DIS | M0)); /*d2d_dmareq2*/
+ MUX_VAL(CP(D2D_DMAREQ3), (IEN | PTD | DIS | M0)); /*d2d_dmareq3*/
+ MUX_VAL(CP(D2D_N3GTRST), (IEN | PTD | DIS | M0)); /*d2d_n3gtrst*/
+ MUX_VAL(CP(D2D_N3GTDI), (IEN | PTD | DIS | M0)); /*d2d_n3gtdi*/
+ MUX_VAL(CP(D2D_N3GTDO), (IEN | PTD | DIS | M0)); /*d2d_n3gtdo*/
+ MUX_VAL(CP(D2D_N3GTMS), (IEN | PTD | DIS | M0)); /*d2d_n3gtms*/
+ MUX_VAL(CP(D2D_N3GTCK), (IEN | PTD | DIS | M0)); /*d2d_n3gtck*/
+ MUX_VAL(CP(D2D_N3GRTCK), (IEN | PTD | DIS | M0)); /*d2d_n3grtck*/
+ MUX_VAL(CP(D2D_MSTDBY), (IEN | PTU | EN | M0)); /*d2d_mstdby*/
+ MUX_VAL(CP(D2D_SWAKEUP), (IEN | PTD | EN | M0)); /*d2d_swakeup*/
+ MUX_VAL(CP(D2D_IDLEREQ), (IEN | PTD | DIS | M0)); /*d2d_idlereq*/
+ MUX_VAL(CP(D2D_IDLEACK), (IEN | PTU | EN | M0)); /*d2d_idleack*/
+ MUX_VAL(CP(D2D_MWRITE), (IEN | PTD | DIS | M0)); /*d2d_mwrite*/
+ MUX_VAL(CP(D2D_SWRITE), (IEN | PTD | DIS | M0)); /*d2d_swrite*/
+ MUX_VAL(CP(D2D_MREAD), (IEN | PTD | DIS | M0)); /*d2d_mread*/
+ MUX_VAL(CP(D2D_SREAD), (IEN | PTD | DIS | M0)); /*d2d_sread*/
+ MUX_VAL(CP(D2D_MBUSFLAG), (IEN | PTD | DIS | M0)); /*d2d_mbusflag*/
+ MUX_VAL(CP(D2D_SBUSFLAG), (IEN | PTD | DIS | M0)); /*d2d_sbusflag*/
+ MUX_VAL(CP(SDRC_CKE0), (IDIS | PTU | EN | M0)); /*sdrc_cke0*/
+ MUX_VAL(CP(SDRC_CKE1), (IDIS | PTD | DIS | M7)); /*sdrc_cke1*/
+}
diff --git a/board/ti/logic/logic.h b/board/ti/logic/logic.h
new file mode 100644
index 0000000000..a880281e0e
--- /dev/null
+++ b/board/ti/logic/logic.h
@@ -0,0 +1,412 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ *
+ * Author:
+ * Peter Barada <peter.barada@logicpd.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 _EVM_H_
+#define _EVM_H_
+
+const omap3_sysinfo sysinfo = {
+ DDR_DISCRETE,
+ "Logic DM37x/OMAP35x reference board",
+#if defined(CONFIG_ENV_IS_IN_ONENAND)
+ "OneNAND",
+#else
+ "NAND",
+#endif
+};
+
+/*
+ * OMAP35x EVM revision
+ * Run time detection of EVM revision is done by reading Ethernet
+ * PHY ID -
+ * GEN_1 = 0x01150000
+ * GEN_2 = 0x92200000
+ */
+enum {
+ OMAP3EVM_BOARD_GEN_1 = 0, /* EVM Rev between A - D */
+ OMAP3EVM_BOARD_GEN_2, /* EVM Rev >= Rev E */
+};
+
+u32 get_omap3_evm_rev(void);
+
+#if defined(CONFIG_CMD_NET)
+static void setup_net_chip(void);
+#endif
+
+/*
+ * IEN - Input Enable
+ * IDIS - Input Disable
+ * PTD - Pull type Down
+ * PTU - Pull type Up
+ * DIS - Pull type selection is inactive
+ * EN - Pull type selection is active
+ * M0 - Mode 0
+ * The commented string gives the final mux configuration for that pin
+ */
+#define MUX_EVM() \
+ /*SDRC*/\
+ MUX_VAL(CP(SDRC_D0), (IEN | PTD | DIS | M0)) /*SDRC_D0*/\
+ MUX_VAL(CP(SDRC_D1), (IEN | PTD | DIS | M0)) /*SDRC_D1*/\
+ MUX_VAL(CP(SDRC_D2), (IEN | PTD | DIS | M0)) /*SDRC_D2*/\
+ MUX_VAL(CP(SDRC_D3), (IEN | PTD | DIS | M0)) /*SDRC_D3*/\
+ MUX_VAL(CP(SDRC_D4), (IEN | PTD | DIS | M0)) /*SDRC_D4*/\
+ MUX_VAL(CP(SDRC_D5), (IEN | PTD | DIS | M0)) /*SDRC_D5*/\
+ MUX_VAL(CP(SDRC_D6), (IEN | PTD | DIS | M0)) /*SDRC_D6*/\
+ MUX_VAL(CP(SDRC_D7), (IEN | PTD | DIS | M0)) /*SDRC_D7*/\
+ MUX_VAL(CP(SDRC_D8), (IEN | PTD | DIS | M0)) /*SDRC_D8*/\
+ MUX_VAL(CP(SDRC_D9), (IEN | PTD | DIS | M0)) /*SDRC_D9*/\
+ MUX_VAL(CP(SDRC_D10), (IEN | PTD | DIS | M0)) /*SDRC_D10*/\
+ MUX_VAL(CP(SDRC_D11), (IEN | PTD | DIS | M0)) /*SDRC_D11*/\
+ MUX_VAL(CP(SDRC_D12), (IEN | PTD | DIS | M0)) /*SDRC_D12*/\
+ MUX_VAL(CP(SDRC_D13), (IEN | PTD | DIS | M0)) /*SDRC_D13*/\
+ MUX_VAL(CP(SDRC_D14), (IEN | PTD | DIS | M0)) /*SDRC_D14*/\
+ MUX_VAL(CP(SDRC_D15), (IEN | PTD | DIS | M0)) /*SDRC_D15*/\
+ MUX_VAL(CP(SDRC_D16), (IEN | PTD | DIS | M0)) /*SDRC_D16*/\
+ MUX_VAL(CP(SDRC_D17), (IEN | PTD | DIS | M0)) /*SDRC_D17*/\
+ MUX_VAL(CP(SDRC_D18), (IEN | PTD | DIS | M0)) /*SDRC_D18*/\
+ MUX_VAL(CP(SDRC_D19), (IEN | PTD | DIS | M0)) /*SDRC_D19*/\
+ MUX_VAL(CP(SDRC_D20), (IEN | PTD | DIS | M0)) /*SDRC_D20*/\
+ MUX_VAL(CP(SDRC_D21), (IEN | PTD | DIS | M0)) /*SDRC_D21*/\
+ MUX_VAL(CP(SDRC_D22), (IEN | PTD | DIS | M0)) /*SDRC_D22*/\
+ MUX_VAL(CP(SDRC_D23), (IEN | PTD | DIS | M0)) /*SDRC_D23*/\
+ MUX_VAL(CP(SDRC_D24), (IEN | PTD | DIS | M0)) /*SDRC_D24*/\
+ MUX_VAL(CP(SDRC_D25), (IEN | PTD | DIS | M0)) /*SDRC_D25*/\
+ MUX_VAL(CP(SDRC_D26), (IEN | PTD | DIS | M0)) /*SDRC_D26*/\
+ MUX_VAL(CP(SDRC_D27), (IEN | PTD | DIS | M0)) /*SDRC_D27*/\
+ MUX_VAL(CP(SDRC_D28), (IEN | PTD | DIS | M0)) /*SDRC_D28*/\
+ MUX_VAL(CP(SDRC_D29), (IEN | PTD | DIS | M0)) /*SDRC_D29*/\
+ MUX_VAL(CP(SDRC_D30), (IEN | PTD | DIS | M0)) /*SDRC_D30*/\
+ MUX_VAL(CP(SDRC_D31), (IEN | PTD | DIS | M0)) /*SDRC_D31*/\
+ MUX_VAL(CP(SDRC_CLK), (IEN | PTD | DIS | M0)) /*SDRC_CLK*/\
+ MUX_VAL(CP(SDRC_DQS0), (IEN | PTD | DIS | M0)) /*SDRC_DQS0*/\
+ MUX_VAL(CP(SDRC_DQS1), (IEN | PTD | DIS | M0)) /*SDRC_DQS1*/\
+ MUX_VAL(CP(SDRC_DQS2), (IEN | PTD | DIS | M0)) /*SDRC_DQS2*/\
+ MUX_VAL(CP(SDRC_DQS3), (IEN | PTD | DIS | M0)) /*SDRC_DQS3*/\
+ /*GPMC*/\
+ MUX_VAL(CP(GPMC_A1), (IDIS | PTU | EN | M0)) /*GPMC_A1*/\
+ MUX_VAL(CP(GPMC_A2), (IDIS | PTU | EN | M0)) /*GPMC_A2*/\
+ MUX_VAL(CP(GPMC_A3), (IDIS | PTU | EN | M0)) /*GPMC_A3*/\
+ MUX_VAL(CP(GPMC_A4), (IDIS | PTU | EN | M0)) /*GPMC_A4*/\
+ MUX_VAL(CP(GPMC_A5), (IDIS | PTU | EN | M0)) /*GPMC_A5*/\
+ MUX_VAL(CP(GPMC_A6), (IDIS | PTU | EN | M0)) /*GPMC_A6*/\
+ MUX_VAL(CP(GPMC_A7), (IDIS | PTU | EN | M0)) /*GPMC_A7*/\
+ MUX_VAL(CP(GPMC_A8), (IDIS | PTU | EN | M0)) /*GPMC_A8*/\
+ MUX_VAL(CP(GPMC_A9), (IDIS | PTU | EN | M0)) /*GPMC_A9*/\
+ MUX_VAL(CP(GPMC_A10), (IDIS | PTU | EN | M0)) /*GPMC_A10*/\
+ MUX_VAL(CP(GPMC_D0), (IEN | PTU | EN | M0)) /*GPMC_D0*/\
+ MUX_VAL(CP(GPMC_D1), (IEN | PTU | EN | M0)) /*GPMC_D1*/\
+ MUX_VAL(CP(GPMC_D2), (IEN | PTU | EN | M0)) /*GPMC_D2*/\
+ MUX_VAL(CP(GPMC_D3), (IEN | PTU | EN | M0)) /*GPMC_D3*/\
+ MUX_VAL(CP(GPMC_D4), (IEN | PTU | EN | M0)) /*GPMC_D4*/\
+ MUX_VAL(CP(GPMC_D5), (IEN | PTU | EN | M0)) /*GPMC_D5*/\
+ MUX_VAL(CP(GPMC_D6), (IEN | PTU | EN | M0)) /*GPMC_D6*/\
+ MUX_VAL(CP(GPMC_D7), (IEN | PTU | EN | M0)) /*GPMC_D7*/\
+ MUX_VAL(CP(GPMC_D8), (IEN | PTU | EN | M0)) /*GPMC_D8*/\
+ MUX_VAL(CP(GPMC_D9), (IEN | PTU | EN | M0)) /*GPMC_D9*/\
+ MUX_VAL(CP(GPMC_D10), (IEN | PTU | EN | M0)) /*GPMC_D10*/\
+ MUX_VAL(CP(GPMC_D11), (IEN | PTU | EN | M0)) /*GPMC_D11*/\
+ MUX_VAL(CP(GPMC_D12), (IEN | PTU | EN | M0)) /*GPMC_D12*/\
+ MUX_VAL(CP(GPMC_D13), (IEN | PTU | EN | M0)) /*GPMC_D13*/\
+ MUX_VAL(CP(GPMC_D14), (IEN | PTU | EN | M0)) /*GPMC_D14*/\
+ MUX_VAL(CP(GPMC_D15), (IEN | PTU | EN | M0)) /*GPMC_D15*/\
+ MUX_VAL(CP(GPMC_NCS0), (IDIS | PTU | EN | M0)) /*GPMC_nCS0*/\
+ MUX_VAL(CP(GPMC_NCS1), (IDIS | PTU | EN | M0)) /*GPMC_nCS1*/\
+ MUX_VAL(CP(GPMC_NCS2), (IDIS | PTU | EN | M0)) /*GPMC_nCS2*/\
+ MUX_VAL(CP(GPMC_NCS3), (IDIS | PTU | EN | M0)) /*GPMC_nCS3*/\
+ MUX_VAL(CP(GPMC_NCS4), (IEN | PTU | EN | M0)) /*GPMC_nCS4*/\
+ MUX_VAL(CP(GPMC_NCS5), (IDIS | PTU | EN | M0)) /*GPMC_nCS5*/\
+ MUX_VAL(CP(GPMC_NCS6), (IEN | PTD | DIS | M0)) /*GPMC_nCS6*/\
+ MUX_VAL(CP(GPMC_NCS7), (IEN | PTU | EN | M0)) /*GPMC_nCS7*/\
+ MUX_VAL(CP(GPMC_CLK), (IDIS | PTU | EN | M0)) /*GPMC_CLK*/\
+ MUX_VAL(CP(GPMC_NADV_ALE), (IDIS | PTD | DIS | M0)) /*GPMC_nADV_ALE*/\
+ MUX_VAL(CP(GPMC_NOE), (IDIS | PTD | DIS | M0)) /*GPMC_nOE*/\
+ MUX_VAL(CP(GPMC_NWE), (IDIS | PTD | DIS | M0)) /*GPMC_nWE*/\
+ MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTU | EN | M0)) /*GPMC_nBE0_CLE*/\
+ MUX_VAL(CP(GPMC_NBE1), (IEN | PTU | EN | M0)) /*GPMC_nBE1*/\
+ MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)) /*GPMC_nWP*/\
+ MUX_VAL(CP(GPMC_WAIT0), (IEN | PTU | EN | M0)) /*GPMC_WAIT0*/\
+ MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)) /*GPMC_WAIT1*/\
+ MUX_VAL(CP(GPMC_WAIT2), (IEN | PTU | EN | M4)) /*GPIO_64*/\
+ /* - ETH_nRESET*/\
+ MUX_VAL(CP(GPMC_WAIT3), (IEN | PTU | EN | M0)) /*GPMC_WAIT3*/\
+ /*DSS*/\
+ MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | DIS | M0)) /*DSS_PCLK*/\
+ MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | DIS | M0)) /*DSS_HSYNC*/\
+ MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | DIS | M0)) /*DSS_VSYNC*/\
+ MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | DIS | M0)) /*DSS_ACBIAS*/\
+ MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | DIS | M0)) /*DSS_DATA0*/\
+ MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | DIS | M0)) /*DSS_DATA1*/\
+ MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | DIS | M0)) /*DSS_DATA2*/\
+ MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | DIS | M0)) /*DSS_DATA3*/\
+ MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | DIS | M0)) /*DSS_DATA4*/\
+ MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | DIS | M0)) /*DSS_DATA5*/\
+ MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | DIS | M0)) /*DSS_DATA6*/\
+ MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | DIS | M0)) /*DSS_DATA7*/\
+ MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | DIS | M0)) /*DSS_DATA8*/\
+ MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | DIS | M0)) /*DSS_DATA9*/\
+ MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | DIS | M0)) /*DSS_DATA10*/\
+ MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | DIS | M0)) /*DSS_DATA11*/\
+ MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | DIS | M0)) /*DSS_DATA12*/\
+ MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | DIS | M0)) /*DSS_DATA13*/\
+ MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | DIS | M0)) /*DSS_DATA14*/\
+ MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | DIS | M0)) /*DSS_DATA15*/\
+ MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | DIS | M0)) /*DSS_DATA16*/\
+ MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | DIS | M0)) /*DSS_DATA17*/\
+ MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | DIS | M0)) /*DSS_DATA18*/\
+ MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | DIS | M0)) /*DSS_DATA19*/\
+ MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | DIS | M0)) /*DSS_DATA20*/\
+ MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | DIS | M0)) /*DSS_DATA21*/\
+ MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | DIS | M0)) /*DSS_DATA22*/\
+ MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | DIS | M0)) /*DSS_DATA23*/\
+ /*CAMERA*/\
+ MUX_VAL(CP(CAM_HS), (IEN | PTU | EN | M0)) /*CAM_HS */\
+ MUX_VAL(CP(CAM_VS), (IEN | PTU | EN | M0)) /*CAM_VS */\
+ MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | DIS | M0)) /*CAM_XCLKA*/\
+ MUX_VAL(CP(CAM_PCLK), (IEN | PTU | EN | M0)) /*CAM_PCLK*/\
+ MUX_VAL(CP(CAM_FLD), (IDIS | PTD | DIS | M4)) /*GPIO_98*/\
+ /* - CAM_RESET*/\
+ MUX_VAL(CP(CAM_D0), (IEN | PTD | DIS | M0)) /*CAM_D0*/\
+ MUX_VAL(CP(CAM_D1), (IEN | PTD | DIS | M0)) /*CAM_D1*/\
+ MUX_VAL(CP(CAM_D2), (IEN | PTD | DIS | M0)) /*CAM_D2*/\
+ MUX_VAL(CP(CAM_D3), (IEN | PTD | DIS | M0)) /*CAM_D3*/\
+ MUX_VAL(CP(CAM_D4), (IEN | PTD | DIS | M0)) /*CAM_D4*/\
+ MUX_VAL(CP(CAM_D5), (IEN | PTD | DIS | M0)) /*CAM_D5*/\
+ MUX_VAL(CP(CAM_D6), (IEN | PTD | DIS | M0)) /*CAM_D6*/\
+ MUX_VAL(CP(CAM_D7), (IEN | PTD | DIS | M0)) /*CAM_D7*/\
+ MUX_VAL(CP(CAM_D8), (IEN | PTD | DIS | M0)) /*CAM_D8*/\
+ MUX_VAL(CP(CAM_D9), (IEN | PTD | DIS | M0)) /*CAM_D9*/\
+ MUX_VAL(CP(CAM_D10), (IEN | PTD | DIS | M0)) /*CAM_D10*/\
+ MUX_VAL(CP(CAM_D11), (IEN | PTD | DIS | M0)) /*CAM_D11*/\
+ MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | DIS | M0)) /*CAM_XCLKB*/\
+ MUX_VAL(CP(CAM_WEN), (IEN | PTD | DIS | M4)) /*GPIO_167*/\
+ MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | DIS | M0)) /*CAM_STROBE*/\
+ MUX_VAL(CP(CSI2_DX0), (IEN | PTD | DIS | M0)) /*CSI2_DX0*/\
+ MUX_VAL(CP(CSI2_DY0), (IEN | PTD | DIS | M0)) /*CSI2_DY0*/\
+ MUX_VAL(CP(CSI2_DX1), (IEN | PTD | DIS | M0)) /*CSI2_DX1*/\
+ MUX_VAL(CP(CSI2_DY1), (IEN | PTD | DIS | M0)) /*CSI2_DY1*/\
+ /*Audio Interface */\
+ MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | DIS | M0)) /*McBSP2_FSX*/\
+ MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | DIS | M0)) /*McBSP2_CLKX*/\
+ MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | DIS | M0)) /*McBSP2_DR*/\
+ MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | DIS | M0)) /*McBSP2_DX*/\
+ /*Expansion card */\
+ MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)) /*MMC1_CLK*/\
+ MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)) /*MMC1_CMD*/\
+ MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)) /*MMC1_DAT0*/\
+ MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)) /*MMC1_DAT1*/\
+ MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)) /*MMC1_DAT2*/\
+ MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)) /*MMC1_DAT3*/\
+ MUX_VAL(CP(MMC1_DAT4), (IEN | PTU | EN | M0)) /*MMC1_DAT4*/\
+ MUX_VAL(CP(MMC1_DAT5), (IEN | PTU | EN | M0)) /*MMC1_DAT5*/\
+ MUX_VAL(CP(MMC1_DAT6), (IEN | PTU | EN | M0)) /*MMC1_DAT6*/\
+ MUX_VAL(CP(MMC1_DAT7), (IEN | PTU | EN | M0)) /*MMC1_DAT7*/\
+ /*Wireless LAN */\
+ MUX_VAL(CP(MMC2_CLK), (IEN | PTD | DIS | M0)) /*MMC2_CLK*/\
+ MUX_VAL(CP(MMC2_CMD), (IEN | PTU | EN | M0)) /*MMC2_CMD*/\
+ MUX_VAL(CP(MMC2_DAT0), (IEN | PTU | EN | M0)) /*MMC2_DAT0*/\
+ MUX_VAL(CP(MMC2_DAT1), (IEN | PTU | EN | M0)) /*MMC2_DAT1*/\
+ MUX_VAL(CP(MMC2_DAT2), (IEN | PTU | EN | M0)) /*MMC2_DAT2*/\
+ MUX_VAL(CP(MMC2_DAT3), (IEN | PTU | EN | M0)) /*MMC2_DAT3*/\
+ MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M0)) /*MMC2_DAT4*/\
+ MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M0)) /*MMC2_DAT5*/\
+ MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M0)) /*MMC2_DAT6 */\
+ MUX_VAL(CP(MMC2_DAT7), (IEN | PTU | EN | M0)) /*MMC2_DAT7*/\
+ /*Bluetooth*/\
+ MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)) /*McBSP3_DX*/\
+ MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | DIS | M0)) /*McBSP3_DR*/\
+ MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | DIS | M0)) /*McBSP3_CLKX */\
+ MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | DIS | M0)) /*McBSP3_FSX*/\
+ MUX_VAL(CP(UART2_CTS), (IEN | PTU | EN | M0)) /*UART2_CTS*/\
+ MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)) /*UART2_RTS*/\
+ MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)) /*UART2_TX*/\
+ MUX_VAL(CP(UART2_RX), (IEN | PTD | DIS | M0)) /*UART2_RX*/\
+ /*Modem Interface */\
+ MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)) /*UART1_TX*/\
+ MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)) /*UART1_RTS*/\
+ MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)) /*UART1_CTS*/\
+ MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)) /*UART1_RX*/\
+ MUX_VAL(CP(MCBSP4_CLKX), (IDIS | PTD | DIS | M4)) /*GPIO_152*/\
+ /* - LCD_INI*/\
+ MUX_VAL(CP(MCBSP4_DR), (IDIS | PTD | DIS | M4)) /*GPIO_153*/\
+ /* - LCD_ENVDD */\
+ MUX_VAL(CP(MCBSP4_DX), (IDIS | PTD | DIS | M4)) /*GPIO_154*/\
+ /* - LCD_QVGA/nVGA */\
+ MUX_VAL(CP(MCBSP4_FSX), (IDIS | PTD | DIS | M4)) /*GPIO_155*/\
+ /* - LCD_RESB */\
+ MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M0)) /*MCBSP1_CLKR */\
+ MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN | M0)) /*MCBSP1_FSR*/\
+ MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)) /*MCBSP1_DX*/\
+ MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M0)) /*MCBSP1_DR*/\
+ MUX_VAL(CP(MCBSP_CLKS), (IEN | PTU | DIS | M0)) /*MCBSP_CLKS */\
+ MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | DIS | M0)) /*MCBSP1_FSX*/\
+ MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | DIS | M0)) /*MCBSP1_CLKX */\
+ /*Serial Interface*/\
+ MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)) /*UART3_CTS_*/\
+ /* RCTX*/\
+ MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)) /*UART3_RTS_SD */\
+ MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)) /*UART3_RX_IRRX*/\
+ MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)) /*UART3_TX_IRTX*/\
+ MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)) /*HSUSB0_CLK*/\
+ MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)) /*HSUSB0_STP*/\
+ MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)) /*HSUSB0_DIR*/\
+ MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)) /*HSUSB0_NXT*/\
+ MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA0*/\
+ MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA1*/\
+ MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA2*/\
+ MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA3*/\
+ MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA4*/\
+ MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA5*/\
+ MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA6*/\
+ MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)) /*HSUSB0_DATA7*/\
+ MUX_VAL(CP(I2C1_SCL), (IEN | PTU | EN | M0)) /*I2C1_SCL*/\
+ MUX_VAL(CP(I2C1_SDA), (IEN | PTU | EN | M0)) /*I2C1_SDA*/\
+ MUX_VAL(CP(I2C2_SCL), (IEN | PTU | EN | M0)) /*I2C2_SCL*/\
+ MUX_VAL(CP(I2C2_SDA), (IEN | PTU | EN | M0)) /*I2C2_SDA*/\
+ MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M0)) /*I2C3_SCL*/\
+ MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M0)) /*I2C3_SDA*/\
+ MUX_VAL(CP(I2C4_SCL), (IEN | PTU | EN | M0)) /*I2C4_SCL*/\
+ MUX_VAL(CP(I2C4_SDA), (IEN | PTU | EN | M0)) /*I2C4_SDA*/\
+ MUX_VAL(CP(HDQ_SIO), (IEN | PTU | EN | M0)) /*HDQ_SIO*/\
+ MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | DIS | M0)) /*McSPI1_CLK*/\
+ MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | DIS | M0)) /*McSPI1_SIMO */\
+ MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | DIS | M0)) /*McSPI1_SOMI */\
+ MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M0)) /*McSPI1_CS0*/\
+ MUX_VAL(CP(MCSPI1_CS1), (IEN | PTD | EN | M4)) /*GPIO_175*/\
+ /* TS_PEN_IRQ */\
+ MUX_VAL(CP(MCSPI1_CS2), (IEN | PTU | DIS | M4)) /*GPIO_176*/\
+ /* - LAN_INTR*/\
+ MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M0)) /*McSPI1_CS3*/\
+ MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | DIS | M0)) /*McSPI2_CLK*/\
+ MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | DIS | M0)) /*McSPI2_SIMO*/\
+ MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | DIS | M0)) /*McSPI2_SOMI*/\
+ MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M0)) /*McSPI2_CS0*/\
+ MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M0)) /*McSPI2_CS1*/\
+ /*Control and debug */\
+ MUX_VAL(CP(SYS_32K), (IEN | PTD | DIS | M0)) /*SYS_32K*/\
+ MUX_VAL(CP(SYS_CLKREQ), (IEN | PTD | DIS | M0)) /*SYS_CLKREQ*/\
+ MUX_VAL(CP(SYS_NIRQ), (IEN | PTU | EN | M0)) /*SYS_nIRQ*/\
+ MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | DIS | M4)) /*GPIO_2*/\
+ /* - PEN_IRQ */\
+ MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | DIS | M4)) /*GPIO_3 */\
+ MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | DIS | M4)) /*GPIO_4*/\
+ MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | DIS | M4)) /*GPIO_5*/\
+ MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | DIS | M4)) /*GPIO_6*/\
+ MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | DIS | M4)) /*GPIO_7*/\
+ MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | DIS | M4)) /*GPIO_8*/\
+ /* - VIO_1V8*/\
+ MUX_VAL(CP(SYS_OFF_MODE), (IEN | PTD | DIS | M0)) /*SYS_OFF_MODE*/\
+ MUX_VAL(CP(SYS_CLKOUT1), (IEN | PTD | DIS | M0)) /*SYS_CLKOUT1*/\
+ MUX_VAL(CP(SYS_CLKOUT2), (IEN | PTU | EN | M0)) /*SYS_CLKOUT2*/\
+ MUX_VAL(CP(JTAG_nTRST), (IEN | PTD | DIS | M0)) /*JTAG_nTRST*/\
+ MUX_VAL(CP(JTAG_TCK), (IEN | PTD | DIS | M0)) /*JTAG_TCK*/\
+ MUX_VAL(CP(JTAG_TMS), (IEN | PTD | DIS | M0)) /*JTAG_TMS*/\
+ MUX_VAL(CP(JTAG_TDI), (IEN | PTD | DIS | M0)) /*JTAG_TDI*/\
+ MUX_VAL(CP(JTAG_EMU0), (IEN | PTD | DIS | M0)) /*JTAG_EMU0*/\
+ MUX_VAL(CP(JTAG_EMU1), (IEN | PTD | DIS | M0)) /*JTAG_EMU1*/\
+ MUX_VAL(CP(ETK_CLK_ES2), (IDIS | PTU | EN | M0)) /*ETK_CLK*/\
+ MUX_VAL(CP(ETK_CTL_ES2), (IDIS | PTD | DIS | M0)) /*ETK_CTL*/\
+ MUX_VAL(CP(ETK_D0_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D0*/\
+ MUX_VAL(CP(ETK_D1_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D1*/\
+ MUX_VAL(CP(ETK_D2_ES2 ), (IEN | PTD | EN | M0)) /*ETK_D2*/\
+ MUX_VAL(CP(ETK_D3_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D3*/\
+ MUX_VAL(CP(ETK_D4_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D4*/\
+ MUX_VAL(CP(ETK_D5_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D5*/\
+ MUX_VAL(CP(ETK_D6_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D6*/\
+ MUX_VAL(CP(ETK_D7_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D7*/\
+ MUX_VAL(CP(ETK_D8_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D8*/\
+ MUX_VAL(CP(ETK_D9_ES2 ), (IEN | PTD | DIS | M0)) /*ETK_D9*/\
+ MUX_VAL(CP(ETK_D10_ES2), (IEN | PTD | DIS | M0)) /*ETK_D10*/\
+ MUX_VAL(CP(ETK_D11_ES2), (IEN | PTD | DIS | M0)) /*ETK_D11*/\
+ MUX_VAL(CP(ETK_D12_ES2), (IEN | PTD | DIS | M0)) /*ETK_D12*/\
+ MUX_VAL(CP(ETK_D13_ES2), (IEN | PTD | DIS | M0)) /*ETK_D13*/\
+ MUX_VAL(CP(ETK_D14_ES2), (IEN | PTD | DIS | M0)) /*ETK_D14*/\
+ MUX_VAL(CP(ETK_D15_ES2), (IEN | PTD | DIS | M0)) /*ETK_D15*/\
+ /*Die to Die */\
+ MUX_VAL(CP(D2D_MCAD1), (IEN | PTD | EN | M0)) /*d2d_mcad1*/\
+ MUX_VAL(CP(D2D_MCAD2), (IEN | PTD | EN | M0)) /*d2d_mcad2*/\
+ MUX_VAL(CP(D2D_MCAD3), (IEN | PTD | EN | M0)) /*d2d_mcad3*/\
+ MUX_VAL(CP(D2D_MCAD4), (IEN | PTD | EN | M0)) /*d2d_mcad4*/\
+ MUX_VAL(CP(D2D_MCAD5), (IEN | PTD | EN | M0)) /*d2d_mcad5*/\
+ MUX_VAL(CP(D2D_MCAD6), (IEN | PTD | EN | M0)) /*d2d_mcad6*/\
+ MUX_VAL(CP(D2D_MCAD7), (IEN | PTD | EN | M0)) /*d2d_mcad7*/\
+ MUX_VAL(CP(D2D_MCAD8), (IEN | PTD | EN | M0)) /*d2d_mcad8*/\
+ MUX_VAL(CP(D2D_MCAD9), (IEN | PTD | EN | M0)) /*d2d_mcad9*/\
+ MUX_VAL(CP(D2D_MCAD10), (IEN | PTD | EN | M0)) /*d2d_mcad10*/\
+ MUX_VAL(CP(D2D_MCAD11), (IEN | PTD | EN | M0)) /*d2d_mcad11*/\
+ MUX_VAL(CP(D2D_MCAD12), (IEN | PTD | EN | M0)) /*d2d_mcad12*/\
+ MUX_VAL(CP(D2D_MCAD13), (IEN | PTD | EN | M0)) /*d2d_mcad13*/\
+ MUX_VAL(CP(D2D_MCAD14), (IEN | PTD | EN | M0)) /*d2d_mcad14*/\
+ MUX_VAL(CP(D2D_MCAD15), (IEN | PTD | EN | M0)) /*d2d_mcad15*/\
+ MUX_VAL(CP(D2D_MCAD16), (IEN | PTD | EN | M0)) /*d2d_mcad16*/\
+ MUX_VAL(CP(D2D_MCAD17), (IEN | PTD | EN | M0)) /*d2d_mcad17*/\
+ MUX_VAL(CP(D2D_MCAD18), (IEN | PTD | EN | M0)) /*d2d_mcad18*/\
+ MUX_VAL(CP(D2D_MCAD19), (IEN | PTD | EN | M0)) /*d2d_mcad19*/\
+ MUX_VAL(CP(D2D_MCAD20), (IEN | PTD | EN | M0)) /*d2d_mcad20*/\
+ MUX_VAL(CP(D2D_MCAD21), (IEN | PTD | EN | M0)) /*d2d_mcad21*/\
+ MUX_VAL(CP(D2D_MCAD22), (IEN | PTD | EN | M0)) /*d2d_mcad22*/\
+ MUX_VAL(CP(D2D_MCAD23), (IEN | PTD | EN | M0)) /*d2d_mcad23*/\
+ MUX_VAL(CP(D2D_MCAD24), (IEN | PTD | EN | M0)) /*d2d_mcad24*/\
+ MUX_VAL(CP(D2D_MCAD25), (IEN | PTD | EN | M0)) /*d2d_mcad25*/\
+ MUX_VAL(CP(D2D_MCAD26), (IEN | PTD | EN | M0)) /*d2d_mcad26*/\
+ MUX_VAL(CP(D2D_MCAD27), (IEN | PTD | EN | M0)) /*d2d_mcad27*/\
+ MUX_VAL(CP(D2D_MCAD28), (IEN | PTD | EN | M0)) /*d2d_mcad28*/\
+ MUX_VAL(CP(D2D_MCAD29), (IEN | PTD | EN | M0)) /*d2d_mcad29*/\
+ MUX_VAL(CP(D2D_MCAD30), (IEN | PTD | EN | M0)) /*d2d_mcad30*/\
+ MUX_VAL(CP(D2D_MCAD31), (IEN | PTD | EN | M0)) /*d2d_mcad31*/\
+ MUX_VAL(CP(D2D_MCAD32), (IEN | PTD | EN | M0)) /*d2d_mcad32*/\
+ MUX_VAL(CP(D2D_MCAD33), (IEN | PTD | EN | M0)) /*d2d_mcad33*/\
+ MUX_VAL(CP(D2D_MCAD34), (IEN | PTD | EN | M0)) /*d2d_mcad34*/\
+ MUX_VAL(CP(D2D_MCAD35), (IEN | PTD | EN | M0)) /*d2d_mcad35*/\
+ MUX_VAL(CP(D2D_MCAD36), (IEN | PTD | EN | M0)) /*d2d_mcad36*/\
+ MUX_VAL(CP(D2D_CLK26MI), (IEN | PTD | DIS | M0)) /*d2d_clk26mi*/\
+ MUX_VAL(CP(D2D_NRESPWRON), (IEN | PTD | EN | M0)) /*d2d_nrespwron*/\
+ MUX_VAL(CP(D2D_NRESWARM), (IEN | PTU | EN | M0)) /*d2d_nreswarm */\
+ MUX_VAL(CP(D2D_ARM9NIRQ), (IEN | PTD | DIS | M0)) /*d2d_arm9nirq */\
+ MUX_VAL(CP(D2D_UMA2P6FIQ), (IEN | PTD | DIS | M0)) /*d2d_uma2p6fiq*/\
+ MUX_VAL(CP(D2D_SPINT), (IEN | PTD | EN | M0)) /*d2d_spint*/\
+ MUX_VAL(CP(D2D_FRINT), (IEN | PTD | EN | M0)) /*d2d_frint*/\
+ MUX_VAL(CP(D2D_DMAREQ0), (IEN | PTD | DIS | M0)) /*d2d_dmareq0*/\
+ MUX_VAL(CP(D2D_DMAREQ1), (IEN | PTD | DIS | M0)) /*d2d_dmareq1*/\
+ MUX_VAL(CP(D2D_DMAREQ2), (IEN | PTD | DIS | M0)) /*d2d_dmareq2*/\
+ MUX_VAL(CP(D2D_DMAREQ3), (IEN | PTD | DIS | M0)) /*d2d_dmareq3*/\
+ MUX_VAL(CP(D2D_N3GTRST), (IEN | PTD | DIS | M0)) /*d2d_n3gtrst*/\
+ MUX_VAL(CP(D2D_N3GTDI), (IEN | PTD | DIS | M0)) /*d2d_n3gtdi*/\
+ MUX_VAL(CP(D2D_N3GTDO), (IEN | PTD | DIS | M0)) /*d2d_n3gtdo*/\
+ MUX_VAL(CP(D2D_N3GTMS), (IEN | PTD | DIS | M0)) /*d2d_n3gtms*/\
+ MUX_VAL(CP(D2D_N3GTCK), (IEN | PTD | DIS | M0)) /*d2d_n3gtck*/\
+ MUX_VAL(CP(D2D_N3GRTCK), (IEN | PTD | DIS | M0)) /*d2d_n3grtck*/\
+ MUX_VAL(CP(D2D_MSTDBY), (IEN | PTU | EN | M0)) /*d2d_mstdby*/\
+ MUX_VAL(CP(D2D_SWAKEUP), (IEN | PTD | EN | M0)) /*d2d_swakeup*/\
+ MUX_VAL(CP(D2D_IDLEREQ), (IEN | PTD | DIS | M0)) /*d2d_idlereq*/\
+ MUX_VAL(CP(D2D_IDLEACK), (IEN | PTU | EN | M0)) /*d2d_idleack*/\
+ MUX_VAL(CP(D2D_MWRITE), (IEN | PTD | DIS | M0)) /*d2d_mwrite*/\
+ MUX_VAL(CP(D2D_SWRITE), (IEN | PTD | DIS | M0)) /*d2d_swrite*/\
+ MUX_VAL(CP(D2D_MREAD), (IEN | PTD | DIS | M0)) /*d2d_mread*/\
+ MUX_VAL(CP(D2D_SREAD), (IEN | PTD | DIS | M0)) /*d2d_sread*/\
+ MUX_VAL(CP(D2D_MBUSFLAG), (IEN | PTD | DIS | M0)) /*d2d_mbusflag*/\
+ MUX_VAL(CP(D2D_SBUSFLAG), (IEN | PTD | DIS | M0)) /*d2d_sbusflag*/\
+ MUX_VAL(CP(SDRC_CKE0), (IDIS | PTU | EN | M0)) /*sdrc_cke0*/\
+ MUX_VAL(CP(SDRC_CKE1), (IDIS | PTD | DIS | M7)) /*sdrc_cke1*/\
+
+#endif
diff --git a/board/ti/logic/prod-id/crc-15.c b/board/ti/logic/prod-id/crc-15.c
new file mode 100644
index 0000000000..344fdaad9e
--- /dev/null
+++ b/board/ti/logic/prod-id/crc-15.c
@@ -0,0 +1,31 @@
+#include "crc-15.h"
+
+/*
+ * Calculate a CRC-15 of a data buffer passed in
+ */
+
+void crc_15_step(unsigned short *crc, unsigned char byte)
+{
+ int i;
+ unsigned short crcnext;
+
+ for (i=0; i<7; ++i) {
+ crcnext = (byte & 1) ^ (*crc>>14);
+ *crc = (*crc << 1) & 0x7fff;
+ if (crcnext)
+ *crc ^= 0x4599;
+ byte >>= 1;
+ }
+}
+
+unsigned short crc_15(void *buf, int len)
+{
+ unsigned char *p = buf;
+ unsigned short xsum = 0;
+ int i;
+
+ for (i=0; i<len; ++i) {
+ crc_15_step(&xsum, p[i]);
+ }
+ return xsum;
+}
diff --git a/board/ti/logic/prod-id/crc-15.h b/board/ti/logic/prod-id/crc-15.h
new file mode 100644
index 0000000000..15a891e387
--- /dev/null
+++ b/board/ti/logic/prod-id/crc-15.h
@@ -0,0 +1,3 @@
+extern unsigned short crc_15(void *byte, int len);
+
+extern void crc_15_step(unsigned short *crc, unsigned char byte);
diff --git a/board/ti/logic/prod-id/debug.h b/board/ti/logic/prod-id/debug.h
new file mode 100644
index 0000000000..38dc9c3b96
--- /dev/null
+++ b/board/ti/logic/prod-id/debug.h
@@ -0,0 +1,12 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINTF(fmt, args...) printf(fmt, ## args)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#endif
diff --git a/board/ti/logic/prod-id/dict.c b/board/ti/logic/prod-id/dict.c
new file mode 100644
index 0000000000..dde08790d4
--- /dev/null
+++ b/board/ti/logic/prod-id/dict.c
@@ -0,0 +1,47 @@
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+
+int id_dict_size(struct id_data *data, struct id_cookie *cookie)
+{
+ idenum_t type;
+ int err;
+ int count = 0;
+ unsigned int size, keyval;
+ struct id_cookie d_cookie;
+
+ d_cookie = *cookie;
+
+ /* It has to be a dictionary */
+ err = id_whatis(&d_cookie, &type);
+ if (type != IDENUM_DICT)
+ return -ID_EINVAL;
+
+ size = extract_unsigned_pnum(&d_cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+
+ d_cookie.size = size;
+ d_cookie.start_offset = d_cookie.offset;
+ while (d_cookie.offset < d_cookie.start_offset+d_cookie.size) {
+ /* It has to be a key */
+ err = id_whatis(&d_cookie, &type);
+ if (type != IDENUM_KEY)
+ return -ID_EINVAL;
+ keyval = extract_unsigned_pnum(&d_cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+
+ /* Get the size of the object */
+ size = id_extract_size(&d_cookie, &err);
+ if (err != ID_EOK)
+ return err;
+
+ /* Move the offset forward by the object size */
+ d_cookie.offset += size;
+
+ /* Increment the count */
+ count++;
+ }
+ return count;
+}
diff --git a/board/ti/logic/prod-id/extract.c b/board/ti/logic/prod-id/extract.c
new file mode 100644
index 0000000000..09c7bedd7f
--- /dev/null
+++ b/board/ti/logic/prod-id/extract.c
@@ -0,0 +1,70 @@
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+#include "debug.h"
+
+unsigned int extract_unsigned_pnum(struct id_cookie *cookie, int start_bit, int *err)
+{
+ unsigned int value=0;
+ unsigned int bit_offset=0;
+ unsigned char bits;
+ unsigned char ch;
+ int oor;
+
+ *err = ID_EOK;
+ for (;;) {
+ ch = id_fetch_byte(cookie->mem_ptr, cookie->offset++, &oor);
+ if (oor != ID_EOK) {
+ *err = oor;
+ id_error("extract runs oor");
+ return 0;
+ }
+ if (ch & (1<<(start_bit-1))) {
+ /* more to go, accumulate bits */
+ bits = ch & ((1<<(start_bit - 1)) - 1);
+ value |= (bits << bit_offset);
+ bit_offset += start_bit-1;
+ start_bit = 8;
+ } else {
+ /* last byte of number */
+ bits = ch & ((1<<(start_bit - 1)) - 1);
+ value |= (bits << bit_offset);
+ break;
+ }
+ }
+ return value;
+}
+
+int extract_signed_pnum(struct id_cookie *cookie, int start_bit, int *err)
+{
+ int value=0;
+ unsigned int bit_offset=0;
+ unsigned char bits;
+ unsigned char ch;
+ int oor;
+
+ *err = ID_EOK;
+ for (;;) {
+ ch = id_fetch_byte(cookie->mem_ptr, cookie->offset++, &oor);
+ if (oor != ID_EOK) {
+ *err = oor;
+ id_error("extract runs oor");
+ return 0;
+ }
+ if (ch & (1<<(start_bit-1))) {
+ /* more to go, accumulate bits */
+ bits = ch & ((1<<(start_bit - 1)) - 1);
+ value |= (bits << bit_offset);
+ bit_offset += start_bit-1;
+ start_bit = 8;
+ } else {
+ /* last byte of number */
+ bits = ch & ((1<<(start_bit - 2)) - 1);
+ value |= (bits << bit_offset);
+ if (ch & (1<<(start_bit - 2)))
+ value = -value;
+ break;
+ }
+ }
+ return value;
+}
diff --git a/board/ti/logic/prod-id/id-errno.h b/board/ti/logic/prod-id/id-errno.h
new file mode 100644
index 0000000000..a9a85e98aa
--- /dev/null
+++ b/board/ti/logic/prod-id/id-errno.h
@@ -0,0 +1,10 @@
+#define ID_EOK 0 /* Okay */
+#define ID_ENOENT 2 /* No such key */
+#define ID_ENOMEM 12 /* Out of memory */
+#define ID_EACCES 13 /* Permission denied */
+#define ID_ENODEV 19 /* No such device */
+#define ID_EINVAL 22 /* Invalid arcument */
+#define ID_EDOM 33 /* argument out of domain of func */
+#define ID_ERANGE 34 /* Out of range */
+#define ID_EL2NSYNC 45 /* Level 2 not synchronized */
+#define ID_ENOMEDIUM 123 /* No medium found */
diff --git a/board/ti/logic/prod-id/interface.h b/board/ti/logic/prod-id/interface.h
new file mode 100644
index 0000000000..2646df24ed
--- /dev/null
+++ b/board/ti/logic/prod-id/interface.h
@@ -0,0 +1,105 @@
+/*
+ * Header file that interfaces to environment to access data
+ */
+
+/* Create the enum list of keys, not strings! */
+#undef ID_KEY_STRINGS
+#define ID_KEY_ENUMS
+#include "keys.h"
+
+
+typedef enum {
+ /* Number */
+ IDENUM_NEG_NUM = 0,
+ IDENUM_POS_NUM,
+
+ /* String/Hex String */
+ IDENUM_STR,
+ IDENUM_HEXSTR,
+
+ /* Array */
+ IDENUM_ARRAY,
+
+ /* Dictionary */
+ IDENUM_DICT,
+
+ /* Key */
+ IDENUM_KEY,
+
+ /* Any string */
+ IDENUM_ANY_STRING,
+
+ /* Any number */
+ IDENUM_ANY_NUMBER,
+
+} idenum_t;
+
+/* structure of builtin keys */
+struct id_key {
+ unsigned char *ptr;
+ unsigned int size;
+};
+
+
+/*
+ * return a byte from the ID data at offset 'offset' and set *oor to zero
+ * if offset is in range of the device. If offset is out of range then
+ * set *oor to non-zero. If mem_ptr is non-NULL use it as a pointer to
+ * a cached copy of the ID data */
+extern unsigned char id_fetch_byte(unsigned char *mem_ptr, int offset, int *oor);
+
+struct id_data {
+ /* mem_ptr is a pointer to read the initial ID data into, then if not
+ * null used to read a cached copy of the ID data from */
+ unsigned char *mem_ptr;
+ unsigned int root_size;
+ unsigned int root_offset;
+};
+
+/* Function to do the intial startup (i.e. figure out how much data, offset of
+ * key table, etc */
+extern int id_startup(struct id_data *data);
+/*
+ * Functions provided back to callers for use in accessing data
+ */
+
+/* ID data "cookie" used to access data; ultimately this will be opaque
+ * to the callers as they don't need to know whats in it, just pass it around
+ */
+struct id_cookie {
+ unsigned char *mem_ptr; /* cache pointer to ID data */
+ unsigned int start_offset; /* start offset from beginning of data */
+ unsigned int size; /* size of data in bytes */
+ unsigned int offset; /* current read offset */
+};
+
+/* Initialize the cookie to cover the whole root dictionary */
+extern int id_init_cookie(struct id_data *data, struct id_cookie *cookie);
+
+/* What is the read pointer cookie is pointing at */
+extern int id_whatis(struct id_cookie *cookie, idenum_t *type);
+
+/* Given a string, return the key code (or -1 if not found) */
+extern int id_data_get_key(char *key_name);
+
+
+/* ID error routine to handle malformed data */
+extern void id_error(const char *fmt, ...);
+
+/* Ouptut routine */
+extern int id_printf(const char *format, ...);
+
+
+/* User interface functions */
+extern int id_dict_size(struct id_data *data, struct id_cookie *cookie);
+extern int id_array_size(struct id_data *data, struct id_cookie *cookie);
+
+extern int id_dict_find_key(struct id_cookie *cookie, id_keys_t key);
+extern int id_find_dict(struct id_cookie *cookie, id_keys_t key, idenum_t type);
+extern int id_find_string(struct id_cookie *cookie, id_keys_t key, unsigned char *str_ptr, unsigned int *str_size);
+extern int id_find_number(struct id_cookie *cookie, id_keys_t key, int *num);
+extern int id_find_numbers(struct id_cookie *cookie, id_keys_t *key, int key_size, int *nums);
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(var) sizeof(var)/sizeof((var)[0])
+#endif
diff --git a/board/ti/logic/prod-id/internals.h b/board/ti/logic/prod-id/internals.h
new file mode 100644
index 0000000000..95e9654b0e
--- /dev/null
+++ b/board/ti/logic/prod-id/internals.h
@@ -0,0 +1,19 @@
+/*
+ * Extract an unsigned packed number, first byte is in 'pack_bits'
+ * of first byte, starting at offset 'offset' */
+extern unsigned int extract_unsigned_pnum(struct id_cookie *cookie, int pack_bits, int *err);
+extern int extract_signed_pnum(struct id_cookie *cookie, int pack_bits, int *err);
+
+
+
+// extern struct id_data id_data;
+
+extern int id_read_keys(struct id_data *data);
+extern int id_verify_builtin_keys(struct id_data *data);
+
+#define ID_MAX_KEY_SIZE 32
+
+extern int id_get_key(struct id_data *data, int keyval, struct id_key *key);
+extern int id_iterate_dict(struct id_data *data, struct id_cookie *cookie);
+
+extern int id_extract_size(struct id_cookie *cookie, int *err);
diff --git a/board/ti/logic/prod-id/keys.h b/board/ti/logic/prod-id/keys.h
new file mode 100644
index 0000000000..fcd5881772
--- /dev/null
+++ b/board/ti/logic/prod-id/keys.h
@@ -0,0 +1,95 @@
+
+#undef ID_KEY_START
+#undef ID_KEY_ENTRY
+#undef ID_KEY_END
+
+#if defined(ID_KEY_STRINGS)
+/* This is the usage to build the keys for the compiler; we define
+ * an array of strings whose index is the value */
+#define ID_KEY_START static char *id_keys[] = {
+#define ID_KEY_ENTRY(XX) #XX ,
+#define ID_KEY_END };
+#elif defined(ID_KEY_ENUMS)
+/* This is the usage by people using the library to access the data */
+#define ID_KEY_START typedef enum {
+#define ID_KEY_ENTRY(XX) ID_KEY_ ## XX,
+#define ID_KEY_END } id_keys_t;
+#else
+#error "Need either ID_KEY_INTERFACE or ID_KEY_COMPILER defined!"
+#endif
+
+
+/* There are some implied conventions here: */
+/* - names of keys that contain other keys (dictionaries) end in "_group" */
+/* - names of keys that provide a register setting end in "_reg" */
+/* - any keys that specify a unit of measure, include units in the name (ie. _mhz, _degf, _bytes) */
+
+ID_KEY_START
+
+/* Manufacturing unique data for each SOM */
+ID_KEY_ENTRY(serialization_group)
+ID_KEY_ENTRY(serial_number)
+ID_KEY_ENTRY(wifi_ethaddr1)
+ID_KEY_ENTRY(wifi_ethaddr2)
+ID_KEY_ENTRY(wifi_ethaddr3)
+ID_KEY_ENTRY(wifi_ethaddr4)
+ID_KEY_ENTRY(nvs)
+
+/* BOM Model number infromation */
+ID_KEY_ENTRY(model_group)
+ID_KEY_ENTRY(model_name)
+ID_KEY_ENTRY(part_number)
+ID_KEY_ENTRY(version_code)
+ID_KEY_ENTRY(hardware_platform)
+
+/* CPU specific information */
+ID_KEY_ENTRY(cpu0_group)
+ID_KEY_ENTRY(type)
+ID_KEY_ENTRY(number)
+ID_KEY_ENTRY(speed_mhz)
+ID_KEY_ENTRY(temp_class)
+
+/* CPU bus information */
+ID_KEY_ENTRY(cpu0_bus_group)
+
+/* DRAM bus information */
+ID_KEY_ENTRY(dram_bus_group)
+ID_KEY_ENTRY(sysconfig_reg)
+ID_KEY_ENTRY(sharing_reg)
+ID_KEY_ENTRY(dlla_ctrl_reg)
+ID_KEY_ENTRY(cs_cfg_reg)
+// ID_KEY_ENTRY(cs0_group) Used in the dram_bus_group, but key defined below after local_bus_group
+// ID_KEY_ENTRY(cs1_group) Used in the dram_bus_group, but key defined below after local_bus_group
+ID_KEY_ENTRY(mcfg_reg)
+ID_KEY_ENTRY(mr_reg)
+ID_KEY_ENTRY(rfr_ctrl_reg)
+ID_KEY_ENTRY(emr2_reg)
+ID_KEY_ENTRY(actim_ctrla_reg)
+ID_KEY_ENTRY(actim_ctrlb_reg)
+ID_KEY_ENTRY(power_reg)
+
+/* GPMC keys */
+ID_KEY_ENTRY(local_bus_group)
+ID_KEY_ENTRY(cs0_group)
+ID_KEY_ENTRY(cs1_group)
+ID_KEY_ENTRY(cs2_group)
+ID_KEY_ENTRY(cs3_group)
+ID_KEY_ENTRY(cs4_group)
+ID_KEY_ENTRY(cs5_group)
+ID_KEY_ENTRY(cs6_group)
+ID_KEY_ENTRY(config1_reg)
+ID_KEY_ENTRY(config2_reg)
+ID_KEY_ENTRY(config3_reg)
+ID_KEY_ENTRY(config4_reg)
+ID_KEY_ENTRY(config5_reg)
+ID_KEY_ENTRY(config6_reg)
+ID_KEY_ENTRY(config7_reg)
+
+/* Manufacturing unique data for each SOM */
+ID_KEY_ENTRY(lan_ethaddr1)
+ID_KEY_ENTRY(lan_ethaddr2)
+ID_KEY_ENTRY(lan_ethaddr3)
+ID_KEY_ENTRY(lan_ethaddr4)
+
+/* End of keys */
+ID_KEY_END
diff --git a/board/ti/logic/prod-id/query.c b/board/ti/logic/prod-id/query.c
new file mode 100644
index 0000000000..1429039220
--- /dev/null
+++ b/board/ti/logic/prod-id/query.c
@@ -0,0 +1,184 @@
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+
+static int id_extract_key(struct id_cookie *cookie, id_keys_t *key)
+{
+ int err;
+ id_keys_t keyval;
+
+ keyval = (id_keys_t)extract_unsigned_pnum(cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+ *key = keyval;
+ return ID_EOK;
+}
+
+/* in dictionary that cookie points to find key "key"; if found
+ * update cookie to associated "key" entry and return ID_EOK;
+ * else return -ID_ENOENT */
+int id_dict_find_key(struct id_cookie *cookie, id_keys_t key)
+{
+ int err;
+ unsigned int size;
+ id_keys_t d_key;
+ idenum_t type;
+ struct id_cookie d_cookie = *cookie;
+ struct id_cookie t_cookie;
+
+ err = id_whatis(cookie, &type);
+ if (err != ID_EOK)
+ return err;
+
+ /* Header has to be a dictionary */
+ if (type != IDENUM_DICT)
+ return -ID_EINVAL;
+
+ /* Extract size of dictionary */
+ size = extract_unsigned_pnum(&d_cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+
+ d_cookie.size = size;
+ d_cookie.start_offset = d_cookie.offset;
+
+ /* cookie->offset is now at first key */
+ while (d_cookie.offset < d_cookie.start_offset + d_cookie.size) {
+ /* Extract the key and move the cookie over key */
+ err = id_extract_key(&d_cookie, &d_key);
+ if (err != ID_EOK)
+ return err;
+ t_cookie = d_cookie;
+ /* move forward over the value */
+ size = id_extract_size(&d_cookie, &err);
+ if (err != ID_EOK)
+ return err;
+ if (key == d_key) {
+ d_cookie.size = size;
+ d_cookie.start_offset = t_cookie.offset;
+ d_cookie.offset = t_cookie.offset;
+ *cookie = d_cookie;
+ return ID_EOK;
+ }
+ d_cookie.offset += size;
+ }
+ return -ID_ENOENT;
+}
+
+/* Are these two types a match? */
+static int id_match_type(idenum_t type_a, idenum_t type_b)
+{
+ idenum_t tmp;
+
+ if (type_a == type_b)
+ return 1;
+
+ /* Oder the types (so the "*ANY*" types are in type_b) */
+ if ((int)type_a > (int)type_b) {
+ tmp = type_a;
+ type_a = type_b;
+ type_b = tmp;
+ }
+ if (type_b == IDENUM_ANY_STRING && (type_a == IDENUM_STR || type_a == IDENUM_HEXSTR))
+ return 1;
+
+ if (type_b == IDENUM_ANY_NUMBER && (type_a == IDENUM_NEG_NUM || type_a == IDENUM_POS_NUM))
+ return 1;
+
+ return 0;
+}
+
+/* Find in dictionary (that cookie points to) key "key" that is type "type" */
+int id_find_dict(struct id_cookie *cookie, id_keys_t key, idenum_t type)
+{
+ int err;
+ struct id_cookie d_cookie = *cookie;
+ idenum_t l_type;
+
+ err = id_dict_find_key(&d_cookie, key);
+ if (err != ID_EOK)
+ return err;
+ err = id_whatis(&d_cookie, &l_type);
+ if (err != ID_EOK)
+ return err;
+ if (!id_match_type(l_type, type))
+ return -ID_EINVAL;
+ *cookie = d_cookie;
+ return ID_EOK;
+}
+
+/* in dictionary pointed at by cookie, find the key "key"; verify its a
+ * string and copy its value */
+int id_find_string(struct id_cookie *cookie, id_keys_t key, unsigned char *str_ptr, unsigned int *str_size)
+{
+ int err, i;
+ unsigned char byte;
+ unsigned int size;
+ struct id_cookie d_cookie = *cookie;
+
+ err = id_find_dict(&d_cookie, key, IDENUM_ANY_STRING);
+
+ if (err != ID_EOK)
+ return err;
+ /* Extract the string size */
+ size = extract_unsigned_pnum(&d_cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+
+ if (size > *str_size)
+ return -ID_ERANGE;
+
+ for(i=0; i<size; ++i) {
+ byte = id_fetch_byte(d_cookie.mem_ptr, d_cookie.offset++, &err);
+ if (err)
+ return err;
+ str_ptr[i] = byte;
+ }
+ *str_size = size;
+
+ return ID_EOK;
+}
+
+/* in dictionary pointed at by cookie, find the key "key"; verify its a
+ * number (either pos/neg) and return its value through *num */
+int id_find_number(struct id_cookie *cookie, id_keys_t key, int *num)
+{
+ int err;
+ int l_num;
+ idenum_t l_type;
+ struct id_cookie d_cookie = *cookie;
+
+ err = id_find_dict(&d_cookie, key, IDENUM_ANY_NUMBER);
+
+ if (err != ID_EOK)
+ return err;
+ err = id_whatis(&d_cookie, &l_type);
+ if (err != ID_EOK)
+ return err;
+ /* Extract the number size */
+ l_num = extract_unsigned_pnum(&d_cookie, 5, &err);
+ if (err != ID_EOK)
+ return err;
+
+ if (l_type == IDENUM_NEG_NUM)
+ l_num = -l_num;
+
+ *num = l_num;
+ return ID_EOK;
+}
+
+/* in dictionary pointed at by cookie, find the list of keys; verify they are
+ * numbers (either pos/neg) and return their value through *nums */
+int id_find_numbers(struct id_cookie *cookie, id_keys_t *keys, int key_size, int *nums)
+{
+ int i, err;
+ struct id_cookie d_cookie;
+
+ for (i=0;i<key_size; ++i) {
+ d_cookie = *cookie;
+ err = id_find_number(&d_cookie, keys[i], &nums[i]);
+ if (err != ID_EOK)
+ return err;
+ }
+ return ID_EOK;
+}
diff --git a/board/ti/logic/prod-id/size.c b/board/ti/logic/prod-id/size.c
new file mode 100644
index 0000000000..c4aec4c6fe
--- /dev/null
+++ b/board/ti/logic/prod-id/size.c
@@ -0,0 +1,49 @@
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+
+int id_extract_size(struct id_cookie *cookie, int *err)
+{
+ idenum_t type;
+ struct id_cookie s_cookie;
+ int size;
+
+ s_cookie = *cookie;
+
+ *err = id_whatis(&s_cookie, &type);
+ if (*err != ID_EOK)
+ return *err;
+
+ switch(type) {
+ case IDENUM_DICT:
+ size = extract_unsigned_pnum(&s_cookie, 5, err);
+ size += (s_cookie.offset - cookie->offset);
+ break;
+ case IDENUM_ARRAY:
+ size = extract_unsigned_pnum(&s_cookie, 5, err);
+ size += (s_cookie.offset - cookie->offset);
+ break;
+ case IDENUM_STR:
+ case IDENUM_HEXSTR:
+ size = extract_unsigned_pnum(&s_cookie, 5, err);
+ size += (s_cookie.offset - cookie->offset);
+ break;
+ case IDENUM_POS_NUM:
+ case IDENUM_NEG_NUM:
+ extract_signed_pnum(&s_cookie, 5, err);
+ size = (s_cookie.offset - cookie->offset);
+ break;
+ case IDENUM_KEY:
+ extract_unsigned_pnum(&s_cookie, 5, err);
+ size = (s_cookie.offset - cookie->offset);
+ break;
+ default:
+ *err = -ID_EDOM;
+ size = 0;
+ break;
+ }
+ if (*err != ID_EOK)
+ return *err;
+
+ return size;
+}
diff --git a/board/ti/logic/prod-id/startup.c b/board/ti/logic/prod-id/startup.c
new file mode 100644
index 0000000000..73dd74069d
--- /dev/null
+++ b/board/ti/logic/prod-id/startup.c
@@ -0,0 +1,185 @@
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+#include "crc-15.h"
+
+/* struct id_data id_data; */
+
+struct __attribute__ ((packed)) id_header {
+ unsigned char signature[4];
+ unsigned char id_fmt_ver;
+ unsigned char unused0;
+ unsigned short data_length;
+} ;
+
+struct __attribute__ ((packed)) id_checksums {
+ unsigned short header;
+ unsigned short data;
+} ;
+
+int id_startup(struct id_data *data)
+{
+ int i, err;
+ struct id_cookie cookie;
+ unsigned char byte, *p;
+ char *header_tag= "LpId";
+ unsigned short xsum;
+ struct id_header hdr;
+ struct id_checksums xsums;
+ unsigned char *mem_ptr = data->mem_ptr;
+
+ /* Clear out data->mem_ptr since we want all the fetches to come
+ * from the AT24 chip. Once we've validated the CRCs, restore
+ * data->mem_ptr to allow id_fetch_byte to read from data->mem_ptr
+ * instead of the AT24 chip. Should speed up accesses dramatically */
+ data->mem_ptr = NULL;
+
+ memset(&cookie, 0, sizeof(cookie));
+ /* Data starts with the header, should be 'LpId' */
+ for (i=0; i<4; ++i) {
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ hdr.signature[i] = byte;
+ cookie.offset++;
+ if (err != ID_EOK) {
+ id_printf("%s[%u]\n", __FILE__, __LINE__);
+ goto err_ret;
+ }
+ if (hdr.signature[i] != header_tag[i]) {
+ id_printf("%s[%u]\n", __FILE__, __LINE__);
+ err = ID_ENODEV;
+ goto err_ret;
+ }
+ }
+
+ /* First LE 8-bit value is ID format version */
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ hdr.id_fmt_ver = byte;
+ cookie.offset++;
+
+ /* Second LE 8-bit value is currently not used */
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ hdr.unused0 = byte;
+ cookie.offset++;
+
+ /* Next LE 16-bit value is length of data */
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ hdr.data_length = byte;
+ cookie.offset++;
+
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ hdr.data_length |= byte << 8;
+ cookie.offset++;
+
+ /* Next LE 16-bit value is xsum of header */
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ xsums.header = byte;
+ cookie.offset++;
+
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ xsums.header |= byte << 8;
+ cookie.offset++;
+
+ /* Checksum the header */
+ xsum = 0;
+ p = (unsigned char *)&hdr;
+ for (i = 0; i < sizeof(hdr); ++i)
+ crc_15_step(&xsum, p[i]);
+
+ if (xsum != xsums.header) {
+ id_printf("%s[%u] xsum: 0x%04x, xsums.header: 0x%04x\n",
+ __FILE__, __LINE__, xsum, xsums.header);
+ err = -ID_EL2NSYNC;
+ goto err_ret;
+ }
+
+ /* Next LE 16-bit value is xsum of data */
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ xsums.data = byte;
+ cookie.offset++;
+
+ byte = id_fetch_byte(NULL, cookie.offset, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset] = byte;
+ xsums.data |= byte << 8;
+ cookie.offset++;
+
+ /* Checksum the data (next id_len bytes), must match xsums.data */
+ xsum = 0;
+ for (i = 0; i < hdr.data_length; ++i) {
+ byte = id_fetch_byte(NULL, cookie.offset + i, &err);
+ if (mem_ptr)
+ mem_ptr[cookie.offset + i] = byte;
+ if (err != ID_EOK) {
+ id_printf("%s[%u]\n", __FILE__, __LINE__);
+ goto err_ret;
+ }
+ crc_15_step(&xsum, byte);
+ }
+ if (xsum != xsums.data) {
+ id_printf("%s[%u] xsum: 0x%04x, xsums.data: 0x%04x\n",
+ __FILE__, __LINE__, xsum, xsums.data);
+ err = -ID_EL2NSYNC;
+ goto err_ret;
+ }
+
+ /* offset is now at the first byte of the root dictionary which
+ contains its span */
+ data->root_offset = cookie.offset;
+ data->root_size = extract_unsigned_pnum(&cookie, 5, &err);
+ if (err != ID_EOK) {
+ id_printf("%s[%u]\n", __FILE__, __LINE__);
+ goto err_ret;
+ }
+
+ data->root_size += cookie.offset - data->root_offset;
+
+#if 0
+ id_printf("Data format version: %u\n", hdr.id_fmt_ver);
+#endif
+
+ /* Restore data->mem_ptr to allow id_fetch_byte to read
+ * from the cached data instead of the AT24 chip */
+ data->mem_ptr = mem_ptr;
+
+ return ID_EOK;
+
+err_ret:
+
+ /* Error return - make sure signature in SRAM is invalid */
+ if (mem_ptr)
+ mem_ptr[0] = 0;
+
+ return err;
+}
+
+/*
+ * Reset the cookie to cover the whole root dictionary
+ */
+int id_init_cookie(struct id_data *data, struct id_cookie *cookie)
+{
+ if (!cookie)
+ return -ID_EINVAL;
+ cookie->mem_ptr = data->mem_ptr;
+ cookie->start_offset = data->root_offset;
+ cookie->size = data->root_size;
+ cookie->offset = cookie->start_offset;
+ return ID_EOK;
+}
diff --git a/board/ti/logic/prod-id/type.c b/board/ti/logic/prod-id/type.c
new file mode 100644
index 0000000000..57eda7f734
--- /dev/null
+++ b/board/ti/logic/prod-id/type.c
@@ -0,0 +1,20 @@
+#include "interface.h"
+#include "internals.h"
+#include "id-errno.h"
+
+int id_whatis(struct id_cookie *cookie, idenum_t *type)
+{
+ unsigned char byte;
+ int oor;
+ if (!cookie)
+ return -ID_EINVAL;
+
+ byte = id_fetch_byte(cookie->mem_ptr, cookie->offset, &oor);
+ if (oor != ID_EOK)
+ return -ID_ERANGE;
+
+ byte >>= 5;
+ *type = (idenum_t)byte;
+
+ return ID_EOK;
+}
diff --git a/board/ti/logic/product_id.h b/board/ti/logic/product_id.h
new file mode 100644
index 0000000000..b8a1600656
--- /dev/null
+++ b/board/ti/logic/product_id.h
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2008, 2009, 2010
+ * Logic Product Development, <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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 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 __PRODUCTID_H__
+#define __PRODUCTID_H__
+
+#define LOGIC_HEADER_VERSION_0 0
+#define LOGIC_HEADER_VERSION_1 1
+#define LOGIC_HEADER_VERSION_2 2
+#define LOGIC_HEADER_VERSION_3 3
+
+struct product_zone_0_rev_0 {
+ unsigned char header_version; // offset 0
+ char part_number[11]; // offset 1
+ char revision; // offset 12
+ char sn_week; // offset 13
+ char sn_year; // offset 14
+ char sn_site; // offset 15
+ int sn_cnt; // offset 16
+ char maturity; // offset 20
+};
+
+struct product_zone_0_rev_1 {
+ unsigned char header_version; // offset 0
+ char part_number[11]; // offset 1
+ char reserved; // revision removed after version 0
+ char sn_week; // offset 13
+ char sn_year; // offset 14
+ char sn_site; // offset 15
+ int sn_cnt; // offset 16
+ char maturity; // offset 20
+ char wifi_trim; // offset 21
+};
+
+
+struct product_zone_0_rev_2 {
+ unsigned char header_version; // offset 0
+ char part_number[11]; // offset 1
+ char revision; // offset 12
+ char sn_week; // offset 13
+ char sn_year; // offset 14
+ char sn_site; // offset 15
+ int sn_cnt; // offset 16
+ char maturity; // offset 20
+ char wifi_trim; // offset 21
+ unsigned char full_mac[6]; // offset 22
+};
+
+struct product_zone_2_rev_0 {
+ unsigned char mac0[3]; // offset 0
+ unsigned char mac1[3]; // offset 3
+ unsigned char mac2[3]; // offset 6
+ unsigned char mac3[3]; // offset 9
+ unsigned char nor0_size; // offset 12
+ unsigned char nor1_size; // offset 13
+ unsigned char nand0_size; // offset 14
+ unsigned char nand1_size; // offset 15
+ unsigned char sdram0_size; // offset 16
+ unsigned char sdram1_size; // offset 17
+ short processor_type; // offset 18
+ int feature_bits; // offset 20
+ int platform_bits; // offset 24
+};
+
+struct product_zone_2_rev_2 {
+ unsigned char mac0[3]; // offset 0
+ unsigned char mac1[3]; // offset 3
+ unsigned char mac2[3]; // offset 6
+ unsigned char mac3[3]; // offset 9
+ unsigned char nor0_size; // offset 12
+ unsigned char nor1_size; // offset 13
+ unsigned char nand0_size; // offset 14
+ unsigned char nand1_size; // offset 15
+ unsigned char sdram0_size; // offset 16
+ unsigned char sdram1_size; // offset 17
+ short processor_type; // offset 18
+ char reserved[4]; // offset 20
+ int platform_bits; // offset 24
+};
+
+struct product_zone_2_rev_3 {
+ unsigned char mac0[3]; // offset 0
+ unsigned char mac1[3]; // offset 3
+ unsigned char mac2[3]; // offset 6
+ unsigned char mac3[3]; // offset 9
+ unsigned char nor0_size; // offset 12
+ unsigned char nor1_size; // offset 13
+ unsigned char nand0_size; // offset 14
+ unsigned char nand1_size; // offset 15
+ unsigned char sdram0_size; // offset 16
+ unsigned char sdram1_size; // offset 17
+ short processor_type; // offset 18
+ char reserved[4]; // offset 20
+ int platform_bits; // offset 24
+ int hardware_revision; // offset 28
+};
+
+
+struct product_id_data {
+ struct {
+ union {
+ struct product_zone_0_rev_0 pz_0r0;
+ struct product_zone_0_rev_1 pz_0r1;
+ struct product_zone_0_rev_2 pz_0r2;
+ } u_zone0;
+
+ struct {
+ char model_revision;
+ char model_number[31];
+ } zone1;
+ union {
+ struct product_zone_2_rev_0 pz_2r0;
+ struct product_zone_2_rev_2 pz_2r2;
+ struct product_zone_2_rev_3 pz_2r3;
+ } zone2;
+ struct {
+ unsigned char data[468];
+ unsigned int valid;
+ } wifi_config_data;
+ } d;
+ unsigned int checksum;
+};
+
+// Only calculate across the data to checksum, compare to stored
+// value(outside of checksummed range)
+static inline int calculate_checksum(void *p, int len)
+{
+ unsigned char *buf = p;
+ unsigned int xsum = 0;
+ int i;
+
+ for (i=0; i<len; ++i)
+ xsum = ((xsum << 3) || (xsum >> 29)) ^ buf[i];
+
+ return xsum;
+}
+
+extern int fetch_production_data(void);
+extern void dump_production_data(void);
+extern void board_get_nth_enetaddr (unsigned char *enetaddr, int which, int position);
+
+#endif
diff --git a/board/ti/logic/splash-332x57.h b/board/ti/logic/splash-332x57.h
new file mode 100644
index 0000000000..d5b2e63d61
--- /dev/null
+++ b/board/ti/logic/splash-332x57.h
@@ -0,0 +1,367 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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
+ */
+
+/*
+ * Splash Screen Image
+ *
+ * To update this image, perform the following steps to convert your
+ * image to RGB565, compress with gzip, and format as C code.
+ * 1) Open your image in GIMP
+ * 2) Select File -> Save as...
+ * 3) Enter splash.bmp and select Save
+ * 4) On the "Save as BMP" dialog, open the "Advanced Options" section
+ * 5) Select "R5 G6 B5" under the "16 bits" section and select Save
+ * 6) At a prompt, run the following commands:
+ * gzip splash.bmp
+ * xxd -i splash.bmp.gz > splash.h
+ * 7) Replace the code below with the contents of splash.h
+ *
+ * Note that this image originally came from a 800x600 logo image, cropped
+ * in gimp using a selection box originating at [234,212], and 332x57 large.
+ */
+unsigned char splash_bmp_gz[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0x95, 0xeb, 0x22, 0x4f, 0x00, 0x03, 0x73, 0x70,
+ 0x6c, 0x61, 0x73, 0x68, 0x32, 0x2e, 0x62, 0x6d, 0x70, 0x00, 0xed, 0x5d,
+ 0x4f, 0x48, 0xe3, 0x5e, 0x1e, 0xef, 0x8f, 0x2d, 0x6c, 0x60, 0x3d, 0x84,
+ 0x1d, 0x61, 0x02, 0xca, 0x6e, 0x02, 0x0a, 0x06, 0x1c, 0x68, 0x61, 0x0e,
+ 0x16, 0xbc, 0xb4, 0xd0, 0x05, 0xcb, 0x7a, 0xb0, 0xfc, 0x84, 0x51, 0xc6,
+ 0x83, 0x53, 0x1c, 0x90, 0xe2, 0x41, 0x8a, 0x07, 0x29, 0x5e, 0x4a, 0xf1,
+ 0x20, 0x65, 0x0e, 0x6e, 0x11, 0x46, 0xda, 0x39, 0x38, 0xe8, 0x80, 0x4b,
+ 0x3d, 0x08, 0xf5, 0x20, 0xd8, 0x8b, 0xd0, 0x1e, 0x84, 0x0a, 0x23, 0x74,
+ 0x96, 0x11, 0xda, 0x05, 0x85, 0x08, 0x2e, 0xe4, 0xe0, 0x21, 0x0b, 0x1e,
+ 0xdc, 0x3e, 0xf3, 0x8b, 0x7d, 0x2f, 0x7f, 0x5e, 0xde, 0x4b, 0xaa, 0xee,
+ 0xfc, 0x26, 0x9f, 0x87, 0xce, 0x80, 0x4d, 0xf2, 0x5e, 0xf2, 0xc9, 0xf7,
+ 0x7d, 0xff, 0x37, 0x32, 0xfe, 0x97, 0xbc, 0xef, 0x1e, 0x7f, 0x6b, 0xff,
+ 0x8c, 0xb4, 0x7f, 0xfe, 0xfe, 0x8b, 0xcf, 0x17, 0x6a, 0xff, 0xfb, 0x8b,
+ 0x8f, 0xf5, 0xfd, 0xa1, 0xfd, 0xef, 0xbf, 0xfe, 0xe1, 0xf3, 0xfd, 0xf9,
+ 0x4f, 0xea, 0xcf, 0x03, 0xfe, 0xeb, 0xf3, 0xfd, 0xfb, 0x8f, 0x3e, 0xdf,
+ 0x5f, 0x7d, 0xdd, 0xc3, 0x2c, 0x33, 0x20, 0x48, 0xa1, 0xb1, 0x98, 0x3a,
+ 0x86, 0x22, 0x3b, 0x41, 0xbf, 0x10, 0x66, 0xba, 0x78, 0x01, 0x0f, 0x1e,
+ 0xa8, 0x10, 0x66, 0x6a, 0xa1, 0xd3, 0xf4, 0x64, 0xe9, 0x63, 0x7d, 0x45,
+ 0xae, 0x28, 0xda, 0xe8, 0x97, 0xde, 0x54, 0x5f, 0x14, 0xe5, 0x34, 0x13,
+ 0x39, 0xe6, 0x9e, 0x7b, 0x86, 0x1e, 0x7e, 0x36, 0x84, 0x99, 0x9e, 0x84,
+ 0x72, 0xf4, 0x49, 0xb9, 0xb3, 0x44, 0x45, 0x39, 0x6c, 0xbc, 0x28, 0x8e,
+ 0xc5, 0x3c, 0xd9, 0xe9, 0xe1, 0xa9, 0xb0, 0x16, 0x1f, 0xa9, 0x5a, 0x33,
+ 0x12, 0xc5, 0x72, 0x7d, 0x2f, 0x35, 0x20, 0x3c, 0xf7, 0x8c, 0x3d, 0xfc,
+ 0xde, 0x11, 0x66, 0x16, 0x73, 0xa4, 0x9c, 0xd4, 0xd0, 0xd7, 0x5a, 0xcc,
+ 0x79, 0xdc, 0xf4, 0xf0, 0xb8, 0xa0, 0x91, 0x96, 0x1d, 0x8c, 0x4a, 0x72,
+ 0xda, 0xd3, 0x38, 0x3d, 0x3c, 0x26, 0x66, 0x99, 0xf1, 0xe4, 0x79, 0x93,
+ 0x9e, 0x9b, 0x9b, 0x8d, 0xeb, 0xe9, 0xe7, 0x9e, 0xbb, 0x87, 0xdf, 0x37,
+ 0x8e, 0xb9, 0x89, 0xdc, 0x8a, 0x4c, 0xcf, 0xcd, 0xc9, 0x52, 0x54, 0x7c,
+ 0xee, 0xb9, 0x77, 0x10, 0x66, 0x2e, 0xf9, 0x5a, 0x68, 0x2d, 0x7e, 0x32,
+ 0x3d, 0x9e, 0x3c, 0x99, 0x9e, 0x8f, 0xd5, 0x42, 0x17, 0x9c, 0x7b, 0x4b,
+ 0x8d, 0x6f, 0xdf, 0x9d, 0x9d, 0xe0, 0x7c, 0xec, 0x64, 0xfa, 0x55, 0xf2,
+ 0x55, 0x72, 0x37, 0xbe, 0x16, 0x67, 0x22, 0x51, 0x31, 0xc3, 0xf2, 0x5d,
+ 0x98, 0xb1, 0x39, 0xc2, 0x8c, 0x5f, 0x60, 0x22, 0x6b, 0xf1, 0xeb, 0xf6,
+ 0x3a, 0xae, 0xef, 0xd7, 0xf1, 0x33, 0xef, 0x4d, 0x5f, 0x42, 0x93, 0x25,
+ 0x7a, 0x66, 0xf6, 0x4b, 0x27, 0x2e, 0xa4, 0xe6, 0x6e, 0x3c, 0x90, 0x95,
+ 0xd3, 0x76, 0x83, 0x6d, 0x7f, 0x66, 0xd0, 0x86, 0xff, 0x52, 0x88, 0xcd,
+ 0x2a, 0x47, 0xe7, 0xcd, 0x22, 0xf4, 0x76, 0x15, 0xe5, 0xf3, 0xa6, 0x72,
+ 0x14, 0xc8, 0x32, 0x11, 0xde, 0xe1, 0xfc, 0xe6, 0xc4, 0xbd, 0xd4, 0x41,
+ 0xf9, 0xb0, 0xb1, 0x22, 0xb7, 0xa0, 0x35, 0x57, 0x94, 0x51, 0x69, 0xb9,
+ 0xbe, 0x51, 0x96, 0xd3, 0x6b, 0xf1, 0x2d, 0xd6, 0xfa, 0xe8, 0x01, 0x41,
+ 0x9d, 0x3b, 0xf8, 0x7d, 0x9a, 0xbe, 0x20, 0xe0, 0x56, 0x98, 0x19, 0x8b,
+ 0x4d, 0xe4, 0x46, 0xaa, 0xb7, 0xcd, 0x0a, 0xe4, 0x1d, 0x59, 0x91, 0x0f,
+ 0x1b, 0x4b, 0xa5, 0xf1, 0xa4, 0x9f, 0x50, 0xab, 0x07, 0xfe, 0x95, 0x40,
+ 0x36, 0x90, 0x1d, 0x8b, 0x91, 0x7d, 0x5e, 0xc3, 0x31, 0xa7, 0xcd, 0x57,
+ 0x3f, 0x3e, 0xa4, 0x86, 0x13, 0x6b, 0xf1, 0xa8, 0xf8, 0x5c, 0xfe, 0x18,
+ 0x67, 0xda, 0xe6, 0x7a, 0x3e, 0x83, 0x79, 0x3a, 0x38, 0x2c, 0x11, 0xbf,
+ 0x09, 0x6b, 0x71, 0xab, 0x73, 0x08, 0xcc, 0x6e, 0x5c, 0x39, 0x6a, 0x62,
+ 0xbc, 0x5c, 0xad, 0x3b, 0xae, 0x3a, 0x9c, 0x78, 0x47, 0x39, 0xc7, 0xab,
+ 0xf0, 0xaf, 0xdb, 0x45, 0xdb, 0x3d, 0xe4, 0xb6, 0x79, 0x56, 0x10, 0x2d,
+ 0xfc, 0x67, 0xf3, 0xb1, 0xce, 0xe7, 0x2a, 0x4a, 0x2d, 0x84, 0xbf, 0x5e,
+ 0x86, 0x1d, 0x4e, 0x4c, 0xd5, 0x71, 0xd7, 0x1a, 0x95, 0x26, 0x72, 0x24,
+ 0x92, 0x33, 0xc3, 0x2e, 0xdf, 0x9f, 0x67, 0x3f, 0x4f, 0xb7, 0xe2, 0x5a,
+ 0x08, 0xbf, 0x56, 0xf0, 0x7e, 0xdc, 0x14, 0x76, 0xe3, 0xcf, 0x21, 0xbd,
+ 0x33, 0xec, 0x87, 0xd4, 0x2d, 0xb5, 0xb6, 0x79, 0x50, 0x26, 0x91, 0x06,
+ 0x46, 0xfc, 0xba, 0x4d, 0x7a, 0x05, 0xab, 0x77, 0xff, 0x4b, 0x68, 0xa3,
+ 0x4c, 0x76, 0x06, 0xae, 0x4a, 0x2e, 0x3f, 0x8e, 0xb9, 0xfd, 0x7c, 0x05,
+ 0xc3, 0x74, 0x14, 0xad, 0xbb, 0x97, 0x95, 0xeb, 0x69, 0x23, 0x37, 0xc7,
+ 0x62, 0xad, 0x87, 0xcf, 0x14, 0xe5, 0x2f, 0x58, 0x5e, 0x8e, 0xc5, 0x38,
+ 0x22, 0x89, 0xb0, 0xd9, 0x98, 0xb7, 0x5d, 0x45, 0x86, 0x55, 0xa5, 0xcb,
+ 0x62, 0x8e, 0x74, 0xbd, 0x2a, 0x76, 0x82, 0x64, 0x6b, 0x3e, 0x6c, 0x04,
+ 0xb2, 0xa4, 0xb2, 0xbb, 0x9b, 0xf0, 0x0b, 0xeb, 0x79, 0x7b, 0x49, 0x81,
+ 0x62, 0xaa, 0xee, 0x44, 0xd3, 0x24, 0xe5, 0x65, 0xcb, 0x82, 0x97, 0xc3,
+ 0x89, 0x19, 0x8a, 0x79, 0xb6, 0xee, 0xd8, 0x2c, 0xc9, 0x4e, 0x24, 0x85,
+ 0x0e, 0x1b, 0x74, 0xab, 0x07, 0x30, 0x4a, 0x74, 0x98, 0x97, 0x2b, 0x18,
+ 0x5e, 0x0a, 0x8c, 0x9c, 0xc6, 0xc9, 0x7b, 0x14, 0x15, 0xe5, 0x43, 0x0a,
+ 0x3f, 0x7f, 0xb7, 0xbc, 0x5c, 0x2a, 0xad, 0xe7, 0xf7, 0x1f, 0xc6, 0x7a,
+ 0xfe, 0xa6, 0x70, 0x50, 0x1e, 0xa9, 0xf6, 0x4b, 0xf0, 0x2c, 0x6e, 0x9b,
+ 0x3d, 0x09, 0xba, 0xb3, 0x77, 0x07, 0xb5, 0xd0, 0x01, 0xa1, 0x1c, 0xd2,
+ 0x70, 0xd8, 0xa0, 0x67, 0x26, 0xb9, 0xbc, 0x34, 0x93, 0x12, 0xa7, 0x69,
+ 0xba, 0x19, 0x02, 0x9c, 0x15, 0x04, 0x1b, 0x66, 0xae, 0xc5, 0x69, 0xb8,
+ 0xde, 0x81, 0x51, 0xcf, 0x26, 0xe3, 0xa5, 0xc0, 0xec, 0xe7, 0x69, 0xaf,
+ 0xb5, 0x90, 0xc4, 0xad, 0xc0, 0x2d, 0x2f, 0x77, 0x82, 0xc6, 0xbf, 0x85,
+ 0x99, 0x41, 0x71, 0x28, 0x32, 0x91, 0xfb, 0x08, 0x69, 0x1a, 0x8b, 0xb9,
+ 0xd9, 0x67, 0xd0, 0x37, 0x05, 0xe6, 0x64, 0x7a, 0x19, 0xab, 0xef, 0xe8,
+ 0xb1, 0xd9, 0xa0, 0xdd, 0xcd, 0x61, 0x5e, 0xb6, 0xee, 0x3a, 0x71, 0x79,
+ 0xe3, 0x30, 0xca, 0xcb, 0x0f, 0x29, 0xe3, 0x0c, 0xde, 0x4a, 0x8d, 0x72,
+ 0x20, 0xfb, 0x2a, 0x39, 0x9c, 0x18, 0x4e, 0xec, 0xa5, 0x5e, 0x6f, 0x6f,
+ 0x9a, 0xc8, 0xbd, 0x9b, 0x02, 0x4e, 0x66, 0x0e, 0x45, 0x8c, 0x7e, 0x89,
+ 0x8a, 0xc2, 0x55, 0xd7, 0xf3, 0xe3, 0xf7, 0x67, 0x1d, 0x4e, 0x9c, 0xa6,
+ 0x7b, 0xb7, 0xb9, 0xaa, 0xf1, 0x53, 0xce, 0x78, 0xc9, 0xfb, 0xd6, 0x4d,
+ 0x58, 0x79, 0xdb, 0x5c, 0x2a, 0xc9, 0x69, 0x70, 0xb5, 0xf1, 0xe4, 0x7a,
+ 0xde, 0x4c, 0xeb, 0x64, 0x22, 0xd6, 0x6b, 0x70, 0xcb, 0x4b, 0x09, 0xa3,
+ 0x71, 0xbc, 0x63, 0x81, 0x36, 0xaf, 0xcd, 0x62, 0xb2, 0x44, 0xab, 0xb5,
+ 0x5b, 0x21, 0xc3, 0x2e, 0x24, 0xc9, 0xad, 0x94, 0x2d, 0x56, 0x4e, 0xbf,
+ 0x95, 0x8c, 0x77, 0xc5, 0x0a, 0xca, 0x11, 0x9d, 0x05, 0x04, 0xf3, 0xf2,
+ 0xa6, 0x50, 0x0b, 0x99, 0x0f, 0xa9, 0xfd, 0xa3, 0x3f, 0xef, 0x58, 0x4c,
+ 0xaf, 0x0b, 0x01, 0x5f, 0xff, 0x9c, 0x4e, 0x62, 0x7f, 0xe6, 0xd6, 0xa0,
+ 0xbb, 0xa8, 0x81, 0xcd, 0x5a, 0xcd, 0x67, 0x40, 0xd0, 0xeb, 0xd6, 0x15,
+ 0x65, 0x3f, 0x5f, 0x0b, 0xe9, 0x65, 0xac, 0xc0, 0xac, 0x06, 0xf7, 0x52,
+ 0x28, 0xeb, 0x9d, 0xf1, 0xf2, 0x55, 0x52, 0x3f, 0xbb, 0xef, 0x8d, 0x85,
+ 0x24, 0x1a, 0x4f, 0xcb, 0xb0, 0x27, 0xd3, 0xa8, 0x66, 0x71, 0x53, 0xc0,
+ 0x49, 0x00, 0xb7, 0xbc, 0xbc, 0x0a, 0xe3, 0x3f, 0x17, 0x66, 0x3e, 0xa4,
+ 0xb4, 0x6c, 0x0a, 0x5a, 0xdb, 0xca, 0x0a, 0xc0, 0x46, 0xe4, 0xaa, 0x76,
+ 0xb6, 0x21, 0x8c, 0xa8, 0x78, 0x56, 0x20, 0xb7, 0x01, 0xce, 0x0a, 0x34,
+ 0xb3, 0x81, 0x79, 0x79, 0x9a, 0x26, 0x3f, 0xee, 0x98, 0xd3, 0x6b, 0x80,
+ 0x4b, 0x25, 0xab, 0xd8, 0x28, 0x7c, 0x17, 0x35, 0xae, 0x99, 0x6b, 0xab,
+ 0xbc, 0xef, 0xb5, 0x4e, 0xaf, 0x58, 0xae, 0x0f, 0x61, 0xe4, 0xd2, 0xa0,
+ 0x08, 0x4b, 0x4d, 0x27, 0xbc, 0x9c, 0x13, 0xf5, 0x3a, 0xc3, 0x7e, 0xde,
+ 0xdc, 0xda, 0x3d, 0xe6, 0x34, 0xdf, 0x45, 0x5f, 0xcb, 0xce, 0x33, 0xf7,
+ 0xd8, 0xbc, 0x04, 0x60, 0x22, 0x5a, 0x2c, 0xa6, 0x3b, 0xd1, 0x95, 0xb3,
+ 0x82, 0x7a, 0x97, 0x86, 0xa9, 0xb4, 0x56, 0x26, 0xd2, 0x20, 0xd4, 0x36,
+ 0x5b, 0x26, 0xcf, 0xc7, 0x1a, 0x30, 0x2f, 0xad, 0xa5, 0x98, 0x11, 0x6c,
+ 0x16, 0xbd, 0xea, 0x7a, 0x1e, 0xaf, 0xe9, 0xcc, 0xc7, 0xd0, 0xe7, 0x3f,
+ 0x52, 0x35, 0xdb, 0x7f, 0xd6, 0xe2, 0xad, 0x3b, 0xf4, 0x53, 0x97, 0x3c,
+ 0xee, 0xac, 0x17, 0xdc, 0x28, 0xb4, 0x97, 0x38, 0xe1, 0xa5, 0xfe, 0x3d,
+ 0xd8, 0xc3, 0x58, 0x34, 0xb3, 0x0c, 0xf0, 0x2f, 0x6f, 0x94, 0xed, 0x3c,
+ 0xb9, 0x4f, 0xc3, 0x4b, 0x60, 0x81, 0xa8, 0x3b, 0xe9, 0x6d, 0xd3, 0x99,
+ 0x2f, 0x06, 0xc6, 0x16, 0xdb, 0xd9, 0x7b, 0x64, 0x0a, 0xf9, 0x04, 0x64,
+ 0x49, 0x4f, 0x82, 0x4c, 0xdb, 0xec, 0x6b, 0x91, 0xfb, 0x10, 0x9c, 0xf1,
+ 0xf2, 0x92, 0x47, 0x6d, 0xc3, 0xc9, 0x92, 0x9d, 0x2d, 0xe3, 0xf3, 0x9d,
+ 0x4c, 0xa3, 0x32, 0xdf, 0xf8, 0x96, 0x0b, 0x0c, 0xea, 0xa9, 0xd9, 0x6c,
+ 0xd8, 0xad, 0xe3, 0x92, 0x7f, 0xeb, 0x8a, 0x97, 0x52, 0x08, 0x9d, 0xd3,
+ 0x84, 0x0d, 0x8f, 0xb6, 0x58, 0x33, 0x6f, 0x94, 0x11, 0x4f, 0xc3, 0x4b,
+ 0x9f, 0xef, 0x7a, 0xba, 0x45, 0xf9, 0xe4, 0xac, 0xaf, 0x0c, 0xef, 0x3c,
+ 0x34, 0x3b, 0x27, 0xc0, 0x67, 0xee, 0x94, 0x48, 0xdb, 0x24, 0xd7, 0x39,
+ 0x9c, 0xf1, 0x72, 0x01, 0xd1, 0xc9, 0x6e, 0x9b, 0x64, 0xef, 0x01, 0x9a,
+ 0x39, 0xf5, 0xb2, 0xa2, 0xff, 0x3b, 0x13, 0x81, 0x7d, 0x35, 0x15, 0x05,
+ 0xb7, 0x83, 0xab, 0x70, 0xcb, 0x4b, 0xd4, 0x0e, 0xe7, 0xaa, 0xdd, 0x8a,
+ 0xa6, 0x3c, 0x15, 0x2f, 0x7d, 0x3e, 0x35, 0x42, 0x78, 0xde, 0xfc, 0xec,
+ 0x52, 0x62, 0xfe, 0xe7, 0x1d, 0xca, 0x20, 0xbc, 0xbf, 0xc1, 0x0c, 0x83,
+ 0x6d, 0x6d, 0xd3, 0xce, 0xb7, 0x59, 0x94, 0x57, 0x4d, 0x3c, 0x0d, 0x66,
+ 0x70, 0xc2, 0x4b, 0xde, 0x87, 0xca, 0x35, 0xd2, 0x35, 0x1c, 0x73, 0xb0,
+ 0x4d, 0x53, 0x51, 0xf4, 0xde, 0x10, 0x94, 0xb7, 0x24, 0x7a, 0xb2, 0x3b,
+ 0x5e, 0x66, 0x58, 0x78, 0x3e, 0x4d, 0xc5, 0xde, 0x5f, 0x4e, 0x8a, 0xa7,
+ 0xe3, 0xe5, 0x55, 0x58, 0x3d, 0xc2, 0x4d, 0x2c, 0x1a, 0x60, 0x42, 0x97,
+ 0x6d, 0xf9, 0x49, 0xc1, 0xf9, 0x1b, 0xac, 0x67, 0x63, 0x17, 0x63, 0x21,
+ 0xbd, 0x23, 0x4e, 0x78, 0xb9, 0x8a, 0xc8, 0xfc, 0xf3, 0x26, 0xb9, 0x07,
+ 0x00, 0xd5, 0x4a, 0x51, 0x5d, 0xee, 0x1d, 0x0b, 0x6b, 0x29, 0x9f, 0x6c,
+ 0xa3, 0x86, 0x00, 0xee, 0x78, 0x09, 0xff, 0x15, 0xc8, 0x6f, 0x7b, 0x5d,
+ 0x84, 0x14, 0x4f, 0xc7, 0x4b, 0x81, 0x51, 0xbd, 0x1d, 0xaf, 0xb7, 0x79,
+ 0xca, 0x39, 0xa2, 0x30, 0x66, 0x66, 0xbc, 0xa9, 0x3a, 0xf3, 0x8d, 0xfe,
+ 0x13, 0xeb, 0xdb, 0xec, 0x97, 0xc8, 0x62, 0xa8, 0x4e, 0x78, 0x79, 0x32,
+ 0x0d, 0x5f, 0xc9, 0x4e, 0x27, 0x83, 0xb1, 0x1a, 0x84, 0x25, 0xfd, 0x52,
+ 0x89, 0x87, 0xfe, 0x16, 0x45, 0x2c, 0x63, 0xe5, 0x88, 0x64, 0x4f, 0xbd,
+ 0xe0, 0xdc, 0xf0, 0x52, 0x46, 0xa2, 0x02, 0xaf, 0xa8, 0x77, 0x2e, 0x6b,
+ 0x3c, 0x1d, 0x2f, 0xb5, 0x77, 0x9d, 0x46, 0x3a, 0x18, 0x31, 0xcb, 0x98,
+ 0x65, 0x65, 0xd0, 0xef, 0xe5, 0x2a, 0xb6, 0xd8, 0xbd, 0x54, 0xbf, 0xa5,
+ 0xb6, 0xb9, 0x6b, 0x99, 0x67, 0x01, 0xc3, 0x09, 0x2f, 0xd1, 0xe7, 0x69,
+ 0x9d, 0xcf, 0x61, 0x44, 0x86, 0x85, 0x3d, 0xd4, 0x9b, 0x0d, 0xf8, 0x5e,
+ 0xae, 0xc5, 0xe1, 0xb3, 0x06, 0x30, 0x73, 0xe1, 0x1f, 0xfe, 0xe7, 0x17,
+ 0xdc, 0xd8, 0xe3, 0xbd, 0xd0, 0xda, 0x2b, 0x0a, 0xa9, 0xe6, 0x43, 0x82,
+ 0xa7, 0xe4, 0xe5, 0x50, 0x04, 0x1c, 0xf1, 0xc9, 0xd5, 0xfc, 0x51, 0x0d,
+ 0x4b, 0xc3, 0x54, 0xdd, 0xb9, 0xcf, 0x1e, 0x44, 0xd2, 0xcd, 0xf3, 0x36,
+ 0x6f, 0x88, 0xfc, 0x98, 0x4e, 0x78, 0x79, 0x53, 0xe8, 0x1c, 0xf3, 0x56,
+ 0xa2, 0x8b, 0x7d, 0xc2, 0x7e, 0x99, 0xbe, 0x16, 0xec, 0x05, 0xea, 0x49,
+ 0xc0, 0xb3, 0xb7, 0xd2, 0x97, 0xa2, 0xe2, 0x46, 0x59, 0x39, 0x52, 0xc7,
+ 0xb7, 0x23, 0xae, 0x0a, 0x5b, 0x4a, 0x74, 0xbc, 0x9c, 0x65, 0x5e, 0x56,
+ 0x3a, 0xc7, 0x6e, 0x36, 0x70, 0xf9, 0x72, 0xb4, 0xd0, 0x78, 0x49, 0xb3,
+ 0x97, 0x00, 0x38, 0xe1, 0xe5, 0xa0, 0xa8, 0xee, 0x41, 0x64, 0x72, 0xc8,
+ 0x1c, 0x7e, 0xc1, 0x8c, 0x43, 0x2d, 0xaa, 0x79, 0x18, 0x51, 0x0b, 0x99,
+ 0x65, 0xab, 0x8d, 0x10, 0x59, 0x97, 0xf4, 0xbc, 0xe4, 0x7d, 0xb0, 0x6e,
+ 0x4b, 0xfb, 0x3c, 0x61, 0x0d, 0x73, 0x45, 0x86, 0x2d, 0x9f, 0x3d, 0x28,
+ 0xaa, 0x59, 0xb1, 0xd4, 0xba, 0x6b, 0x21, 0xeb, 0x08, 0x03, 0x1d, 0x2f,
+ 0xb7, 0x10, 0x7d, 0xf6, 0xa0, 0xdc, 0x3d, 0xed, 0xb2, 0xc3, 0xcb, 0x9b,
+ 0x42, 0x54, 0x9c, 0x7b, 0x18, 0xab, 0x41, 0xbf, 0x90, 0x61, 0x71, 0xd7,
+ 0x71, 0xc2, 0xcb, 0x8b, 0xdf, 0x64, 0xdd, 0xb8, 0x0b, 0x3d, 0x24, 0x2a,
+ 0x9a, 0xdf, 0x51, 0x3a, 0x4f, 0xa6, 0x19, 0x76, 0xe3, 0xfa, 0x18, 0xee,
+ 0xa8, 0x44, 0x52, 0x9b, 0xe6, 0x96, 0x97, 0xcb, 0x75, 0x3a, 0xbd, 0x06,
+ 0x8e, 0xa9, 0xa3, 0xb6, 0x0d, 0xca, 0xd8, 0xf7, 0x16, 0xbb, 0xd2, 0x97,
+ 0x90, 0x75, 0x56, 0x3f, 0x1d, 0x2f, 0x33, 0x08, 0x2f, 0x27, 0x4b, 0x34,
+ 0xab, 0xb0, 0x83, 0xc6, 0xcb, 0x8a, 0x32, 0x23, 0x77, 0xc6, 0x8a, 0xdc,
+ 0x2f, 0x9d, 0x37, 0xa7, 0xea, 0x67, 0x85, 0x5d, 0x8b, 0x6c, 0x66, 0x27,
+ 0xbc, 0xd4, 0xd6, 0x41, 0xeb, 0x73, 0x84, 0x61, 0xc5, 0xcb, 0x6e, 0xdc,
+ 0x15, 0x10, 0x77, 0x87, 0xb5, 0x04, 0x32, 0x8b, 0xf6, 0xff, 0x93, 0x97,
+ 0x33, 0xb2, 0x3e, 0xce, 0xae, 0xe1, 0xc7, 0xe2, 0xa5, 0x35, 0x96, 0xeb,
+ 0x66, 0xf1, 0x3e, 0x27, 0xbc, 0xdc, 0x7a, 0x44, 0x5e, 0x72, 0x55, 0xe7,
+ 0xe7, 0x84, 0x71, 0xc9, 0x07, 0xb2, 0x9a, 0x25, 0x60, 0xbd, 0x17, 0xc2,
+ 0x70, 0xc2, 0x4b, 0x58, 0x6b, 0xf8, 0x58, 0xa7, 0xdb, 0xc7, 0x61, 0x9b,
+ 0x09, 0xdd, 0xc7, 0x61, 0x5f, 0x7d, 0x51, 0xb6, 0xca, 0xa8, 0xc1, 0xed,
+ 0xe3, 0xc6, 0x08, 0x12, 0x9e, 0x97, 0xf0, 0x0e, 0xb3, 0x51, 0xe6, 0x69,
+ 0x96, 0x61, 0x03, 0x8d, 0x97, 0x45, 0xf9, 0xb6, 0xd9, 0xd7, 0xd2, 0xc6,
+ 0x6d, 0xb3, 0x5f, 0x82, 0xf5, 0xe1, 0xde, 0x6d, 0xbd, 0x5d, 0xe1, 0x84,
+ 0x97, 0x97, 0x7c, 0xdf, 0xfd, 0x22, 0xe9, 0xe2, 0xda, 0x28, 0x1e, 0x9b,
+ 0x97, 0xe0, 0xb9, 0x69, 0x32, 0xb3, 0xa2, 0x90, 0xac, 0xce, 0x89, 0xdd,
+ 0x03, 0xe7, 0x85, 0x8d, 0x4a, 0x74, 0x79, 0xd3, 0x2f, 0x8a, 0x9d, 0x63,
+ 0x51, 0xbb, 0x07, 0xf5, 0x3e, 0x59, 0x69, 0xf1, 0xef, 0x83, 0x53, 0xf5,
+ 0xc3, 0x86, 0xf9, 0x30, 0xfa, 0xc5, 0x71, 0xbc, 0x14, 0x18, 0x38, 0xbf,
+ 0xd5, 0x8d, 0xed, 0x69, 0x84, 0xc6, 0xcb, 0xb3, 0x82, 0x5f, 0x18, 0x80,
+ 0x46, 0x54, 0x94, 0x42, 0x3d, 0x89, 0xa5, 0x92, 0xc6, 0x4e, 0x7d, 0xec,
+ 0xc0, 0x09, 0x2f, 0xa3, 0xa2, 0x7a, 0x0c, 0x8d, 0x5f, 0xc4, 0x78, 0x0e,
+ 0x73, 0x5e, 0x1e, 0x94, 0x9d, 0x9f, 0xb3, 0x83, 0x39, 0xb1, 0x77, 0xbb,
+ 0xf3, 0x3e, 0x3e, 0x96, 0xbc, 0x44, 0x2d, 0x14, 0xab, 0x3c, 0x76, 0x73,
+ 0xa0, 0x7e, 0xb2, 0x8f, 0x88, 0x0e, 0x80, 0x46, 0x21, 0xad, 0x34, 0x6e,
+ 0xbe, 0xfd, 0xcc, 0xad, 0x86, 0xd1, 0xa2, 0xc0, 0xfb, 0x89, 0xce, 0x20,
+ 0xbf, 0xc2, 0x8a, 0xdc, 0xcd, 0xba, 0x52, 0x3b, 0x7b, 0x5c, 0x8c, 0x69,
+ 0xd9, 0x58, 0xa8, 0x8c, 0x77, 0xc2, 0xcb, 0xb1, 0xfb, 0x1a, 0xa6, 0xa2,
+ 0xa5, 0xe6, 0x43, 0x02, 0x2b, 0x5e, 0xd2, 0xfa, 0x13, 0x8c, 0x30, 0xe6,
+ 0x69, 0x92, 0xc5, 0x22, 0x9d, 0xf0, 0x12, 0xcd, 0xfa, 0xc1, 0x79, 0x1a,
+ 0xf5, 0x78, 0x8f, 0xf8, 0xd5, 0x37, 0x10, 0x1b, 0xd8, 0x2f, 0xc0, 0xbe,
+ 0x58, 0x32, 0xbf, 0xba, 0x1d, 0xf0, 0xbc, 0x44, 0xa3, 0xfc, 0x6e, 0xf6,
+ 0x41, 0x3d, 0xec, 0xfd, 0x97, 0x51, 0x51, 0x5d, 0x2d, 0x1a, 0x93, 0x77,
+ 0xc2, 0x4b, 0x35, 0x82, 0x78, 0xd8, 0x70, 0x23, 0xef, 0xa3, 0x22, 0xfc,
+ 0x44, 0x3b, 0x70, 0x23, 0x83, 0xd5, 0xaa, 0x50, 0x63, 0x3d, 0xcc, 0x79,
+ 0x93, 0x24, 0xe2, 0xe3, 0x84, 0x97, 0x97, 0x3c, 0xec, 0xcd, 0xa6, 0xb9,
+ 0x23, 0xa8, 0x47, 0x1e, 0xd5, 0xd4, 0xc3, 0x0c, 0x9c, 0x3f, 0x6c, 0x5f,
+ 0xbd, 0x48, 0x02, 0x3c, 0x2f, 0x51, 0x5d, 0xf5, 0xdb, 0xd1, 0xd3, 0xc6,
+ 0x21, 0xd5, 0xb7, 0xa2, 0x89, 0x64, 0x09, 0xd0, 0xf3, 0x32, 0xcc, 0xa8,
+ 0x5a, 0x32, 0x5d, 0xd6, 0xad, 0x1e, 0x68, 0xbe, 0xa0, 0x86, 0x5b, 0x22,
+ 0x06, 0x59, 0x81, 0x89, 0x7c, 0x33, 0xe4, 0x83, 0x03, 0x90, 0xe9, 0x06,
+ 0xce, 0xf2, 0x89, 0xd0, 0xe8, 0x3c, 0x69, 0xbc, 0xea, 0x82, 0x43, 0xf3,
+ 0x24, 0xf4, 0x7a, 0x06, 0x5a, 0x2d, 0xd4, 0xbb, 0x4d, 0x3a, 0x1b, 0x6b,
+ 0xe0, 0x79, 0x19, 0x66, 0x60, 0x8b, 0x9c, 0x4e, 0x23, 0xc1, 0x83, 0x84,
+ 0x97, 0x5a, 0xdc, 0x15, 0xd6, 0xa4, 0xe9, 0x79, 0xa9, 0xed, 0x5d, 0xee,
+ 0x24, 0x5b, 0x86, 0x35, 0xab, 0xf3, 0x73, 0x9e, 0x3d, 0x17, 0x15, 0x6f,
+ 0x0a, 0x56, 0x75, 0x7c, 0x64, 0x67, 0x75, 0xc6, 0xcb, 0x5d, 0x24, 0x66,
+ 0xd8, 0x2f, 0xd9, 0x67, 0xca, 0x02, 0xa0, 0x59, 0x65, 0x53, 0x75, 0xbd,
+ 0x7c, 0x7a, 0x8f, 0xe4, 0x83, 0x54, 0x14, 0x77, 0xf7, 0x1a, 0xc0, 0x2e,
+ 0xcf, 0x0d, 0x95, 0xdf, 0xb4, 0x3e, 0x2f, 0x6b, 0x90, 0xf0, 0x72, 0x8b,
+ 0x55, 0x2b, 0xc8, 0xe0, 0xda, 0x4a, 0x5a, 0x5e, 0x86, 0x7f, 0xcb, 0x58,
+ 0xdd, 0x74, 0xb5, 0x8b, 0x03, 0x1b, 0xd0, 0x98, 0x75, 0x8e, 0x5a, 0xa5,
+ 0xe4, 0xc8, 0xb4, 0x35, 0x4a, 0x33, 0xe9, 0xab, 0xa2, 0x65, 0x5a, 0x53,
+ 0x67, 0x84, 0x33, 0x5e, 0x66, 0xd8, 0x8f, 0x88, 0x17, 0xff, 0xa0, 0x6c,
+ 0xaf, 0x0d, 0x8e, 0x27, 0xd1, 0x37, 0xc8, 0x4c, 0x9f, 0x43, 0xb3, 0xc7,
+ 0x6f, 0x9b, 0x56, 0xde, 0x75, 0x52, 0xd8, 0xf1, 0x32, 0x2a, 0xa2, 0x3a,
+ 0xb9, 0xbb, 0xdd, 0xb0, 0x03, 0x12, 0x5e, 0x6a, 0xfe, 0xd3, 0x3d, 0x17,
+ 0xbc, 0xd4, 0x76, 0x18, 0x5c, 0x96, 0x3d, 0x19, 0x60, 0x1b, 0x50, 0x85,
+ 0x93, 0x2a, 0xe0, 0xb0, 0x6d, 0xa5, 0xe4, 0xcb, 0x0a, 0x99, 0xdd, 0xe0,
+ 0xb4, 0x8e, 0x62, 0x38, 0x81, 0x5e, 0x6f, 0xb2, 0x84, 0xf7, 0x63, 0xbe,
+ 0xd2, 0xb1, 0xd2, 0x5c, 0x36, 0xed, 0x04, 0xd1, 0x3a, 0xa0, 0xcd, 0x06,
+ 0xde, 0x76, 0x0b, 0x33, 0x81, 0x2c, 0xce, 0x9f, 0x6c, 0x5f, 0x47, 0xa1,
+ 0xef, 0xf2, 0x38, 0x91, 0xb3, 0xbe, 0x6f, 0xb3, 0x4c, 0xef, 0x36, 0x59,
+ 0xfd, 0x3b, 0x09, 0x2f, 0x07, 0x7f, 0x7b, 0x27, 0x60, 0x8b, 0x9c, 0x8e,
+ 0x97, 0xd7, 0xd3, 0xea, 0x3d, 0xed, 0x86, 0x9c, 0xd7, 0x57, 0x5c, 0x7f,
+ 0xcd, 0xf3, 0xd4, 0xe7, 0xb8, 0x0a, 0xdb, 0x57, 0x96, 0x93, 0x5a, 0x97,
+ 0x4e, 0x79, 0x19, 0x66, 0xf4, 0x5a, 0xed, 0x48, 0xd5, 0xca, 0x17, 0xfe,
+ 0x99, 0x5b, 0xcc, 0xe9, 0xb5, 0x0d, 0xab, 0xbc, 0x8c, 0x80, 0xae, 0x6e,
+ 0x08, 0x57, 0xe3, 0xb5, 0x13, 0x04, 0x1e, 0xfe, 0x16, 0x46, 0x5a, 0xd8,
+ 0xf3, 0xf2, 0xb3, 0x49, 0xfd, 0x9c, 0xb9, 0xc7, 0xc5, 0x2f, 0xa8, 0x5a,
+ 0xf5, 0x52, 0xc9, 0xde, 0x63, 0x4b, 0xc2, 0x4b, 0x2d, 0x4f, 0x05, 0xbe,
+ 0x6b, 0x34, 0xbc, 0xec, 0x49, 0xa8, 0xef, 0xb0, 0x55, 0x0d, 0x1f, 0x1d,
+ 0xe6, 0x63, 0xf0, 0x13, 0x3a, 0x28, 0xd3, 0x32, 0x7d, 0x40, 0x20, 0xe9,
+ 0x8f, 0x82, 0x66, 0x90, 0xe1, 0xe0, 0x94, 0x97, 0x60, 0x0f, 0xd4, 0x6b,
+ 0x11, 0x4d, 0xe5, 0x45, 0x91, 0x89, 0xc0, 0x57, 0x0e, 0x33, 0x51, 0x71,
+ 0x2f, 0x65, 0xec, 0xa1, 0x68, 0xbd, 0x5f, 0x66, 0x58, 0x63, 0x37, 0x96,
+ 0x83, 0xb2, 0xbe, 0x23, 0xcf, 0x31, 0x27, 0xc6, 0x6e, 0xa0, 0x1a, 0x51,
+ 0xab, 0xfe, 0x17, 0x24, 0x75, 0xba, 0xc6, 0x7a, 0xe3, 0x15, 0x79, 0x31,
+ 0xb7, 0x13, 0x9c, 0x45, 0x7c, 0x58, 0x70, 0x8c, 0xf7, 0xb6, 0x69, 0xa7,
+ 0xf9, 0xda, 0xf3, 0xf2, 0x98, 0xfb, 0xde, 0x30, 0x3e, 0x29, 0x52, 0x5e,
+ 0x5e, 0x70, 0x9d, 0xd8, 0x06, 0xfa, 0x56, 0x82, 0x8e, 0x7a, 0x02, 0xc3,
+ 0xfb, 0xc0, 0xef, 0x0c, 0x3b, 0xcb, 0x84, 0x19, 0xb2, 0x9a, 0xb4, 0x01,
+ 0x28, 0x63, 0xf0, 0xa0, 0x4c, 0x17, 0xc3, 0xcb, 0xb0, 0x7b, 0xa9, 0xbe,
+ 0xce, 0x8d, 0xc6, 0x80, 0xbc, 0x72, 0xd3, 0x39, 0x2f, 0xc1, 0x3b, 0x66,
+ 0xac, 0xe7, 0x68, 0x2a, 0xcb, 0xf5, 0xc9, 0x12, 0xd8, 0x5d, 0xe5, 0xf4,
+ 0x4d, 0x81, 0xab, 0x9a, 0x69, 0xc0, 0x07, 0x65, 0x9c, 0x96, 0x1e, 0x15,
+ 0xcd, 0x7a, 0x81, 0x1e, 0x36, 0x36, 0xca, 0x8b, 0xb9, 0xd3, 0xf4, 0x69,
+ 0x7a, 0x31, 0xb7, 0x51, 0xd6, 0xcb, 0xb8, 0x8a, 0x62, 0xbe, 0x62, 0xb2,
+ 0x7e, 0x1b, 0xe3, 0x86, 0x0a, 0x72, 0xe0, 0xfd, 0x1d, 0xa9, 0x82, 0x5d,
+ 0xfb, 0x34, 0x1d, 0xc8, 0x6e, 0x94, 0xf5, 0x33, 0x6a, 0xd9, 0x64, 0xef,
+ 0xd8, 0xf9, 0xd5, 0xa3, 0xa2, 0x96, 0x63, 0x87, 0x6a, 0x21, 0x24, 0x7d,
+ 0x0d, 0x06, 0x84, 0xbd, 0x54, 0x67, 0xfd, 0x13, 0x39, 0x1e, 0xf9, 0xab,
+ 0x14, 0x9a, 0xaa, 0xcf, 0x89, 0x97, 0xfc, 0x72, 0x7d, 0x35, 0xf8, 0x35,
+ 0xbf, 0x98, 0x63, 0x22, 0x64, 0x7e, 0x99, 0x4e, 0xf4, 0xeb, 0x6b, 0x9e,
+ 0xc6, 0x86, 0x02, 0x3d, 0xd3, 0xf0, 0xbd, 0xc6, 0x3a, 0x58, 0x22, 0xa8,
+ 0x4e, 0xd4, 0xe0, 0x86, 0x97, 0xc0, 0x4b, 0x41, 0xdf, 0xb3, 0xd3, 0xfe,
+ 0x6d, 0xdc, 0x09, 0x76, 0xa7, 0x3b, 0x11, 0x79, 0x7f, 0xa2, 0xf1, 0x24,
+ 0x79, 0x7d, 0x3e, 0xc0, 0x61, 0x03, 0x6f, 0x55, 0x5a, 0xf3, 0x32, 0xc3,
+ 0xd6, 0x42, 0xec, 0x43, 0x0e, 0x03, 0x57, 0x45, 0xf7, 0x35, 0x8d, 0x97,
+ 0x7a, 0xdf, 0x2d, 0xdf, 0xd6, 0x6d, 0xfd, 0x42, 0x2d, 0x34, 0x9c, 0x58,
+ 0x2a, 0x75, 0x2c, 0xb5, 0x15, 0xd9, 0xe8, 0xa1, 0x1b, 0x8a, 0xcc, 0xc8,
+ 0x20, 0x9f, 0x6e, 0x46, 0xee, 0x49, 0xac, 0xc8, 0xb7, 0xcd, 0xf1, 0xe4,
+ 0x72, 0x1d, 0x37, 0xd3, 0x0e, 0x80, 0x86, 0x09, 0xce, 0xc8, 0x93, 0x7d,
+ 0xfc, 0x1e, 0x35, 0xe2, 0x9e, 0x69, 0x60, 0x97, 0xa1, 0xe9, 0xbd, 0xee,
+ 0x8e, 0x97, 0xc0, 0x7b, 0x4a, 0xd7, 0xa9, 0xe6, 0xa6, 0x40, 0xb2, 0x47,
+ 0x68, 0xba, 0x1c, 0x39, 0x36, 0xca, 0x66, 0x71, 0x44, 0x52, 0x5e, 0x82,
+ 0xe8, 0x3c, 0xd9, 0x4e, 0x04, 0x30, 0x52, 0xb5, 0xbb, 0xc3, 0x1a, 0x2f,
+ 0xbf, 0x37, 0x5e, 0x6f, 0x4f, 0x96, 0x3a, 0xe3, 0xdb, 0xd1, 0x72, 0xbd,
+ 0x63, 0xd9, 0x8d, 0x54, 0xf5, 0x9a, 0xaa, 0xc6, 0x4b, 0xe5, 0xa8, 0x73,
+ 0xdc, 0xaf, 0xdb, 0x20, 0x13, 0xfa, 0x8d, 0xae, 0x23, 0x27, 0xf8, 0x8c,
+ 0x59, 0xbd, 0x28, 0x13, 0xe9, 0x97, 0xde, 0x07, 0x41, 0x2e, 0xc7, 0x64,
+ 0xe9, 0x7b, 0x63, 0xb3, 0x31, 0x59, 0x52, 0x8e, 0xec, 0xef, 0x37, 0xc0,
+ 0x9c, 0xb8, 0x54, 0xc2, 0x77, 0xbc, 0x43, 0x01, 0x32, 0xd2, 0xc9, 0xdf,
+ 0xe6, 0x26, 0xa5, 0xd7, 0x0f, 0xae, 0x37, 0x72, 0xe6, 0x47, 0x3d, 0xe6,
+ 0xac, 0x32, 0xe6, 0xf5, 0x38, 0x6c, 0x90, 0xfb, 0x1e, 0x04, 0x66, 0x21,
+ 0x49, 0xca, 0x94, 0xf3, 0xb6, 0x54, 0x30, 0xdf, 0x21, 0x68, 0xfa, 0x0c,
+ 0x46, 0x91, 0xec, 0x02, 0xeb, 0xfb, 0xfb, 0x35, 0x6f, 0xff, 0x66, 0xd9,
+ 0xe7, 0xb9, 0xad, 0xc8, 0xeb, 0x79, 0x63, 0x6d, 0x2d, 0x59, 0x9f, 0xc1,
+ 0x8a, 0xa2, 0x1c, 0xf5, 0x24, 0xcc, 0xfd, 0x02, 0x4c, 0x64, 0x54, 0x9a,
+ 0x13, 0xd5, 0xba, 0xa7, 0x85, 0xa4, 0x9c, 0xae, 0x28, 0x53, 0x84, 0xf2,
+ 0x92, 0x06, 0xb3, 0x0c, 0x9a, 0x53, 0x69, 0x0f, 0x5a, 0x4f, 0x16, 0xcc,
+ 0x4b, 0x9a, 0x48, 0x37, 0x8a, 0x2f, 0xa1, 0xb3, 0x82, 0x75, 0xa5, 0x11,
+ 0xc0, 0x72, 0xfd, 0x94, 0xfa, 0x7b, 0x0a, 0x06, 0x84, 0x40, 0x16, 0xbf,
+ 0xa3, 0xb7, 0xee, 0xcf, 0x6b, 0xad, 0xd9, 0xc3, 0x7d, 0x59, 0x8b, 0xb2,
+ 0x7d, 0x64, 0x73, 0x28, 0x32, 0x59, 0xb2, 0x7e, 0xc7, 0x5a, 0x6d, 0x1d,
+ 0x84, 0xcc, 0xf6, 0x45, 0x73, 0xe8, 0xd0, 0x73, 0x8c, 0x4a, 0x23, 0xd5,
+ 0x40, 0xd6, 0xdc, 0xff, 0x55, 0x0b, 0xb5, 0x30, 0xab, 0x05, 0x5d, 0x59,
+ 0x0f, 0xca, 0x72, 0x5a, 0x32, 0x74, 0x6b, 0xd2, 0xc0, 0x66, 0xa7, 0xea,
+ 0x15, 0x65, 0xa4, 0xba, 0x9f, 0x1f, 0x95, 0x2a, 0x0a, 0xc8, 0x90, 0x07,
+ 0xd2, 0x80, 0x64, 0xc6, 0xe4, 0xe0, 0x7d, 0xbb, 0xd4, 0xbd, 0x83, 0xe9,
+ 0xf3, 0x3f, 0x76, 0x82, 0xa0, 0x5f, 0x39, 0x18, 0xbb, 0x71, 0x77, 0x19,
+ 0x35, 0x7e, 0xe1, 0x7a, 0xfa, 0xac, 0x00, 0x3a, 0x40, 0xaf, 0xc8, 0x4d,
+ 0x45, 0x1d, 0x33, 0xed, 0x3b, 0x09, 0xfa, 0x58, 0x8f, 0xc5, 0x9c, 0x7a,
+ 0xd8, 0x32, 0xec, 0x7c, 0x6c, 0x31, 0xf7, 0xb2, 0xf2, 0xbd, 0x31, 0xf3,
+ 0x70, 0x56, 0xa0, 0x37, 0x4d, 0xdd, 0x77, 0xb1, 0x1e, 0x8a, 0xe0, 0x6b,
+ 0x49, 0x8f, 0xb9, 0xb5, 0xb8, 0x36, 0xe6, 0x09, 0xe7, 0x30, 0x27, 0x8e,
+ 0x27, 0x7b, 0xb7, 0xdf, 0x54, 0xfb, 0x5a, 0x45, 0x59, 0xbb, 0xde, 0x79,
+ 0x93, 0xab, 0xd2, 0x74, 0xe3, 0x16, 0x18, 0xd0, 0x9d, 0xdd, 0x6c, 0x0c,
+ 0x45, 0x06, 0x31, 0xbd, 0xa8, 0xc1, 0x6a, 0xcd, 0x8f, 0x03, 0x47, 0xae,
+ 0x06, 0xed, 0x24, 0x35, 0x13, 0xb9, 0x9e, 0x06, 0x5d, 0xe1, 0x87, 0x22,
+ 0x62, 0x0c, 0xec, 0xf2, 0x02, 0x33, 0x16, 0xb3, 0xef, 0x0e, 0x41, 0x03,
+ 0xd5, 0x37, 0x47, 0x87, 0x45, 0x9d, 0x6d, 0xf6, 0x1c, 0x00, 0x1d, 0xf3,
+ 0x57, 0x83, 0x57, 0x61, 0x29, 0x04, 0xc6, 0xfb, 0x60, 0x77, 0x3a, 0x2e,
+ 0xf3, 0xbe, 0x0b, 0x6e, 0x35, 0xa8, 0x9e, 0xf3, 0x2a, 0xbc, 0x1a, 0x1c,
+ 0x10, 0xba, 0x99, 0x2d, 0x69, 0x06, 0xf0, 0x3d, 0x9d, 0x3b, 0xf7, 0xeb,
+ 0x00, 0xd7, 0x03, 0x5e, 0x97, 0xc7, 0xbd, 0xde, 0x8f, 0x00, 0xbf, 0x40,
+ 0xff, 0xdd, 0x14, 0x2d, 0x57, 0x79, 0xf4, 0x1e, 0x3c, 0xe0, 0x11, 0x66,
+ 0xc6, 0x29, 0x35, 0x4a, 0x80, 0x15, 0xf9, 0x79, 0x7a, 0x1a, 0x7b, 0xf8,
+ 0x39, 0x30, 0x16, 0x73, 0xf2, 0x6d, 0x14, 0x53, 0x75, 0x9c, 0x1f, 0xd6,
+ 0x83, 0x07, 0x37, 0x58, 0x0d, 0xbe, 0xde, 0xa6, 0xf3, 0xee, 0xaa, 0xd8,
+ 0x37, 0xf1, 0x37, 0x78, 0xf0, 0xd0, 0x0d, 0x5c, 0x70, 0x81, 0x2c, 0xed,
+ 0xf7, 0x4f, 0x00, 0x2c, 0xd7, 0xdd, 0xe7, 0x28, 0x7a, 0xf0, 0x60, 0x06,
+ 0xf0, 0xed, 0x90, 0x4e, 0xe2, 0x6e, 0x33, 0xb2, 0x9c, 0xf6, 0x24, 0xa5,
+ 0x87, 0xc7, 0x41, 0x98, 0xa1, 0xf7, 0x07, 0x01, 0x4e, 0xee, 0xe7, 0xbd,
+ 0x6f, 0x7a, 0xf6, 0xf0, 0x78, 0xe0, 0x7d, 0x43, 0x11, 0x3a, 0x5b, 0x67,
+ 0x54, 0x5a, 0xcc, 0x75, 0xb3, 0xf7, 0x98, 0x07, 0x0f, 0xe6, 0x08, 0x13,
+ 0xee, 0xe4, 0x20, 0xc2, 0xf4, 0x21, 0xe5, 0xac, 0xea, 0xc2, 0x83, 0x07,
+ 0x27, 0x38, 0xe6, 0x40, 0x1f, 0x06, 0xf3, 0x7a, 0x9d, 0xd6, 0xdd, 0x5b,
+ 0x09, 0xc4, 0x45, 0xaf, 0xc2, 0xcf, 0xf5, 0x6d, 0xaa, 0x1e, 0x7e, 0x6e,
+ 0x5c, 0xf2, 0x63, 0xb1, 0xd3, 0xf4, 0x8b, 0xe2, 0x41, 0x59, 0x1d, 0xe0,
+ 0x7b, 0x02, 0x17, 0x92, 0x4c, 0xc4, 0x2f, 0xf0, 0xcf, 0x3d, 0x35, 0x0f,
+ 0x3f, 0x35, 0x78, 0xdf, 0x67, 0x2e, 0x2a, 0xae, 0x06, 0x77, 0xee, 0x87,
+ 0xda, 0x31, 0xf1, 0xb9, 0xe7, 0xe4, 0xe1, 0xc7, 0xc6, 0xff, 0x00, 0x2f,
+ 0x51, 0xc1, 0x57, 0x1e, 0x94, 0x00, 0x00
+};
+unsigned int splash_bmp_gz_len = 3859;
diff --git a/board/ti/logic/splash-480x272.h b/board/ti/logic/splash-480x272.h
new file mode 100644
index 0000000000..0d249e7936
--- /dev/null
+++ b/board/ti/logic/splash-480x272.h
@@ -0,0 +1,408 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Development <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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
+ */
+
+/*
+ * Splash Screen Image
+ *
+ * To update this image, perform the following steps to convert your
+ * image to RGB565, compress with gzip, and format as C code.
+ * 1) Open your image in GIMP
+ * 2) Select File -> Save as...
+ * 3) Enter splash.bmp and select Save
+ * 4) On the "Save as BMP" dialog, open the "Advanced Options" section
+ * 5) Select "R5 G6 B5" under the "16 bits" section and select Save
+ * 6) At a prompt, run the following commands:
+ * gzip splash.bmp
+ * xxd -i splash.bmp.gz > splash.h
+ * 7) Replace the code below with the contents of splash.h
+ */
+unsigned char splash_bmp_gz[] = {
+ 0x1f, 0x8b, 0x08, 0x08, 0xbe, 0x32, 0x9b, 0x4e, 0x00, 0x03, 0x73, 0x70,
+ 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x62, 0x6d, 0x70, 0x00, 0xed, 0xdd, 0x4f,
+ 0x48, 0x1b, 0x6b, 0xbf, 0xc0, 0xf1, 0xbc, 0x5c, 0xe1, 0x0e, 0xdc, 0x2e,
+ 0xc2, 0x6d, 0xa1, 0x81, 0x16, 0xde, 0x04, 0x2c, 0x18, 0xb0, 0x60, 0xa0,
+ 0x0b, 0x03, 0x6e, 0x12, 0xc8, 0x0b, 0x06, 0x5c, 0x34, 0x1c, 0xe1, 0x28,
+ 0xed, 0xc2, 0x23, 0x2d, 0x14, 0xe9, 0x42, 0xc4, 0x85, 0x04, 0x37, 0x41,
+ 0x5c, 0x88, 0x74, 0x21, 0x41, 0xa8, 0xc4, 0xb3, 0x68, 0xd1, 0x82, 0x97,
+ 0xb8, 0x28, 0xc4, 0x85, 0x60, 0x36, 0x42, 0x5c, 0x14, 0x22, 0x1c, 0x21,
+ 0x07, 0x5a, 0x48, 0x2e, 0xb4, 0x90, 0x42, 0x2f, 0x64, 0xe1, 0x22, 0x17,
+ 0xbc, 0xd0, 0x9b, 0x31, 0x67, 0x9a, 0x99, 0xc9, 0xfc, 0x79, 0x9e, 0x49,
+ 0xd4, 0xbe, 0x2f, 0xdf, 0xcf, 0xe0, 0xe1, 0x80, 0xf9, 0xf3, 0x8c, 0x9d,
+ 0xdf, 0x3c, 0xff, 0x7e, 0xcf, 0x33, 0xf1, 0x89, 0x7f, 0xfc, 0xdf, 0xbf,
+ 0xf9, 0x54, 0xff, 0x68, 0xfd, 0x8c, 0xb6, 0x7e, 0xfe, 0xfb, 0x6f, 0x3e,
+ 0x9f, 0xbf, 0xf5, 0xf3, 0x37, 0x9f, 0xdf, 0x77, 0xf9, 0x9b, 0xd6, 0xef,
+ 0xff, 0xf3, 0x3f, 0x7c, 0x97, 0x3f, 0x3f, 0xfc, 0x6f, 0xeb, 0x75, 0xff,
+ 0xee, 0xf3, 0xfd, 0xdd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7a, 0x66,
+ 0x94, 0xc1, 0x50, 0x3d, 0x3a, 0x9e, 0x6c, 0x1f, 0x43, 0xf1, 0xdd, 0xc8,
+ 0x40, 0x28, 0xa6, 0xdc, 0x74, 0xa9, 0x00, 0x38, 0x8b, 0x29, 0x27, 0xd1,
+ 0xd3, 0xf4, 0x64, 0xfe, 0x75, 0x79, 0xb9, 0x51, 0x6c, 0x6a, 0xc7, 0xfd,
+ 0xfa, 0xaf, 0xa5, 0xdb, 0xdb, 0x8d, 0xb4, 0x12, 0x3f, 0x0e, 0xdc, 0x74,
+ 0x09, 0x01, 0x58, 0x89, 0x29, 0xb7, 0x66, 0x9b, 0x47, 0xbf, 0x37, 0xbf,
+ 0xdb, 0x2a, 0x36, 0x0f, 0x2b, 0xb7, 0xb7, 0xc7, 0x93, 0xd4, 0xc5, 0xc0,
+ 0xcf, 0x65, 0x2d, 0x35, 0x5a, 0xb2, 0x8f, 0x5c, 0xa3, 0xa5, 0xf2, 0xfe,
+ 0xc2, 0x60, 0xe8, 0xa6, 0x4b, 0x0c, 0x40, 0x15, 0x53, 0xe6, 0xd7, 0x45,
+ 0x63, 0x57, 0x73, 0xaf, 0x36, 0xbf, 0x4e, 0x0c, 0x03, 0x3f, 0x03, 0x99,
+ 0xda, 0xb7, 0x63, 0xac, 0xde, 0x48, 0xd3, 0x23, 0x06, 0x6e, 0xde, 0x8c,
+ 0x32, 0x31, 0xf7, 0xa9, 0x2a, 0x1f, 0xc3, 0x5b, 0x95, 0x6f, 0xd3, 0x37,
+ 0x5d, 0x76, 0x00, 0x3e, 0xdf, 0x71, 0xe0, 0xf1, 0xfa, 0x72, 0x43, 0x3e,
+ 0x86, 0x27, 0xf3, 0x89, 0xf0, 0x4d, 0x97, 0xbd, 0x23, 0xa6, 0x7c, 0x09,
+ 0x9e, 0x44, 0xd7, 0x52, 0x1f, 0xa6, 0x27, 0xe6, 0x3e, 0x4c, 0xbf, 0x48,
+ 0x9e, 0x44, 0x3f, 0x07, 0x7a, 0x1f, 0x71, 0x0b, 0xb6, 0xfe, 0x3a, 0xbb,
+ 0x91, 0x17, 0xc9, 0x0f, 0xd3, 0x0f, 0xe7, 0x1e, 0xce, 0xed, 0xa5, 0xd6,
+ 0x52, 0x4a, 0x3c, 0x11, 0xce, 0xf8, 0x83, 0x7d, 0x28, 0xb1, 0xb5, 0x98,
+ 0x32, 0x10, 0x52, 0xe2, 0x6b, 0xa9, 0x6f, 0xad, 0xf3, 0xf8, 0x76, 0x79,
+ 0x1e, 0xb4, 0x75, 0xe0, 0xe6, 0x5d, 0x74, 0x32, 0x2f, 0x1f, 0xc1, 0xf7,
+ 0xeb, 0x1f, 0x7a, 0xa8, 0x85, 0xf7, 0x52, 0x23, 0x2b, 0x8d, 0xb4, 0xdb,
+ 0xe1, 0x6f, 0xbd, 0xe6, 0x81, 0xcb, 0x7d, 0xa2, 0x1e, 0xf5, 0xaf, 0x34,
+ 0x8f, 0x3e, 0x55, 0xb7, 0x75, 0x77, 0xa1, 0xed, 0xc6, 0xa7, 0x6a, 0xf3,
+ 0x68, 0x64, 0x45, 0x89, 0x07, 0x3d, 0x96, 0xef, 0x59, 0x78, 0x7f, 0xe1,
+ 0xa0, 0x70, 0x58, 0x59, 0x6e, 0xd4, 0x74, 0xe7, 0x5c, 0x6c, 0x8e, 0xd5,
+ 0x97, 0xca, 0x9b, 0x85, 0x46, 0x7a, 0x2d, 0xf5, 0xc6, 0x6f, 0xff, 0xee,
+ 0xc1, 0x50, 0xbb, 0xec, 0xea, 0x7f, 0x4f, 0xd3, 0x9f, 0x05, 0x62, 0x30,
+ 0xa6, 0x8c, 0x27, 0x1f, 0xaf, 0x8f, 0x96, 0x2e, 0xaa, 0x45, 0xdd, 0x6c,
+ 0xc0, 0x72, 0xe3, 0xb0, 0xb2, 0x98, 0x9f, 0x98, 0x1b, 0x10, 0x1c, 0x75,
+ 0x50, 0xe7, 0x13, 0x46, 0x56, 0x46, 0x56, 0xc6, 0x93, 0x62, 0xaf, 0xd7,
+ 0x1c, 0x07, 0xb4, 0xf2, 0x9a, 0x8f, 0x57, 0x0b, 0xc3, 0xb3, 0x6b, 0xa9,
+ 0x44, 0x98, 0xf9, 0x87, 0x9f, 0x9b, 0xb7, 0xde, 0xf0, 0x46, 0x36, 0xe3,
+ 0x70, 0x15, 0x3b, 0x59, 0x14, 0xbe, 0x63, 0xac, 0xa5, 0xec, 0x3e, 0x23,
+ 0xa4, 0xec, 0xa5, 0x9a, 0x47, 0x55, 0x87, 0xd9, 0xaf, 0xda, 0xf7, 0x40,
+ 0x69, 0x78, 0xf6, 0x37, 0xc9, 0x32, 0x7e, 0x8d, 0xfd, 0xb2, 0xb3, 0xed,
+ 0xda, 0x26, 0xb9, 0xa8, 0x9e, 0xe5, 0xc2, 0x36, 0xf3, 0x6a, 0x2f, 0x92,
+ 0x9d, 0xd7, 0x15, 0x9b, 0x27, 0x51, 0xe7, 0xef, 0xcb, 0xf8, 0x87, 0x67,
+ 0xa7, 0xca, 0x4e, 0xdf, 0x35, 0x56, 0x7f, 0xbc, 0x2e, 0x52, 0x13, 0x67,
+ 0xfc, 0x4b, 0x97, 0x9f, 0xf3, 0x3e, 0x2b, 0x77, 0xc6, 0x27, 0x51, 0xe7,
+ 0x73, 0x55, 0xef, 0x23, 0xe7, 0xb9, 0xbd, 0x14, 0xad, 0x81, 0x9f, 0x57,
+ 0xc6, 0xff, 0x6a, 0xe1, 0x42, 0xba, 0x37, 0x7c, 0x50, 0x10, 0xa9, 0x5d,
+ 0xba, 0xfd, 0xb2, 0x23, 0xfa, 0x0d, 0x76, 0x75, 0xc9, 0xbb, 0xe8, 0x66,
+ 0x41, 0xec, 0x13, 0x02, 0x25, 0xf1, 0xfa, 0xe8, 0x38, 0xf0, 0x3e, 0x5b,
+ 0x74, 0xb8, 0x23, 0x18, 0xd5, 0xbe, 0xdf, 0x2d, 0x7e, 0x9b, 0xee, 0x8e,
+ 0xe1, 0xf1, 0x64, 0xed, 0xc7, 0x6b, 0xb6, 0x1b, 0xef, 0x1c, 0xe3, 0x77,
+ 0x3c, 0x19, 0x10, 0xba, 0x73, 0x6e, 0x55, 0x5e, 0xb8, 0x9e, 0x45, 0xc6,
+ 0xdf, 0xbe, 0x0b, 0xcf, 0xaf, 0x8b, 0x9e, 0x6f, 0xdb, 0x6e, 0x44, 0xec,
+ 0x9c, 0x0f, 0x2b, 0x23, 0x2b, 0xa2, 0x6d, 0x01, 0x5c, 0xbf, 0x81, 0xd0,
+ 0x46, 0xd6, 0xbd, 0xe6, 0x31, 0x9a, 0x2a, 0x7b, 0xe9, 0x09, 0x8b, 0xc6,
+ 0x6f, 0xcd, 0x26, 0x7e, 0x87, 0x67, 0x9f, 0x4a, 0x94, 0xb3, 0xf6, 0xdd,
+ 0xbf, 0x22, 0xd2, 0x02, 0xac, 0x47, 0x0f, 0x2b, 0x72, 0x67, 0xaf, 0xea,
+ 0x6e, 0x21, 0xe8, 0xe3, 0x77, 0xd9, 0x21, 0x7e, 0x43, 0x4a, 0x23, 0xed,
+ 0xd4, 0x7e, 0x30, 0x2a, 0x36, 0x5f, 0x2d, 0x38, 0x97, 0xbf, 0xd7, 0xf8,
+ 0x5d, 0xcc, 0x6f, 0x64, 0xdf, 0xff, 0x38, 0x36, 0xb2, 0xe7, 0xb9, 0x83,
+ 0xc2, 0x68, 0xe9, 0x7e, 0x5d, 0x5f, 0x8a, 0x8b, 0xea, 0xad, 0x59, 0xb9,
+ 0x4f, 0xc7, 0x75, 0x3a, 0x89, 0x1e, 0x08, 0xd6, 0x6b, 0x9a, 0xc3, 0x8a,
+ 0x7c, 0x04, 0x8b, 0xd7, 0xbf, 0x56, 0xb5, 0xce, 0x69, 0x5a, 0xae, 0x84,
+ 0xaa, 0xb3, 0x5c, 0xc8, 0x25, 0x82, 0xd7, 0x52, 0x32, 0xf7, 0x84, 0x8e,
+ 0xee, 0x71, 0x00, 0xb1, 0xf8, 0x0d, 0x29, 0xef, 0xb3, 0xb2, 0xdf, 0xf5,
+ 0x72, 0xce, 0xe9, 0x0c, 0x7a, 0x8d, 0xdf, 0xdd, 0x48, 0xf7, 0xef, 0x62,
+ 0xca, 0x83, 0xf0, 0x50, 0xfc, 0xf1, 0xfa, 0x6b, 0x5d, 0x0b, 0x7f, 0x7e,
+ 0x7d, 0x86, 0xfe, 0xf0, 0x4f, 0x2b, 0xa4, 0x7c, 0x98, 0x5e, 0x72, 0xec,
+ 0x8f, 0x99, 0x6d, 0x55, 0x64, 0x5b, 0xd1, 0xfa, 0xf8, 0xad, 0x7d, 0xef,
+ 0xe4, 0x5d, 0x77, 0x1f, 0xdd, 0xf5, 0xef, 0xab, 0x85, 0xee, 0x12, 0x3c,
+ 0xa9, 0x57, 0x0a, 0x23, 0x2b, 0x0f, 0xe7, 0x86, 0x67, 0x87, 0x67, 0xf7,
+ 0x17, 0x1e, 0xed, 0x6c, 0x59, 0xd4, 0xa3, 0xe7, 0x39, 0xa7, 0x3a, 0x78,
+ 0x28, 0xde, 0x3d, 0x0e, 0x5f, 0x6c, 0x06, 0x4a, 0x1b, 0xd9, 0x89, 0xcb,
+ 0x4f, 0x1d, 0x9e, 0x3d, 0x4d, 0xdf, 0xd9, 0x09, 0x94, 0xba, 0x5f, 0xe5,
+ 0x2d, 0x7e, 0x83, 0xbe, 0x0d, 0x8b, 0xe8, 0xbd, 0xa8, 0x2e, 0xe6, 0x1b,
+ 0x69, 0xf5, 0xdb, 0x26, 0xe6, 0x36, 0xb2, 0x56, 0xbd, 0x62, 0x25, 0x6e,
+ 0x7f, 0x0e, 0xbd, 0xc6, 0x6f, 0xdd, 0xa1, 0xa5, 0xff, 0x9b, 0x5f, 0x1d,
+ 0x6d, 0xd0, 0x4a, 0x31, 0x99, 0x97, 0x1d, 0x55, 0x40, 0x6f, 0x32, 0xfe,
+ 0x97, 0x73, 0xe2, 0xa3, 0x4d, 0x6f, 0xfc, 0x8d, 0xf4, 0x93, 0x7a, 0xf7,
+ 0xd5, 0x63, 0xa7, 0x79, 0x24, 0x37, 0x92, 0xa5, 0x8f, 0xdf, 0xf3, 0xdc,
+ 0x49, 0xd4, 0xfa, 0xa8, 0xb7, 0x7e, 0xcc, 0x9f, 0x3b, 0x9e, 0x34, 0xf7,
+ 0xd5, 0xd4, 0x9c, 0x92, 0x67, 0xa6, 0x16, 0xc0, 0xdb, 0xc0, 0x9a, 0xee,
+ 0x6a, 0xd3, 0xf8, 0x57, 0xec, 0xca, 0x33, 0x18, 0x32, 0xf7, 0xfd, 0x8b,
+ 0xcd, 0xf7, 0xd9, 0x93, 0xa8, 0xb9, 0xce, 0x0e, 0x29, 0xab, 0x91, 0xfd,
+ 0x05, 0xe3, 0xdd, 0xc1, 0x5b, 0xfc, 0x3e, 0x9c, 0x33, 0x97, 0xee, 0x63,
+ 0xe5, 0xe5, 0x9c, 0x31, 0xbf, 0x2d, 0xe3, 0xff, 0x30, 0x6d, 0x6c, 0xd1,
+ 0x9f, 0xe7, 0x9c, 0xee, 0x94, 0xbd, 0xc6, 0xef, 0xd7, 0x98, 0xf3, 0xeb,
+ 0x62, 0xca, 0xab, 0x05, 0x2d, 0x5b, 0x5e, 0x76, 0x8c, 0x0c, 0xbd, 0x51,
+ 0xc7, 0x44, 0x03, 0x25, 0xb7, 0xb1, 0x50, 0xbd, 0x44, 0xf8, 0x2c, 0x27,
+ 0x3e, 0x96, 0x73, 0x96, 0x93, 0x29, 0x8d, 0x3e, 0x7e, 0x4f, 0xd3, 0xe2,
+ 0xef, 0x3b, 0x0e, 0x98, 0x7b, 0xa8, 0x8b, 0x79, 0xbb, 0x9c, 0x4e, 0xfd,
+ 0xd5, 0xa6, 0xc5, 0xa4, 0x75, 0x6f, 0x3a, 0xe8, 0x7b, 0x64, 0x6a, 0xcf,
+ 0x2f, 0x95, 0x87, 0x1c, 0xea, 0xb9, 0x07, 0x61, 0x7d, 0x2d, 0xec, 0x25,
+ 0x7e, 0x9f, 0x85, 0xcd, 0x6d, 0xf5, 0xf7, 0x59, 0xeb, 0xd1, 0xdd, 0xe3,
+ 0x80, 0x36, 0x56, 0x7f, 0xaf, 0xe6, 0x36, 0x63, 0x77, 0xd5, 0xf1, 0xab,
+ 0x52, 0xe2, 0x5a, 0xce, 0x0f, 0x59, 0x3c, 0xd7, 0xe9, 0x2c, 0xd7, 0xbe,
+ 0x9a, 0x86, 0xa5, 0x46, 0x1f, 0x94, 0x78, 0x45, 0xb0, 0x37, 0x5c, 0xb3,
+ 0xb8, 0x8e, 0xed, 0xe9, 0xe3, 0xd7, 0xbe, 0x56, 0xec, 0xe6, 0x5f, 0x31,
+ 0x7e, 0xeb, 0x46, 0xd6, 0xb9, 0x27, 0xf6, 0x22, 0x69, 0x8c, 0x93, 0xd1,
+ 0x92, 0x55, 0xbb, 0x6f, 0x2d, 0x55, 0xfb, 0x6e, 0x7c, 0xd5, 0x97, 0xa0,
+ 0xd3, 0xa7, 0x7e, 0x0e, 0x8c, 0xe9, 0xda, 0x26, 0x5e, 0xe2, 0xd7, 0x7c,
+ 0xbf, 0xd8, 0x77, 0x18, 0x99, 0x9a, 0x51, 0xd4, 0xf9, 0xf9, 0xcd, 0x82,
+ 0xdb, 0x4c, 0xf8, 0xf5, 0xc4, 0xaf, 0x3a, 0x42, 0xd2, 0x6e, 0x99, 0x5d,
+ 0x54, 0xbd, 0xcd, 0x3d, 0x40, 0xde, 0x1b, 0x7f, 0xa7, 0xcd, 0xd7, 0x90,
+ 0xa8, 0xef, 0xd4, 0xba, 0xe9, 0xd6, 0xac, 0x58, 0x6f, 0xf8, 0x5e, 0x4d,
+ 0x7c, 0x6e, 0xc1, 0x5b, 0xfc, 0x7e, 0x09, 0x1a, 0xc7, 0x42, 0x27, 0xf3,
+ 0x6e, 0x63, 0x52, 0x3e, 0xdf, 0x87, 0x69, 0x63, 0x1b, 0xa2, 0xbb, 0xd6,
+ 0x08, 0x29, 0xc6, 0x19, 0x9c, 0xad, 0x8a, 0xdb, 0x79, 0x7c, 0x09, 0x3e,
+ 0xe9, 0x29, 0x7e, 0xeb, 0x51, 0x63, 0x99, 0x1e, 0xbb, 0xc4, 0xdb, 0x1b,
+ 0xbf, 0xd5, 0x2c, 0x55, 0xb7, 0xeb, 0x89, 0x5f, 0x9f, 0xef, 0xdb, 0x74,
+ 0x4d, 0xf2, 0x5f, 0x0e, 0xbd, 0xd9, 0x8d, 0xe8, 0x5b, 0x7c, 0x32, 0x2d,
+ 0x56, 0xd5, 0xdb, 0xc0, 0xa9, 0x50, 0x6f, 0x58, 0xbc, 0x4f, 0xe4, 0x2d,
+ 0x7e, 0x5f, 0x1a, 0xfa, 0x8c, 0x17, 0x55, 0xb1, 0xfb, 0x85, 0x71, 0xa5,
+ 0xd5, 0xdd, 0xa2, 0xf9, 0xf7, 0x4a, 0x5c, 0x3f, 0x87, 0x53, 0x6c, 0x3a,
+ 0xb5, 0x9c, 0xdb, 0x7a, 0x8d, 0x5f, 0xe3, 0xb8, 0x73, 0xa0, 0xd4, 0xaf,
+ 0xec, 0xa6, 0xeb, 0x8a, 0x5f, 0x9f, 0xaf, 0x9d, 0xb1, 0xf7, 0xa9, 0xfa,
+ 0x96, 0x1a, 0xf8, 0x5a, 0xfc, 0xcf, 0x6f, 0xc6, 0x48, 0x73, 0x9e, 0x87,
+ 0xb0, 0xf2, 0xa0, 0xd5, 0x1b, 0x76, 0x9b, 0x1b, 0xde, 0x6e, 0xac, 0x5a,
+ 0xcc, 0x40, 0x58, 0xf1, 0x12, 0xbf, 0x41, 0x9f, 0xb1, 0x9e, 0x14, 0x3d,
+ 0x87, 0xe3, 0x80, 0x7e, 0x6c, 0xaa, 0xd8, 0x34, 0xcf, 0x92, 0x18, 0xe3,
+ 0x5b, 0xa4, 0x1f, 0xdf, 0x5b, 0xfc, 0x66, 0xfc, 0xfa, 0xf2, 0x54, 0x9b,
+ 0xee, 0x79, 0x19, 0xa2, 0xae, 0x2f, 0x7e, 0xbf, 0xc6, 0xda, 0xef, 0xe8,
+ 0x25, 0x87, 0x16, 0xe2, 0x1e, 0x9b, 0x56, 0xfb, 0xfe, 0xde, 0x74, 0x9a,
+ 0x87, 0xb0, 0xf3, 0x35, 0xe6, 0x96, 0xf3, 0x24, 0x7a, 0xe5, 0x78, 0x89,
+ 0xdf, 0x55, 0x43, 0x1b, 0xe2, 0x53, 0x55, 0x7c, 0xc4, 0xdb, 0xd8, 0x6b,
+ 0x36, 0xf6, 0x35, 0x7f, 0xf3, 0xeb, 0x7b, 0x07, 0xbf, 0xbb, 0x66, 0x3b,
+ 0xaa, 0x7a, 0x8b, 0x5f, 0xfd, 0x6f, 0xd5, 0xf6, 0x80, 0x7b, 0x1f, 0x40,
+ 0xd4, 0xf5, 0xc5, 0x6f, 0x48, 0x69, 0x8f, 0xee, 0x3f, 0xda, 0x09, 0x4a,
+ 0x96, 0x11, 0x5e, 0x74, 0xaf, 0x50, 0xf8, 0xb5, 0xe4, 0x6d, 0x0e, 0xfe,
+ 0xbf, 0x1c, 0xe7, 0x86, 0xef, 0xd7, 0xc5, 0x72, 0x64, 0xbd, 0xc4, 0xef,
+ 0x87, 0x69, 0xfd, 0x37, 0xb9, 0xf5, 0x19, 0xf5, 0x56, 0x23, 0xfa, 0x96,
+ 0xc3, 0x62, 0x3e, 0xa8, 0xfb, 0x5d, 0xc2, 0x30, 0x12, 0xdc, 0x3c, 0x12,
+ 0x69, 0xcb, 0x7e, 0x0e, 0xf4, 0x12, 0xbf, 0x0d, 0x43, 0xf6, 0xc9, 0x43,
+ 0xe9, 0x96, 0x90, 0xbd, 0xeb, 0x8b, 0x5f, 0xed, 0x9e, 0x28, 0x73, 0x17,
+ 0x85, 0x57, 0x33, 0x8a, 0xd5, 0xea, 0x04, 0xf9, 0x36, 0x74, 0xdb, 0x1b,
+ 0xff, 0xfe, 0xc2, 0x7d, 0xdb, 0xde, 0xf0, 0x9e, 0xed, 0x7a, 0x03, 0x3d,
+ 0x2f, 0xf1, 0x6b, 0xbc, 0xee, 0xed, 0xd7, 0x35, 0x74, 0xcb, 0xf8, 0xf5,
+ 0x99, 0x10, 0x5b, 0x15, 0xfd, 0x35, 0xb7, 0x96, 0xd2, 0x7f, 0xea, 0x88,
+ 0x43, 0x59, 0x82, 0x3f, 0xfe, 0x6f, 0x20, 0xd4, 0xcb, 0xf8, 0xf3, 0x1d,
+ 0xdd, 0xb9, 0x17, 0x9b, 0xa2, 0x3d, 0x0e, 0x11, 0xd7, 0x19, 0xbf, 0x43,
+ 0x71, 0xf5, 0x1d, 0xbf, 0xf7, 0xb5, 0xfc, 0xb0, 0x66, 0xec, 0x01, 0x6a,
+ 0xa6, 0xca, 0xde, 0x73, 0x68, 0xd4, 0x4c, 0x69, 0xeb, 0x75, 0xc3, 0xe7,
+ 0x42, 0xf3, 0xc0, 0x5e, 0xe2, 0xf7, 0x3c, 0xd7, 0x79, 0xcf, 0x93, 0xba,
+ 0x5c, 0xce, 0xa6, 0x7e, 0xbe, 0xe6, 0x5e, 0x4d, 0x3f, 0x3b, 0x74, 0x6b,
+ 0x56, 0x5f, 0x7a, 0xbb, 0xfe, 0x5c, 0x22, 0xbc, 0x59, 0x68, 0x1e, 0xb5,
+ 0x8f, 0x3f, 0x8f, 0x02, 0x25, 0xfd, 0x88, 0x97, 0x5c, 0xfc, 0xce, 0x28,
+ 0x77, 0x8b, 0x9d, 0xf7, 0x6e, 0x55, 0x9c, 0xd6, 0x21, 0xca, 0xd2, 0xe2,
+ 0x57, 0xa6, 0x6d, 0xa2, 0xf2, 0x12, 0xbf, 0x0f, 0xc2, 0xed, 0x36, 0x8d,
+ 0xd8, 0xfd, 0x1a, 0xbd, 0x18, 0x08, 0x59, 0xc5, 0x5a, 0x4d, 0xea, 0xdf,
+ 0xab, 0xdb, 0x49, 0xd4, 0x6a, 0x15, 0xe0, 0xa8, 0xd0, 0x68, 0xaa, 0x7c,
+ 0xfc, 0x06, 0x7d, 0xfa, 0xbe, 0xb7, 0xec, 0x75, 0xaf, 0xef, 0x01, 0x2f,
+ 0x37, 0xf4, 0x23, 0x58, 0xfb, 0xba, 0x6c, 0xcc, 0xa2, 0xed, 0xa8, 0xc0,
+ 0x49, 0xd4, 0x3e, 0x93, 0x45, 0x2e, 0x7e, 0xdf, 0x18, 0xfa, 0xdb, 0x07,
+ 0x85, 0xfe, 0xf5, 0x7e, 0x3b, 0xf1, 0x7b, 0x9e, 0x4b, 0x84, 0x9f, 0xfd,
+ 0x38, 0x56, 0x23, 0x03, 0xa1, 0x8c, 0xdf, 0xe9, 0x7b, 0xbc, 0xc4, 0xef,
+ 0xe7, 0xbf, 0xea, 0x84, 0x89, 0x3e, 0xb6, 0xff, 0x61, 0x2d, 0x11, 0xb6,
+ 0xbe, 0xf2, 0xe4, 0x66, 0x82, 0xad, 0xec, 0xa5, 0xcc, 0x39, 0xba, 0x63,
+ 0x75, 0x91, 0x3d, 0xee, 0x7a, 0x8d, 0xdf, 0xa5, 0xb2, 0x5c, 0xbf, 0x4b,
+ 0x9f, 0x33, 0x6d, 0x1c, 0xa3, 0x32, 0x46, 0xf6, 0x73, 0x9b, 0xd6, 0xe0,
+ 0xbb, 0xa8, 0xfd, 0x2e, 0x25, 0x72, 0xf1, 0x9b, 0x31, 0xc4, 0xef, 0x64,
+ 0x5e, 0xe6, 0x2c, 0xdc, 0x68, 0xf1, 0x5b, 0x6c, 0x3e, 0x6d, 0x74, 0x8e,
+ 0xe5, 0xc6, 0xfd, 0xfa, 0xa7, 0xea, 0x54, 0xf9, 0x2c, 0xb7, 0x67, 0xb3,
+ 0xeb, 0x80, 0x97, 0xf8, 0xd5, 0xce, 0x43, 0x76, 0x2e, 0x12, 0xf2, 0xec,
+ 0xe2, 0xb7, 0x1f, 0x57, 0x8f, 0x9a, 0x57, 0xad, 0x6f, 0x9d, 0x8b, 0x8d,
+ 0xe0, 0xfe, 0x9c, 0xf1, 0xfb, 0xb4, 0x61, 0xce, 0xa3, 0xd6, 0xfc, 0x73,
+ 0xc5, 0xaf, 0xbd, 0xa5, 0xb2, 0x55, 0xfe, 0x9d, 0x97, 0xf8, 0x7d, 0x43,
+ 0xfc, 0x5e, 0x1b, 0xbb, 0xf8, 0x0d, 0x94, 0xfa, 0xf3, 0xf9, 0x5f, 0x82,
+ 0x23, 0x2b, 0xda, 0x88, 0x8e, 0x7d, 0x1b, 0x54, 0xcf, 0x4b, 0xfc, 0xea,
+ 0x5b, 0xeb, 0xaf, 0xcb, 0x72, 0xed, 0x67, 0xfd, 0xd8, 0x97, 0xb1, 0xfd,
+ 0xac, 0xcf, 0x09, 0xd9, 0x6e, 0xd8, 0xad, 0xc0, 0x71, 0x6a, 0x3f, 0x77,
+ 0x67, 0x74, 0x39, 0xc7, 0xaf, 0xbe, 0xc5, 0xb2, 0x59, 0x08, 0xca, 0x9c,
+ 0x86, 0x0b, 0x2d, 0x7e, 0xb7, 0x1b, 0x17, 0xd5, 0x7b, 0x35, 0xed, 0xb8,
+ 0xa8, 0xde, 0xaf, 0xeb, 0xfb, 0xeb, 0x77, 0x76, 0xcc, 0xe3, 0x1e, 0x5e,
+ 0xe2, 0xf7, 0x4b, 0xf0, 0xde, 0xe5, 0x49, 0xca, 0xe5, 0xe3, 0xc2, 0x8b,
+ 0xab, 0x8e, 0x5f, 0xf5, 0xfa, 0xd6, 0xea, 0xe0, 0x62, 0x53, 0xe4, 0x2a,
+ 0xf0, 0x32, 0x7e, 0xa5, 0x5f, 0x6f, 0x37, 0x56, 0x97, 0xdb, 0x07, 0xe2,
+ 0xf6, 0x76, 0xe7, 0xbd, 0xc6, 0xf1, 0x2b, 0xe3, 0xac, 0x94, 0xdd, 0x68,
+ 0xcc, 0xf3, 0xc8, 0x54, 0xf9, 0xb0, 0x62, 0x7d, 0x74, 0xe7, 0x5f, 0x38,
+ 0xc5, 0x6f, 0x48, 0xd1, 0xaf, 0xaf, 0xee, 0x65, 0x0c, 0xb1, 0x9b, 0x16,
+ 0xbf, 0x67, 0xb9, 0x81, 0xd0, 0xa0, 0xee, 0x48, 0x84, 0xeb, 0xd1, 0x5b,
+ 0xb3, 0x8b, 0x79, 0x2d, 0x8a, 0xcd, 0x39, 0x2a, 0x5e, 0xe2, 0x37, 0x11,
+ 0x6e, 0xbf, 0x47, 0x66, 0x1e, 0x00, 0xde, 0xd8, 0xc5, 0xef, 0x41, 0xa1,
+ 0x1f, 0x9f, 0xfe, 0x2c, 0x7c, 0x67, 0xa7, 0x73, 0x7f, 0xbf, 0xaa, 0xfa,
+ 0xd7, 0x38, 0xd2, 0x64, 0xb7, 0x2f, 0x87, 0x35, 0xe3, 0xfc, 0xd9, 0x6b,
+ 0x43, 0xdb, 0xdb, 0x98, 0x3d, 0x69, 0x37, 0x22, 0x10, 0x6c, 0xc5, 0x86,
+ 0xdd, 0xd1, 0x3d, 0x32, 0xe4, 0x3c, 0x7f, 0x74, 0xa6, 0x1b, 0x47, 0x5f,
+ 0x6e, 0xf4, 0x73, 0x1f, 0x4f, 0xb7, 0xf1, 0xe7, 0x70, 0x52, 0x5b, 0xbd,
+ 0x65, 0x6c, 0x33, 0x78, 0x89, 0xdf, 0xf1, 0xcb, 0x3d, 0xbe, 0xb6, 0x6d,
+ 0x7b, 0x1c, 0xe8, 0x1f, 0xbb, 0xf8, 0x95, 0x9d, 0x67, 0xe8, 0xd6, 0xbd,
+ 0x4e, 0x58, 0x2c, 0x87, 0xd2, 0x4b, 0xfc, 0x1a, 0x57, 0x09, 0x39, 0xcd,
+ 0xd4, 0x9a, 0x3d, 0x37, 0xe4, 0x6f, 0x6c, 0x1a, 0xc6, 0x7c, 0x07, 0x42,
+ 0xfa, 0xb9, 0x6c, 0xb1, 0xfc, 0x0d, 0x37, 0xce, 0xf1, 0x6b, 0xcc, 0xe2,
+ 0xee, 0x67, 0xfb, 0xd3, 0x7d, 0xfe, 0x37, 0x11, 0x6e, 0x9f, 0xad, 0x31,
+ 0xe7, 0xda, 0x4b, 0xfc, 0xb6, 0x33, 0xfa, 0x0e, 0x2b, 0xac, 0xe3, 0xbf,
+ 0x7a, 0x89, 0xb0, 0xfe, 0xca, 0xef, 0xe8, 0xad, 0xed, 0xa3, 0xee, 0x56,
+ 0xda, 0xbd, 0x5f, 0xd4, 0xa7, 0xaa, 0x48, 0x06, 0x96, 0x97, 0xf8, 0xfd,
+ 0x12, 0xd4, 0x67, 0x4d, 0xc8, 0x5c, 0x39, 0xc6, 0xcc, 0x0f, 0xe3, 0x88,
+ 0x4b, 0x4c, 0xd1, 0xaf, 0xf3, 0x77, 0xdf, 0x2d, 0x52, 0x84, 0x73, 0xfc,
+ 0x1a, 0xfb, 0xd2, 0x7f, 0x1e, 0x5d, 0x6f, 0xfe, 0x64, 0xfb, 0xee, 0x51,
+ 0x35, 0x64, 0x81, 0xcb, 0xc7, 0x6f, 0x4c, 0x69, 0xf7, 0xe2, 0xe5, 0x56,
+ 0x7d, 0xc3, 0x1b, 0xe3, 0x7a, 0x55, 0xcd, 0x85, 0x50, 0xa4, 0xd9, 0x51,
+ 0xe2, 0x7f, 0x76, 0xed, 0x6f, 0xa1, 0x12, 0x6b, 0x93, 0x7b, 0x5b, 0x7f,
+ 0x64, 0xcc, 0xbe, 0x16, 0xcd, 0x1f, 0xfb, 0x1c, 0x30, 0xae, 0x17, 0x30,
+ 0xb7, 0xef, 0x8d, 0xbb, 0x69, 0xdd, 0xd9, 0x11, 0x2d, 0x8d, 0x3d, 0xe7,
+ 0xf8, 0x8d, 0x29, 0xfa, 0x11, 0x68, 0xb9, 0x9e, 0x80, 0x33, 0x91, 0xf8,
+ 0xd5, 0xf2, 0x45, 0xf5, 0x3d, 0x7d, 0xf9, 0xf8, 0xd5, 0xda, 0x42, 0xf4,
+ 0x7e, 0xaf, 0x43, 0xc6, 0x6f, 0xb5, 0xaf, 0xa2, 0xf7, 0xd5, 0x9b, 0x89,
+ 0xf0, 0x79, 0xce, 0x6e, 0xdf, 0x44, 0xb1, 0x4f, 0xf5, 0x16, 0xbf, 0x7b,
+ 0x86, 0x5c, 0xc7, 0xfb, 0x75, 0xf7, 0x15, 0xed, 0x2a, 0xe3, 0x6a, 0xbd,
+ 0xa9, 0xb2, 0xb9, 0xbe, 0x7b, 0x6e, 0x58, 0x17, 0x51, 0x6c, 0xf6, 0x7e,
+ 0x4d, 0xba, 0xad, 0x1f, 0x34, 0xb6, 0x07, 0x64, 0xe7, 0xc2, 0xec, 0x89,
+ 0xc4, 0xef, 0x1b, 0x7f, 0x7b, 0x27, 0x3a, 0xfd, 0x5e, 0x96, 0xb2, 0xf1,
+ 0x1b, 0xfb, 0x6b, 0xc5, 0xf4, 0x16, 0xad, 0xe7, 0x6b, 0x11, 0x52, 0xba,
+ 0x77, 0xd1, 0x30, 0x8e, 0xc2, 0x8a, 0xcb, 0xb4, 0x7a, 0xbc, 0x56, 0xb5,
+ 0x79, 0x5b, 0xcd, 0x72, 0x0f, 0xc3, 0x6e, 0xde, 0xe2, 0x37, 0xe3, 0x7f,
+ 0x6d, 0xc8, 0x16, 0x39, 0x28, 0xb8, 0xf7, 0x56, 0x27, 0xe6, 0x8c, 0x77,
+ 0x1a, 0xab, 0xfe, 0xa6, 0x71, 0x37, 0x8c, 0x8b, 0xaa, 0x5d, 0x16, 0x87,
+ 0x28, 0xb7, 0xf8, 0x4d, 0x84, 0x8d, 0x63, 0x06, 0xfd, 0x6a, 0x85, 0x8a,
+ 0xc4, 0xaf, 0x36, 0xff, 0xbc, 0xdf, 0x43, 0xfc, 0x6a, 0x2d, 0x16, 0xa7,
+ 0x5d, 0x43, 0xd0, 0x4f, 0xfa, 0x31, 0xcf, 0x36, 0x2f, 0xbb, 0xf8, 0xc6,
+ 0x5c, 0x77, 0xa6, 0xbc, 0x5b, 0x14, 0x1b, 0xff, 0xf1, 0xba, 0x7f, 0xce,
+ 0xf0, 0xac, 0xf1, 0xfb, 0x26, 0xf3, 0xce, 0xf3, 0xc0, 0x0f, 0x4d, 0xd1,
+ 0x6b, 0x5d, 0xd7, 0xed, 0x46, 0x8c, 0xfb, 0x64, 0x6d, 0x55, 0x9c, 0xc7,
+ 0xe0, 0x62, 0xca, 0xc8, 0x8a, 0x53, 0xde, 0x82, 0xfb, 0xfe, 0x39, 0xe6,
+ 0xa7, 0xb7, 0x3e, 0x5e, 0xb7, 0xff, 0xbb, 0xcd, 0x28, 0x77, 0x76, 0xc4,
+ 0xf6, 0xaf, 0x16, 0x89, 0xdf, 0x07, 0x7f, 0xdd, 0x3b, 0xf4, 0x23, 0xd0,
+ 0x72, 0xf1, 0xfb, 0x6d, 0xba, 0xfd, 0x37, 0xed, 0x5f, 0xbb, 0x01, 0x6e,
+ 0xcc, 0x3b, 0x26, 0xff, 0x91, 0x0d, 0x4a, 0x7f, 0xc6, 0xd7, 0x98, 0xfb,
+ 0xce, 0xd0, 0xa2, 0xa3, 0xa9, 0x5e, 0xe3, 0x37, 0xa6, 0x98, 0x7b, 0xdd,
+ 0xa3, 0x25, 0xbb, 0x9c, 0x8b, 0xb7, 0x81, 0xf9, 0x75, 0x73, 0x2b, 0xdf,
+ 0x6e, 0x7d, 0xc2, 0x88, 0x69, 0x5f, 0x2d, 0xa7, 0xbd, 0xe2, 0x76, 0x23,
+ 0x6a, 0x26, 0x49, 0xcd, 0xa1, 0xf6, 0x71, 0x8f, 0xdf, 0xb7, 0x16, 0xfb,
+ 0xf0, 0x59, 0xcf, 0xc4, 0x0c, 0x84, 0xda, 0xbd, 0xfe, 0xc5, 0xbc, 0xfb,
+ 0x8c, 0xb7, 0x48, 0xfc, 0x6a, 0xeb, 0x35, 0xf4, 0x7f, 0x35, 0x99, 0xf8,
+ 0xbd, 0x35, 0xdb, 0xbe, 0xd7, 0xd9, 0xed, 0x05, 0x88, 0xab, 0xf0, 0x22,
+ 0xa9, 0xbf, 0x92, 0x0f, 0x0a, 0xb2, 0x77, 0xce, 0xc1, 0x90, 0xc8, 0x73,
+ 0x45, 0x8c, 0x2b, 0xf3, 0x9c, 0x78, 0x8d, 0x5f, 0xb5, 0xed, 0x69, 0x6e,
+ 0xbd, 0x57, 0x9b, 0xb7, 0xb7, 0x95, 0xb8, 0xfe, 0x9b, 0x63, 0x4a, 0x22,
+ 0xbc, 0xbf, 0xd0, 0xfd, 0x6c, 0x54, 0xfb, 0x76, 0x6a, 0xc6, 0xdf, 0xfd,
+ 0x14, 0x93, 0x83, 0x82, 0xf9, 0x89, 0x3f, 0xc7, 0x81, 0x70, 0xf2, 0x5c,
+ 0xb7, 0x27, 0xa7, 0xdd, 0xf3, 0x10, 0x44, 0xf6, 0x8f, 0xed, 0xde, 0x07,
+ 0x77, 0xb9, 0x31, 0xbf, 0xbe, 0x1b, 0x99, 0x31, 0xcc, 0x6d, 0xe9, 0x73,
+ 0x53, 0x2f, 0xaa, 0x6e, 0x3d, 0x73, 0xf7, 0xf8, 0x3d, 0x0e, 0x7c, 0xac,
+ 0x74, 0xff, 0x4b, 0x89, 0xc6, 0xef, 0xe7, 0x40, 0x27, 0x87, 0xc6, 0x78,
+ 0xf7, 0x52, 0x9f, 0x00, 0x19, 0x52, 0x82, 0x3e, 0xf5, 0xbf, 0x19, 0xff,
+ 0x8c, 0x12, 0x53, 0xd8, 0xdb, 0xae, 0x9f, 0x06, 0x75, 0x2b, 0x56, 0x0f,
+ 0x0a, 0x72, 0xb9, 0x87, 0x19, 0xff, 0xfe, 0xc2, 0xbd, 0xce, 0x05, 0xe9,
+ 0x40, 0x7c, 0x47, 0x51, 0xef, 0xf1, 0xab, 0xde, 0x8b, 0xba, 0xf7, 0xf1,
+ 0xa9, 0x36, 0x97, 0xca, 0x93, 0x79, 0xb5, 0x55, 0xdb, 0x48, 0x9f, 0xe7,
+ 0x02, 0x25, 0xab, 0x1e, 0xfa, 0x41, 0xc1, 0x69, 0xb4, 0x25, 0x11, 0xb6,
+ 0x7a, 0x16, 0xf2, 0x61, 0x65, 0xb3, 0x30, 0xbf, 0x7e, 0x9a, 0x3e, 0x4d,
+ 0xcf, 0xaf, 0x6f, 0x16, 0xcc, 0x75, 0x66, 0xb1, 0x69, 0x7d, 0xc6, 0x62,
+ 0xcf, 0x5f, 0x98, 0xe8, 0xda, 0x01, 0x5a, 0x9d, 0x3d, 0x1f, 0x2d, 0xa9,
+ 0xad, 0xe5, 0xd3, 0xf4, 0xc8, 0xca, 0x66, 0xc1, 0x5c, 0xa2, 0x9a, 0xcb,
+ 0x6a, 0x1f, 0xb7, 0xfc, 0x8d, 0x44, 0x58, 0x5b, 0xbb, 0x68, 0x6c, 0xfd,
+ 0x8b, 0xec, 0xdf, 0x3e, 0x18, 0xda, 0x5f, 0xe8, 0x9c, 0xff, 0xe3, 0xf5,
+ 0xa0, 0xe1, 0xb7, 0xf5, 0xe8, 0x54, 0xf9, 0x59, 0xf8, 0x4b, 0x70, 0xa9,
+ 0xbc, 0x1a, 0xf9, 0x23, 0x3b, 0xbf, 0xae, 0xc4, 0x45, 0xc6, 0x26, 0x20,
+ 0xaa, 0x93, 0xb5, 0xf7, 0x47, 0x56, 0x66, 0xcc, 0x50, 0x7d, 0xc6, 0x9f,
+ 0xf3, 0xb3, 0xf1, 0x3a, 0x16, 0x05, 0x76, 0x83, 0xd4, 0xf4, 0x12, 0xbf,
+ 0xea, 0xec, 0x85, 0xfc, 0x33, 0x8b, 0xdd, 0xef, 0x5a, 0xbb, 0x91, 0xfe,
+ 0x3c, 0xfd, 0x48, 0xfc, 0xf9, 0x47, 0x13, 0x73, 0xe2, 0xfb, 0x6b, 0xab,
+ 0x0e, 0x2b, 0xce, 0xa3, 0x83, 0xf6, 0xf1, 0x9b, 0xf1, 0x9f, 0x44, 0xfd,
+ 0x3f, 0x72, 0xd4, 0x03, 0x25, 0x63, 0x3b, 0x49, 0x8b, 0x5f, 0xf3, 0xdc,
+ 0x77, 0xb0, 0xd5, 0xf7, 0x1e, 0x08, 0x9d, 0x44, 0x87, 0x67, 0x17, 0xf3,
+ 0x9d, 0x11, 0xb7, 0xe5, 0x46, 0xf7, 0xcc, 0xdd, 0x50, 0xfc, 0x69, 0x43,
+ 0x5d, 0xa7, 0xf8, 0xb4, 0x71, 0x6b, 0x76, 0xb9, 0x71, 0x51, 0x9d, 0x98,
+ 0x5b, 0x2a, 0x13, 0xbf, 0xfd, 0xa4, 0xf6, 0x80, 0xd5, 0xbf, 0x7c, 0x50,
+ 0xe2, 0x3d, 0x27, 0xc2, 0xcf, 0xf8, 0x53, 0x5b, 0x77, 0x22, 0xeb, 0x06,
+ 0x35, 0xbd, 0xc5, 0xaf, 0x3a, 0xfb, 0x2c, 0xf7, 0x84, 0x97, 0xf3, 0x9c,
+ 0x48, 0x9b, 0x43, 0xeb, 0x6b, 0x8a, 0xdb, 0x2c, 0x58, 0xe5, 0x3f, 0x8a,
+ 0xc6, 0xaf, 0x9a, 0x7d, 0x2d, 0xd6, 0xb2, 0x51, 0x8d, 0x96, 0xdc, 0xfe,
+ 0xc2, 0x5a, 0xfc, 0x7e, 0xac, 0x3c, 0xda, 0x99, 0xcc, 0x77, 0x8e, 0x3f,
+ 0x8f, 0x96, 0xca, 0x9d, 0x11, 0xba, 0xd1, 0x92, 0xb9, 0x27, 0xad, 0xc5,
+ 0x6f, 0xf3, 0xa8, 0xf3, 0xbe, 0x5f, 0x76, 0xd4, 0x1d, 0x0b, 0x7e, 0x35,
+ 0x3d, 0x91, 0x58, 0x7d, 0x8d, 0xd5, 0xfe, 0x9c, 0x4a, 0xfc, 0x7e, 0xfd,
+ 0x79, 0x44, 0x5d, 0xd3, 0x30, 0x99, 0xff, 0x58, 0xd9, 0xaa, 0x4c, 0xe6,
+ 0xfb, 0x93, 0xc9, 0x06, 0xcd, 0xb3, 0xf0, 0x62, 0xde, 0xf9, 0x49, 0x96,
+ 0x46, 0xea, 0x0e, 0x1b, 0xe2, 0xb5, 0x43, 0x55, 0x72, 0xd6, 0x54, 0xbf,
+ 0x1f, 0x97, 0xb7, 0x79, 0xe8, 0xe3, 0x80, 0xdd, 0x0e, 0x20, 0x66, 0x87,
+ 0x15, 0xf1, 0xb1, 0xf6, 0x90, 0xf2, 0x72, 0x4e, 0x34, 0xa2, 0x3e, 0xb5,
+ 0x6a, 0x19, 0xeb, 0x16, 0x87, 0xcc, 0xf3, 0x43, 0x13, 0x86, 0xec, 0x71,
+ 0xfb, 0xbf, 0xef, 0x1f, 0x59, 0xf7, 0x3b, 0x90, 0xfb, 0xfa, 0xc1, 0xe5,
+ 0xc6, 0x46, 0xb6, 0x7b, 0xcf, 0x57, 0xb1, 0xe7, 0x87, 0x16, 0x9b, 0xcd,
+ 0xa3, 0x5b, 0xb3, 0xd6, 0x51, 0xa9, 0xc4, 0xc7, 0xea, 0xcf, 0xc2, 0xed,
+ 0x7d, 0xc1, 0x5e, 0xce, 0x35, 0xd2, 0xc5, 0xe6, 0x14, 0xf5, 0xef, 0x8d,
+ 0x99, 0x51, 0x8c, 0x6b, 0x7a, 0xdd, 0xc9, 0xce, 0x04, 0xea, 0xe3, 0x57,
+ 0x26, 0x93, 0xd9, 0xe8, 0x5d, 0xf4, 0x2c, 0x67, 0xbf, 0x13, 0x97, 0x6a,
+ 0xa9, 0x7c, 0x9a, 0x96, 0xcd, 0x32, 0x1b, 0x0c, 0x8d, 0xac, 0x38, 0xb7,
+ 0xa4, 0x6b, 0x97, 0x9f, 0x6b, 0x3f, 0x42, 0xa3, 0x7f, 0x7e, 0xf7, 0x76,
+ 0xc3, 0x3d, 0x23, 0x73, 0x28, 0x3e, 0x99, 0xb7, 0xbf, 0x17, 0xd5, 0x5a,
+ 0x6d, 0x7f, 0xb1, 0xb1, 0x5e, 0xe3, 0xda, 0x44, 0xe3, 0x67, 0x8c, 0xd5,
+ 0x47, 0x4b, 0x23, 0x2b, 0xd6, 0xf3, 0x62, 0x27, 0xd1, 0x9a, 0xc3, 0xd9,
+ 0xaa, 0x4f, 0xef, 0x3e, 0x28, 0x34, 0xd2, 0xf5, 0xae, 0xa7, 0x41, 0x69,
+ 0xfc, 0x2b, 0x53, 0xe5, 0x62, 0x73, 0xb4, 0xf4, 0x3e, 0x3b, 0x56, 0x2f,
+ 0x36, 0xd5, 0x1d, 0x3f, 0xd4, 0xbb, 0x66, 0x3f, 0x77, 0x16, 0x81, 0xa8,
+ 0xa0, 0x6f, 0x2f, 0xe5, 0x76, 0x17, 0x37, 0x93, 0x5f, 0x07, 0xb1, 0x1b,
+ 0xd9, 0x4b, 0xad, 0x5d, 0x1e, 0x7b, 0xa9, 0xde, 0x56, 0xe0, 0x0c, 0x84,
+ 0xbe, 0x4d, 0x9f, 0xe5, 0x46, 0x5b, 0xed, 0xbc, 0xe5, 0x46, 0xb5, 0xd9,
+ 0x3e, 0x9e, 0xb6, 0xae, 0xb8, 0xe6, 0xd1, 0xc8, 0xca, 0x78, 0xd2, 0xeb,
+ 0x0c, 0x65, 0xc6, 0xff, 0x22, 0x39, 0xbf, 0x7e, 0xb7, 0xf8, 0xb1, 0xf2,
+ 0xf4, 0xc7, 0xa7, 0xaa, 0xfd, 0xba, 0xa9, 0xf2, 0x66, 0xeb, 0x4a, 0x1e,
+ 0x8a, 0x3b, 0xef, 0xdd, 0x79, 0x1c, 0x58, 0x4b, 0x69, 0xc7, 0x0b, 0xc1,
+ 0x32, 0x3c, 0x0b, 0x4f, 0xcc, 0xdd, 0xd9, 0xf9, 0xb5, 0x74, 0xaf, 0xb6,
+ 0xdd, 0xd0, 0xbe, 0xef, 0x53, 0x35, 0xd0, 0x8a, 0x39, 0x25, 0x1e, 0x14,
+ 0x2c, 0x75, 0x48, 0x51, 0xe2, 0x9d, 0x6f, 0xd6, 0x1f, 0x43, 0xf1, 0x07,
+ 0x61, 0xfb, 0xfa, 0x50, 0x3d, 0x5b, 0xeb, 0xf7, 0xa9, 0xef, 0x5c, 0x8d,
+ 0xb8, 0xd5, 0xfc, 0x4a, 0xfc, 0xdb, 0xf4, 0x5a, 0xea, 0xdb, 0xf4, 0x50,
+ 0x3c, 0x9c, 0x54, 0x5b, 0xd7, 0x21, 0x65, 0x3c, 0xe9, 0xbe, 0x0b, 0x3e,
+ 0xfa, 0xaf, 0x3d, 0xb7, 0x29, 0x67, 0xde, 0x34, 0x16, 0x79, 0x13, 0x62,
+ 0xca, 0x40, 0x68, 0x35, 0xf2, 0x35, 0x56, 0x8f, 0xaa, 0xc7, 0xf3, 0x48,
+ 0x2f, 0x99, 0xdd, 0x1d, 0x41, 0xdf, 0xe7, 0xc0, 0x6a, 0xa4, 0xfd, 0x99,
+ 0x5f, 0x63, 0xab, 0x91, 0xc1, 0xd0, 0x55, 0xe7, 0x0b, 0xce, 0x28, 0x83,
+ 0xa1, 0xdd, 0xcb, 0xf3, 0x50, 0xbf, 0x4f, 0x9d, 0x8d, 0xb9, 0xda, 0xef,
+ 0xc3, 0xbf, 0x8e, 0x81, 0xd0, 0xe3, 0x75, 0xd9, 0x71, 0xdd, 0x1a, 0xfb,
+ 0xa7, 0x00, 0x37, 0x2e, 0xa6, 0x4c, 0x48, 0xf6, 0x78, 0x55, 0xcb, 0x0d,
+ 0x2f, 0x59, 0x98, 0x00, 0xfa, 0x69, 0x3c, 0x29, 0xdb, 0xe3, 0x55, 0x4d,
+ 0x95, 0x9d, 0xe6, 0xfb, 0x01, 0x5c, 0xbd, 0xd5, 0xc8, 0xa3, 0x1d, 0xb9,
+ 0x2c, 0x82, 0xb6, 0xf7, 0x16, 0xf3, 0x10, 0x00, 0xae, 0xcf, 0xe7, 0xc0,
+ 0xc8, 0x8a, 0xdb, 0x33, 0x05, 0xad, 0x2c, 0x95, 0x59, 0xb7, 0x0d, 0xdc,
+ 0xa4, 0x99, 0x56, 0x8f, 0xd7, 0x4b, 0xbe, 0xe0, 0xd3, 0x46, 0x23, 0x4d,
+ 0xcd, 0x0b, 0xdc, 0xa4, 0x98, 0x22, 0x3f, 0x4f, 0xa4, 0xc6, 0xee, 0xfb,
+ 0xac, 0x4c, 0x96, 0x24, 0x80, 0xab, 0x10, 0xf4, 0x0d, 0xc5, 0xe5, 0xc6,
+ 0xac, 0xc6, 0xea, 0xf3, 0xeb, 0x3c, 0x6b, 0x0e, 0xf8, 0x59, 0xc4, 0x04,
+ 0x5b, 0xd0, 0x6a, 0x66, 0xdc, 0xab, 0x05, 0x6f, 0xbb, 0xed, 0x00, 0xb8,
+ 0x3a, 0xc7, 0x01, 0x75, 0x5f, 0x7e, 0xeb, 0xfd, 0xac, 0x6a, 0xdf, 0x9f,
+ 0xd4, 0xd5, 0xbc, 0xd7, 0xaf, 0x31, 0x32, 0xd1, 0x81, 0x9f, 0xd7, 0x97,
+ 0xe0, 0x78, 0xf2, 0x34, 0x7d, 0x7b, 0xfb, 0xa0, 0xd0, 0x3e, 0x16, 0xf3,
+ 0x1b, 0xd9, 0x97, 0x73, 0x4a, 0x7c, 0x20, 0x14, 0xbc, 0xe9, 0xa2, 0x01,
+ 0x70, 0x15, 0xf4, 0xbd, 0x0d, 0x24, 0xc2, 0xab, 0x91, 0xdd, 0xcb, 0xa3,
+ 0xfd, 0xc4, 0xd8, 0x9b, 0x2e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x57, 0xe9, 0xff, 0x01, 0x8a, 0xc0, 0x18, 0xe0, 0x46, 0xfc,
+ 0x03, 0x00
+};
+unsigned int splash_bmp_gz_len = 4382;
diff --git a/boards.cfg b/boards.cfg
index dfefc3fd6a..f9b09e7426 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -153,6 +153,7 @@ omap3_zoom1 arm armv7 zoom1 logicpd
omap3_zoom2 arm armv7 zoom2 logicpd omap3
omap3_beagle arm armv7 beagle ti omap3
omap3_evm arm armv7 evm ti omap3
+omap3logic arm armv7 logic ti omap3
omap3_sdp3430 arm armv7 sdp3430 ti omap3
devkit8000 arm armv7 devkit8000 timll omap3
omap4_panda arm armv7 panda ti omap4
diff --git a/common/Makefile b/common/Makefile
index 224b7cc712..f3ad4bdd63 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -160,6 +160,7 @@ COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
+COBJS-$(CONFIG_YAFFS2_NEW) += cmd_yaffs2.o
# others
COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c
index 75924f8aac..a5a2930c40 100644
--- a/common/cmd_bdinfo.c
+++ b/common/cmd_bdinfo.c
@@ -350,6 +350,11 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#endif
print_num("relocaddr", gd->relocaddr);
print_num("reloc off", gd->reloc_off);
+#ifdef CONFIG_GDB_SECTION_STARTS
+ print_num("data_start", gd->data_start);
+ print_num("rodata_start", gd->rodata_start);
+ print_num("bss_start", gd->bss_start);
+#endif
print_num("irq_sp", gd->irq_sp); /* irq stack pointer */
print_num("sp start ", gd->start_addr_sp);
print_num("FB base ", gd->fb_base);
@@ -462,3 +467,18 @@ U_BOOT_CMD(
"print Board Info structure",
""
);
+
+#ifdef CONFIG_GDB_SECTION_STARTS
+int do_gdb_debug(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("add-symbol-file u-boot %#lx -s .data %#lx \\\n\t-s .rodata %#lx -s .bss %#lx\n",
+ gd->relocaddr, gd->data_start, gd->rodata_start, gd->bss_start);
+ return 0;
+}
+
+U_BOOT_CMD(
+ gdb_debug, 1, 1, do_gdb_debug,
+ "print gdb 'add-symbol-file' command",
+ ""
+);
+#endif
diff --git a/common/cmd_cache.c b/common/cmd_cache.c
index 5cdd8341f2..5ece657284 100644
--- a/common/cmd_cache.c
+++ b/common/cmd_cache.c
@@ -59,6 +59,15 @@ int do_dcache ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
break;
case 1: dcache_enable ();
break;
+ default:
+#ifdef CONFIG_ARM
+ if (!strcmp(argv[1], "flush")) {
+ /* Flush all of memory */
+ flush_cache(0, ~0);
+ return 0;
+ }
+#endif
+ return cmd_usage(cmdtp);
}
/* FALL TROUGH */
case 1: /* get status */
@@ -93,6 +102,11 @@ U_BOOT_CMD(
U_BOOT_CMD(
dcache, 2, 1, do_dcache,
"enable or disable data cache",
+#ifdef CONFIG_ARM
+ "[on, off, flush]\n"
+ " - enable, disable, or flush data (writethrough) cache"
+#else
"[on, off]\n"
" - enable or disable data (writethrough) cache"
+#endif
);
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
index bd49b796c6..1b954619e9 100644
--- a/common/cmd_flash.c
+++ b/common/cmd_flash.c
@@ -33,12 +33,7 @@
#if defined(CONFIG_CMD_MTDPARTS)
#include <jffs2/jffs2.h>
-
-/* partition handling routines */
-int mtdparts_init(void);
-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);
+#include "mtd_parts.h"
#endif
#ifndef CONFIG_SYS_NO_FLASH
@@ -359,9 +354,9 @@ int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#if defined(CONFIG_CMD_MTDPARTS)
/* erase <part-id> - erase partition */
- if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
+ if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num, 0) == 0)) {
mtdparts_init();
- if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
+ if (find_dev_and_part(argv[1], &dev, &pnum, &part, 0) == 0) {
if (dev->id->type == MTD_DEV_TYPE_NOR) {
bank = dev->id->num;
info = &flash_info[bank];
@@ -555,9 +550,9 @@ int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
#if defined(CONFIG_CMD_MTDPARTS)
/* protect on/off <part-id> */
- if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
+ if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num, 0) == 0)) {
mtdparts_init();
- if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
+ if (find_dev_and_part(argv[2], &dev, &pnum, &part, 0) == 0) {
if (dev->id->type == MTD_DEV_TYPE_NOR) {
bank = dev->id->num;
info = &flash_info[bank];
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
index 27296ddd7d..ecb7090829 100644
--- a/common/cmd_jffs2.c
+++ b/common/cmd_jffs2.c
@@ -106,6 +106,8 @@
#include <onenand_uboot.h>
#endif
+#include "mtd_parts.h"
+
/* enable/disable debugging messages */
#define DEBUG_JFFS
#undef DEBUG_JFFS
@@ -205,6 +207,7 @@ static int mtd_device_validate(u8 type, u8 num, u32 *size)
return 1;
}
+#if 0
/**
* Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
* return device type and number.
@@ -244,6 +247,7 @@ static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *d
*ret_id = p;
return 0;
}
+#endif
/*
* 'Static' version of command line mtdparts_init() routine. Single partition on
@@ -378,7 +382,7 @@ int mtdparts_init(void)
dev_name = "nor0";
#endif
- if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
+ if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num, 0) != 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_mtd_dev);
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index a5576aaab0..b6804dd87e 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -1264,3 +1264,50 @@ U_BOOT_CMD(
"[.b, .w, .l] address value delay(ms)"
);
#endif /* CONFIG_MX_CYCLIC */
+
+#ifdef CONFIG_CMD_HEXDUMP
+#include <linux/ctype.h>
+
+int do_hd ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *src;
+ int i, j, len;
+ if (argc < 3) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ src = (char *)simple_strtoul(argv[1], NULL, 16);
+ len = simple_strtoul(argv[2], NULL, 16);
+
+ while (len > 0) {
+ printf("%p ", src);
+ j = (len > 16) ? 16 : len;
+ for (i=0; i<16; ++i) {
+ if (i < j)
+ printf("%02x ", src[i]);
+ else
+ printf(" ");
+ if (i == 7)
+ printf(" ");
+ }
+ printf(" |");
+ for (i=0; i<j; ++i) {
+ if (isascii(src[i]) && isprint(src[i]))
+ printf("%c", src[i]);
+ else
+ printf(".");
+ }
+ printf("|\n");
+ src += j;
+ len -= j;
+ }
+ return 0;
+}
+
+U_BOOT_CMD(
+ hd, 3, 1, do_hd,
+ "hexdump a memory region",
+ "srcaddr length"
+);
+#endif
diff --git a/common/cmd_misc.c b/common/cmd_misc.c
index 061b1bbad0..c4d266c3e8 100644
--- a/common/cmd_misc.c
+++ b/common/cmd_misc.c
@@ -53,3 +53,46 @@ U_BOOT_CMD(
"N\n"
" - delay execution for N seconds (N is _decimal_ !!!)"
);
+
+#ifdef CONFIG_CMD_TIME
+int do_time (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong start;
+ ulong delta;
+ cmd_tbl_t *cmdtp2;
+ int ret;
+ unsigned int secs, msecs;
+
+ if (argc < 2) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ cmdtp2 = find_cmd(argv[1]);
+ if (!cmdtp2) {
+ printf ("Unknown command '%s' - try help\n", argv[1]);
+ return 1;
+ }
+
+ start = get_timer(0);
+
+ /* Execute command */
+ ret = (cmdtp2->cmd)(cmdtp2, flag, argc-1, argv+1);
+
+ delta = get_timer(start);
+
+ secs = (delta * 1000) / CONFIG_SYS_HZ;
+ msecs = secs % 1000;
+ secs /= 1000;
+
+ printf("'%s' took %u.%03u seconds\n", argv[1], secs, msecs);
+ return ret;
+}
+
+U_BOOT_CMD(
+ time , CONFIG_SYS_MAXARGS, 1, do_time,
+ "time execution of command",
+ "command to time\n"
+ " - time execution of command in seconds"
+);
+#endif
diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 5481c885d3..d0639f6cd2 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -106,6 +106,8 @@
#include <onenand_uboot.h>
#endif
+#include "mtd_parts.h"
+
/* special size referring to all the remaining space in a partition */
#define SIZE_REMAINING 0xFFFFFFFF
@@ -1037,9 +1039,10 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_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
+ * @param quiet non-zero to suppress messages
+ * @return 0 on success, -ERRNO otherwise
*/
-int mtd_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 quiet)
{
const char *p = id;
@@ -1054,13 +1057,15 @@ int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
*dev_type = MTD_DEV_TYPE_ONENAND;
p += 7;
} else {
- printf("incorrect device type in %s\n", id);
- return 1;
+ if (!quiet)
+ printf("incorrect device type in %s\n", id);
+ return -ENODEV;
}
if (!isdigit(*p)) {
- printf("incorrect device number in %s\n", id);
- return 1;
+ if (!quiet)
+ printf("incorrect device number in %s\n", id);
+ return -ERANGE;
}
*dev_num = simple_strtoul(p, (char **)&p, 0);
@@ -1340,14 +1345,16 @@ static void list_partitions(void)
* @param dev pointer to the requested device (output)
* @param part_num verified partition number (output)
* @param part pointer to requested partition (output)
+ * @param quiet non-zero to suppress messages
* @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)
+ u8 *part_num, struct part_info **part, int quiet)
{
struct list_head *dentry, *pentry;
u8 type, dnum, pnum;
const char *p;
+ int ret;
debug("--- find_dev_and_part ---\nid = %s\n", id);
@@ -1367,26 +1374,31 @@ int find_dev_and_part(const char *id, struct mtd_device **dev,
*part = NULL;
*part_num = 0;
- if (mtd_id_parse(p, &p, &type, &dnum) != 0)
- return 1;
+ ret = mtd_id_parse(p, &p, &type, &dnum, quiet);
+ if (ret != 0)
+ return ret;
if ((*p++ != ',') || (*p == '\0')) {
- printf("no partition number specified\n");
+ if (!quiet)
+ 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);
+ if (!quiet)
+ 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);
+ if (!quiet)
+ 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");
+ if (!quiet)
+ printf("no such partition\n");
*dev = NULL;
return 1;
}
@@ -1408,7 +1420,7 @@ static int delete_partition(const char *id)
struct mtd_device *dev;
struct part_info *part;
- if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
+ if (find_dev_and_part(id, &dev, &pnum, &part, 0) == 0) {
debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08x@0x%08x\n",
MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
@@ -1615,7 +1627,7 @@ static int parse_mtdids(const char *const ids)
ret = 1;
/* parse 'nor'|'nand'|'onenand'<dev-num> */
- if (mtd_id_parse(p, &p, &type, &num) != 0)
+ if (mtd_id_parse(p, &p, &type, &num, 0) != 0)
break;
if (*p != '=') {
@@ -1813,7 +1825,7 @@ int mtdparts_init(void)
debug("--- getting current partition: %s\n", tmp_ep);
- if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
+ if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p, 0) == 0) {
current_mtd_dev = cdev;
current_mtd_partnum = pnum;
current_save();
@@ -1896,7 +1908,7 @@ int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 1;
}
- if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
+ if (find_dev_and_part(argv[1], &dev, &pnum, &part, 0) != 0)
return 1;
current_mtd_dev = dev;
@@ -1963,7 +1975,7 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
struct mtdids *id;
struct part_info *p;
- if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
+ if (mtd_id_parse(argv[2], NULL, &type, &num, 0) != 0)
return 1;
if ((id = id_find(type, num)) == NULL) {
@@ -2090,3 +2102,46 @@ U_BOOT_CMD(
"<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"
);
/***************************************************/
+
+int mtd_get_part_priv(const char *partname, int *idx, struct mtd_device **dev, loff_t *off, loff_t *size, void **cookie, void **priv, int quiet)
+{
+ int ret;
+ u8 pnum;
+ struct mtd_device *mtd_dev;
+ struct part_info *part;
+
+ ret = mtdparts_init();
+ if (ret)
+ return ret;
+
+ ret = find_dev_and_part(partname, &mtd_dev, &pnum, &part, quiet);
+ if (ret)
+ return ret;
+
+ if (mtd_dev->id->type != MTD_DEV_TYPE_NAND) {
+ if (!quiet)
+ puts("not a NAND device\n");
+ return -1;
+ }
+
+ *off = part->offset;
+ *dev = mtd_dev;
+ *size = part->size;
+ *idx = mtd_dev->id->num;
+
+ *cookie = part;
+ *priv = part->jffs2_priv;
+
+ ret = nand_set_dev(*idx);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void mtd_set_part_priv(void *cookie, void *priv)
+{
+ struct part_info *part = cookie;
+
+ part->jffs2_priv = priv;
+}
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 44c4d1f89c..9b7a0a73e3 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -29,12 +29,7 @@
#include <nand.h>
#if defined(CONFIG_CMD_MTDPARTS)
-
-/* partition handling routines */
-int mtdparts_init(void);
-int 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);
+#include "mtd_parts.h"
#endif
static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
@@ -98,7 +93,7 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
/* ------------------------------------------------------------------------- */
-static int set_dev(int dev)
+int nand_set_dev(int dev)
{
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
!nand_info[dev].name) {
@@ -148,7 +143,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
if (ret)
return ret;
- ret = find_dev_and_part(partname, &dev, &pnum, &part);
+ ret = find_dev_and_part(partname, &dev, &pnum, &part, 0);
if (ret)
return ret;
@@ -161,7 +156,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
*size = part->size;
*idx = dev->id->num;
- ret = set_dev(*idx);
+ ret = nand_set_dev(*idx);
if (ret)
return ret;
@@ -283,7 +278,7 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
return 1;
}
- set_dev(0);
+ nand_set_dev(0);
if (!strcmp(cmd, "get")) {
ret = get_nand_env_oob(nand, &nand_env_oob_offset);
@@ -423,7 +418,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
}
dev = (int)simple_strtoul(argv[2], NULL, 10);
- set_dev(dev);
+ nand_set_dev(dev);
return 0;
}
@@ -637,6 +632,17 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
return 1;
}
+#ifdef CONFIG_MTD_DEBUG
+ if (strcmp(cmd, "debug") == 0) {
+ if (argc == 3) {
+ ulong val = simple_strtoul(argv[2], NULL, 16);
+ mtd_debug_verbose = val;
+ } else
+ printf("%d\n", mtd_debug_verbose);
+ return 1;
+ }
+#endif
+
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
if (strcmp(cmd, "lock") == 0) {
int tight = 0;
@@ -718,6 +724,10 @@ U_BOOT_CMD(
"nand env.oob set off|partition - set enviromnent offset\n"
"nand env.oob get - get environment offset"
#endif
+#ifdef CONFIG_MTD_DEBUG
+ "\n"
+ "nand debug [level] - display or set the MTD debug level"
+#endif
);
static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
@@ -827,7 +837,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
if (argc >= 2) {
char *p = (argc == 2) ? argv[1] : argv[2];
if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
- (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
+ (find_dev_and_part(p, &dev, &pnum, &part, 0) == 0)) {
if (dev->id->type != MTD_DEV_TYPE_NAND) {
puts("Not a NAND device\n");
return 1;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index b2c88babc4..91728f7109 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -381,6 +381,13 @@ int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (argc < 2)
return cmd_usage(cmdtp);
+#ifdef CONFIG_CHECK_SETENV
+ if (setenv_reserved_name(argv[1])) {
+ printf("## Error: can not set variable \"%s\"\n", argv[1]);
+ return 1;
+ }
+#endif
+
return _do_env_set(flag, argc, argv);
}
@@ -584,6 +591,11 @@ static int do_env_default(cmd_tbl_t *cmdtp, int flag, int argc, char * const arg
return cmd_usage(cmdtp);
set_default_env("## Resetting to default environment\n");
+#if defined(CONFIG_TOUCHUP_ENV)
+ /* On a restored environment, need to initialise board
+ * specific variables */
+ touchup_env();
+#endif
return 0;
}
diff --git a/common/cmd_yaffs2.c b/common/cmd_yaffs2.c
index 7c01ea2a25..9fd037afb2 100644
--- a/common/cmd_yaffs2.c
+++ b/common/cmd_yaffs2.c
@@ -11,11 +11,10 @@
extern void cmd_yaffs_mount(char *mp);
extern void cmd_yaffs_umount(char *mp);
-extern void cmd_yaffs_read_file(char *fn);
-extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile);
extern void cmd_yaffs_ls(const char *mountpt, int longlist);
+extern int cmd_yaffs_df(const char *path, loff_t *size);
extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
-extern void cmd_yaffs_mread_file(char *fn, char *addr);
+extern void cmd_yaffs_mread_file(char *fn, char *addr, long *size);
extern void cmd_yaffs_mkdir(const char *dir);
extern void cmd_yaffs_rmdir(const char *dir);
extern void cmd_yaffs_rm(const char *path);
@@ -26,69 +25,81 @@ extern int yaffs_DumpDevStruct(const char *path);
int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *mtpoint = argv[1];
- cmd_yaffs_mount(mtpoint);
+ if (argc < 2)
+ return cmd_usage(cmdtp);
- return(0);
-}
-
-int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
- char *mtpoint = argv[1];
- cmd_yaffs_umount(mtpoint);
+ cmd_yaffs_mount(argv[1]);
return(0);
}
-int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *dirname = argv[argc-1];
+ if (argc < 2)
+ return cmd_usage(cmdtp);
- cmd_yaffs_ls(dirname, (argc>2)?1:0);
+ cmd_yaffs_umount(argv[1]);
return(0);
}
-int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *filename = argv[1];
- printf ("Reading file %s ", filename);
-
- cmd_yaffs_read_file(filename);
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+ cmd_yaffs_ls(argv[argc-1], (argc>2)?1:0);
- printf ("done\n");
return(0);
}
-int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_ydf (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *filename = argv[1];
- ulong value = simple_strtoul(argv[2], NULL, 16);
- ulong numValues = simple_strtoul(argv[3], NULL, 16);
+ loff_t space;
+ int ret;
- printf ("Writing value (%x) %x times to %s... ", value, numValues, filename);
+ if (argc < 2)
+ return cmd_usage(cmdtp);
- cmd_yaffs_write_file(filename,value,numValues);
+ ret = cmd_yaffs_df(argv[1], &space);
+ if (!ret)
+ printf("Free Space: %lluKiB\n", space / 1024);
- printf ("done\n");
- return(0);
+ return !!ret;
}
+
int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *filename = argv[1];
- ulong addr = simple_strtoul(argv[2], NULL, 16);
+ long size;
+ char buf[12];
+ char *filename;
+ ulong addr;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ filename = argv[2];
+ addr = simple_strtoul(argv[1], NULL, 16);
- cmd_yaffs_mread_file(filename, (char *)addr);
+ cmd_yaffs_mread_file(filename, (char *)addr, &size);
+ sprintf(buf, "%lX", size);
+ setenv("filesize", buf);
return(0);
}
int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *filename = argv[1];
- ulong addr = simple_strtoul(argv[2], NULL, 16);
- ulong size = simple_strtoul(argv[3], NULL, 16);
+ char *filename;
+ ulong addr;
+ ulong size;
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ filename = argv[1];
+ addr = simple_strtoul(argv[2], NULL, 16);
+ size = simple_strtoul(argv[3], NULL, 16);
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
@@ -97,35 +108,44 @@ int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *dirname = argv[1];
-
- cmd_yaffs_mkdir(dirname);
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ cmd_yaffs_mkdir(argv[1]);
return(0);
}
int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *dirname = argv[1];
+ if (argc < 2)
+ return cmd_usage(cmdtp);
- cmd_yaffs_rmdir(dirname);
+ cmd_yaffs_rmdir(argv[1]);
return(0);
}
int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *path = argv[1];
+ if (argc < 2)
+ return cmd_usage(cmdtp);
- cmd_yaffs_rm(path);
+ cmd_yaffs_rm(argv[1]);
return(0);
}
int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *oldPath = argv[1];
- char *newPath = argv[2];
+ char *oldPath;
+ char *newPath;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ oldPath = argv[1];
+ newPath = argv[2];
cmd_yaffs_mv(newPath, oldPath);
@@ -134,7 +154,12 @@ int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- char *dirname = argv[1];
+ char *dirname;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ dirname = argv[1];
if (yaffs_DumpDevStruct(dirname) != 0)
printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname);
return 0;
@@ -142,62 +167,56 @@ int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
ymount, 3, 0, do_ymount,
- "mount yaffs",
- ""
+ "YAFFS mount",
+ "<partition>"
);
U_BOOT_CMD(
yumount, 3, 0, do_yumount,
- "unmount yaffs",
- ""
+ "YAFFS unmount",
+ "<partition>"
);
U_BOOT_CMD(
yls, 4, 0, do_yls,
- "yaffs ls",
- "[-l] name"
-);
-
-U_BOOT_CMD(
- yrd, 2, 0, do_yrd,
- "read file from yaffs",
- "filename"
+ "YAFFS ls",
+ "[-l] <name>"
);
U_BOOT_CMD(
- ywr, 4, 0, do_ywr,
- "write file to yaffs",
- "filename value num_vlues"
+ ydf, 2, 0, do_ydf,
+ "YAFFS disk free",
+ "[-l] <dirname>"
);
U_BOOT_CMD(
yrdm, 3, 0, do_yrdm,
- "read file to memory from yaffs",
- "filename offset"
+ "YAFFS read file to memory",
+ "<addr> <filename>"
);
U_BOOT_CMD(
ywrm, 4, 0, do_ywrm,
- "write file from memory to yaffs",
- "filename offset size"
+ "YAFFS write file from memory",
+ "<filename> <addr> <size>"
);
U_BOOT_CMD(
ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir",
- "dirname"
+ "<dirname>"
);
U_BOOT_CMD(
yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir",
- "dirname"
+ "<dirname>"
);
U_BOOT_CMD(
yrm, 2, 0, do_yrm,
"YAFFS rm",
- "path"
+ "<path>"
);
U_BOOT_CMD(
diff --git a/common/env_common.c b/common/env_common.c
index c3e6388ac0..04a947e92b 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -196,6 +196,14 @@ void set_default_env(const char *s)
gd->flags |= GD_FLG_ENV_READY;
}
+int env_check_valid(const char *buf)
+{
+ env_t *ep = (env_t *)buf;
+ uint32_t crc;
+
+ memcpy(&crc, &ep->crc, sizeof(crc));
+ return crc32(0, ep->data, ENV_SIZE) == crc;
+}
/*
* Check if CRC is valid and (if yes) import the environment.
* Note that "buf" may or may not be aligned.
@@ -205,11 +213,7 @@ int env_import(const char *buf, int check)
env_t *ep = (env_t *)buf;
if (check) {
- uint32_t crc;
-
- memcpy(&crc, &ep->crc, sizeof(crc));
-
- if (crc32(0, ep->data, ENV_SIZE) != crc) {
+ if (!env_check_valid(buf)) {
set_default_env("!bad CRC");
return 0;
}
@@ -244,6 +248,9 @@ void env_relocate (void)
} else {
env_relocate_spec ();
}
+#ifdef CONFIG_TOUCHUP_ENV
+ touchup_env();
+#endif
}
#ifdef CONFIG_AUTO_COMPLETE
diff --git a/common/env_nand.c b/common/env_nand.c
index 14446a6a57..facb4b3016 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -153,30 +153,64 @@ int env_init(void)
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
-int writeenv(size_t offset, u_char *buf)
+static int writeenv(size_t offset, u_char *buf)
{
size_t end = offset + CONFIG_ENV_RANGE;
size_t amount_saved = 0;
size_t blocksize, len;
-
+ int ret, ncopies = 0;
u_char *char_ptr;
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ int current_ecc_method;
+#endif
+
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_default(&current_ecc_method);
+#endif
blocksize = nand_info[0].erasesize;
len = min(blocksize, CONFIG_ENV_SIZE);
- while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
+ while (offset < end) {
if (nand_block_isbad(&nand_info[0], offset)) {
offset += blocksize;
} else {
char_ptr = &buf[amount_saved];
- if (nand_write(&nand_info[0], offset, &len,
- char_ptr))
- return 1;
- offset += blocksize;
- amount_saved += len;
+ /* Data written can not straddle a block in case
+ one of the two blocks goes bad */
+ if ((offset & ~(blocksize - 1)) != ((offset + len - 1) & ~(blocksize - 1)))
+ offset = (offset + blocksize - 1) & ~(blocksize-1);
+
+ if (offset >= end)
+ break;
+
+ ret = nand_write(&nand_info[0], offset, &len,
+ char_ptr);
+
+ if (ret) {
+ /* Need to move offset forward by len,
+ * then to the start of the next block,
+ * reset amount_amount saved to start
+ * at the beginning of the environment */
+ offset += len;
+ offset = (offset + blocksize - 1) & ~(blocksize - 1);
+ amount_saved = 0;
+ } else {
+ amount_saved += len;
+ if (amount_saved >= CONFIG_ENV_SIZE) {
+ ncopies++;
+ amount_saved = 0;
+ }
+ }
+ offset += len;
}
}
- if (amount_saved != CONFIG_ENV_SIZE)
+
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_method(current_ecc_method);
+#endif
+
+ if (!ncopies)
return 1;
return 0;
@@ -211,8 +245,9 @@ int saveenv(void)
if(gd->env_valid == 1) {
puts("Erasing redundant NAND...\n");
nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
- if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options)) {
return 1;
+ }
puts("Writing to redundant NAND... ");
ret = writeenv(CONFIG_ENV_OFFSET_REDUND,
@@ -220,8 +255,9 @@ int saveenv(void)
} else {
puts("Erasing NAND...\n");
nand_erase_options.offset = CONFIG_ENV_OFFSET;
- if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options)) {
return 1;
+ }
puts("Writing to NAND... ");
ret = writeenv(CONFIG_ENV_OFFSET,
@@ -263,8 +299,9 @@ int saveenv(void)
env_new.crc = crc32(0, env_new.data, ENV_SIZE);
puts("Erasing Nand...\n");
- if (nand_erase_opts(&nand_info[0], &nand_erase_options))
+ if (nand_erase_opts(&nand_info[0], &nand_erase_options)) {
return 1;
+ }
puts("Writing to Nand... ");
if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
@@ -273,40 +310,123 @@ int saveenv(void)
}
puts("done\n");
+
return ret;
}
#endif /* CONFIG_ENV_OFFSET_REDUND */
#endif /* CMD_SAVEENV */
-int readenv(size_t offset, u_char * buf)
+#ifdef CONFIG_ENV_OFFSET_REDUND
+static int readenv(size_t offset, u_char * buf)
{
size_t end = offset + CONFIG_ENV_RANGE;
size_t amount_loaded = 0;
size_t blocksize, len;
-
u_char *char_ptr;
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ int current_ecc_method;
+#endif
blocksize = nand_info[0].erasesize;
if (!blocksize)
return 1;
len = min(blocksize, CONFIG_ENV_SIZE);
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_default(&current_ecc_method);
+#endif
+
while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
if (nand_block_isbad(&nand_info[0], offset)) {
offset += blocksize;
} else {
char_ptr = &buf[amount_loaded];
- if (nand_read_skip_bad(&nand_info[0], offset, &len, char_ptr))
+ if (nand_read_skip_bad(&nand_info[0], offset, &len, char_ptr)) {
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_method(current_ecc_method);
+#endif
+
return 1;
+ }
offset += blocksize;
amount_loaded += len;
}
}
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_method(current_ecc_method);
+#endif
if (amount_loaded != CONFIG_ENV_SIZE)
return 1;
return 0;
}
+#else /* ! CONFIG_ENV_OFFSET_REDUND */
+/* Read the environment, checking along the way. return 0 if valid
+ * environment or no environment is found, negative on error */
+static int readenv(size_t offset, u_char * buf)
+{
+ size_t end = offset + CONFIG_ENV_RANGE;
+ size_t amount_loaded = 0;
+ size_t blocksize, len;
+ u_char *char_ptr;
+ int ret;
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ int current_ecc_method;
+#endif
+
+ blocksize = nand_info[0].erasesize;
+ if (!blocksize)
+ return -1;
+ len = min(blocksize, CONFIG_ENV_SIZE);
+
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_default(&current_ecc_method);
+#endif
+
+ while (offset < end) {
+ if (nand_block_isbad(&nand_info[0], offset)) {
+ offset += blocksize;
+ } else {
+ char_ptr = &buf[amount_loaded];
+ /* Data read can not straddle a block in case
+ one of the two blocks goes bad */
+ if ((offset & ~(blocksize - 1)) != ((offset + len - 1) & ~(blocksize - 1)))
+ offset = (offset + blocksize - 1) & ~(blocksize-1);
+ if (offset >= end)
+ break;
+
+ ret = nand_read(&nand_info[0], offset, &len, char_ptr);
+
+ if (ret) {
+ /* Need to move offset forward by len,
+ * then to the start of the next block,
+ * reset amount_amount saved to start
+ * at the beginning of the environment */
+ offset += len;
+ offset = (offset + blocksize - 1) & ~(blocksize - 1);
+ amount_loaded = 0;
+ } else {
+ amount_loaded += len;
+ if (amount_loaded >= CONFIG_ENV_SIZE) {
+ if (env_check_valid(buf))
+ goto found;
+ amount_loaded = 0;
+ }
+ }
+ offset += len;
+ }
+ }
+
+found:
+#if defined(CONFIG_NAND_MULTIPLE_ECC)
+ nand_switch_ecc_method(current_ecc_method);
+#endif
+ if (amount_loaded != CONFIG_ENV_SIZE)
+ return 0;
+
+ return 1;
+}
+#endif
#ifdef CONFIG_ENV_OFFSET_OOB
int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
@@ -346,6 +466,7 @@ void env_relocate_spec(void)
#if !defined(ENV_IS_EMBEDDED)
int crc1_ok = 0, crc2_ok = 0;
env_t *ep, *tmp_env1, *tmp_env2;
+ int ret;
tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
@@ -358,11 +479,11 @@ void env_relocate_spec(void)
return;
}
- if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
- puts("No Valid Environment Area found\n");
+ ret = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
+ printf("%sValid Environment Area found\n", ret ? "No ":"");
- if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
- puts("No Valid Redundant Environment Area found\n");
+ ret = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
+ printf("%sValid Redundant Environment Area found\n", ret ? "No ":"");
crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
@@ -433,7 +554,7 @@ void env_relocate_spec (void)
#endif
ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
- if (ret) {
+ if (ret < 0) {
set_default_env("!readenv() failed");
return;
}
diff --git a/common/lcd.c b/common/lcd.c
index 0555ab4fb7..85a946828e 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -35,12 +35,16 @@
#include <stdarg.h>
#include <linux/types.h>
#include <stdio_dev.h>
+#include <div64.h>
+#include <malloc.h>
#if defined(CONFIG_POST)
#include <post.h>
#endif
#include <lcd.h>
#include <watchdog.h>
+int console_color_black, console_color_white;
+
#if defined CONFIG_PXA250 || defined CONFIG_PXA27X || defined CONFIG_CPU_MONAHANS
#include <asm/byteorder.h>
#endif
@@ -63,20 +67,22 @@
/************************************************************************/
#ifdef CONFIG_LCD_LOGO
# include <bmp_logo.h> /* Get logo data, width and height */
-# if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
-# error Default Color Map overlaps with Logo Color Map
-# endif
#endif
DECLARE_GLOBAL_DATA_PTR;
ulong lcd_setmem (ulong addr);
-static void lcd_drawchars (ushort x, ushort y, uchar *str, int count);
+static void lcd_drawchars_16 (ushort x, ushort y, uchar *str, int count);
+static void lcd_drawchars_24 (ushort x, ushort y, uchar *str, int count);
+static void lcd_drawchars_x (ushort x, ushort y, uchar *str, int count);
+
+static void (*lcd_drawchars) (ushort x, ushort y, uchar *str, int count);
static inline void lcd_puts_xy (ushort x, ushort y, uchar *s);
static inline void lcd_putc_xy (ushort x, ushort y, uchar c);
static int lcd_init (void *lcdbase);
+static int lcd_init_colors (void);
static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]);
static void *lcd_logo (void);
@@ -139,12 +145,9 @@ static inline void console_newline (void)
/*----------------------------------------------------------------------*/
-void lcd_putc (const char c)
+void _lcd_putc (const char c)
{
- if (!lcd_is_enabled) {
- serial_putc(c);
- return;
- }
+ int i;
switch (c) {
case '\r': console_col = 0;
@@ -165,6 +168,13 @@ void lcd_putc (const char c)
case '\b': console_back();
return;
+ case '\f': /* Clear to EOL */
+ for (i=console_col; i < CONSOLE_COLS; ++i)
+ lcd_putc_xy (i * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT,
+ ' ');
+ return;
+
default: lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
console_row * VIDEO_FONT_HEIGHT,
c);
@@ -176,6 +186,15 @@ void lcd_putc (const char c)
/* NOTREACHED */
}
+void lcd_putc (const char c)
+{
+ if (!lcd_is_enabled) {
+ serial_putc(c);
+ return;
+ }
+ _lcd_putc(c);
+}
+
/*----------------------------------------------------------------------*/
void lcd_puts (const char *s)
@@ -204,11 +223,152 @@ void lcd_printf(const char *fmt, ...)
lcd_puts(buf);
}
+#define NUM_ANCHORS 5
+struct anchors {
+ int row, col;
+} anchors[NUM_ANCHORS];
+
+void output_lcd_string(char *p)
+{
+ char c;
+ int row,col;
+ int tmp;
+ char *s, *r;
+ int idx;
+
+ while ((c = *p++) != '\0') {
+ if (c == '/' && *p) {
+ switch(*p) {
+ case 'g':
+ /* Set cursor to anchor idx+'A' */
+ if (p[1]) {
+ idx = p[1]-'A';
+ if (idx >= 0 && idx < NUM_ANCHORS) {
+ console_row = anchors[idx].row;
+ console_col = anchors[idx].col;
+ }
+ p++;
+ } else {
+ _lcd_putc('/');
+ _lcd_putc(*p);
+ }
+ break;
+ case 'a':
+ /* Set anchor idx+'A' to cursor */
+ if (p[1]) {
+ idx = p[1]-'A';
+ if (idx >= 0 && idx < NUM_ANCHORS) {
+ anchors[idx].row = console_row;
+ anchors[idx].col = console_col;
+ }
+ p++;
+ } else {
+ _lcd_putc('/');
+ _lcd_putc(*p);
+ }
+ break;
+ case 'A':
+ /* Goto the lcd_anchor in environment */
+ s = getenv("lcd_anchor");
+ if (s) {
+ row = simple_strtoul(s, &r, 0);
+ if (r && *r==',') {
+ col = simple_strtoul(r+1, &r, 0);
+ if (r && !*r) {
+ if (row >= CONSOLE_ROWS)
+ row = CONSOLE_ROWS - 1;
+ if (row >= CONSOLE_COLS)
+ row = CONSOLE_COLS - 1;
+ console_row = row;
+ console_col = col;
+ }
+ }
+ }
+ break;
+ case 'p':
+ /* Cursor position, pos+'A' */
+ if (p[1] && p[2]) {
+ console_row = p[1]-'A';
+ console_col = p[2]-'A';
+ p+=2;
+ } else {
+ _lcd_putc('/');
+ _lcd_putc(*p);
+ }
+ break;
+ case 'i':
+ /* Invert video */
+ tmp = lcd_color_fg;
+ lcd_color_fg = lcd_color_bg;
+ lcd_color_bg = tmp;
+ break;
+ case 'b':
+ /* Back up the display */
+ _lcd_putc('\b');
+ break;
+ case 'r':
+ /* Carriage return */
+ _lcd_putc('\r');
+ break;
+ case 'n':
+ /* Line feed */
+ _lcd_putc('\n');
+ break;
+ case 'k':
+ /* Clear to end of line */
+ _lcd_putc('\f');
+ break;
+ default:
+ _lcd_putc('/');
+ _lcd_putc(*p);
+ break;
+ }
+ p++;
+ } else {
+ _lcd_putc(c);
+ }
+ }
+
+#ifdef CONFIG_ARM
+ /* Flush the cache to make sure display tracks content of memory */
+ flush_cache(0, ~0);
+#endif
+}
+
+int do_echo_lcd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (i > 1)
+ _lcd_putc(' ');
+ output_lcd_string(argv[i]);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ echo_lcd, CONFIG_SYS_MAXARGS, 1, do_echo_lcd,
+ "echo args to LCD",
+ "[args..]\n"
+ " - echo args to LCD, following escape sequences:\n"
+" /pRC - goto row 'R' ('A'+row), column 'C' ('A'+col)\n"
+" /aN - save the current position as anchor 'N' ('A'+n)\n"
+" /gN - set cursor position to anchor point 'N' ('A'+n)\n"
+" /i - invert video colors\n"
+" /b - backspace\n"
+" /r - carriage return\n"
+" /n - carriage return + linefeed\n"
+" /k - clear to end of line\n"
+" /A - goto lcd_anchor value in environment (R,C in decimal)\n"
+);
+
/************************************************************************/
/* ** Low-Level Graphics Routines */
/************************************************************************/
-static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
+static void lcd_drawchars_unknown (ushort x, ushort y, uchar *str, int count)
{
uchar *dest;
ushort off, row;
@@ -261,6 +421,64 @@ static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
}
}
+static void lcd_drawchars_16 (ushort x, ushort y, uchar *str, int count)
+{
+ uchar *dest;
+ ushort off, row;
+
+ dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_COLOR16) / 8);
+ off = x * (1 << LCD_COLOR16) % 8;
+
+ for (row=0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
+ uchar *s = str;
+ int i;
+ ushort *d = (ushort *)dest;
+
+ for (i=0; i<count; ++i) {
+ uchar c, bits;
+
+ c = *s++;
+ bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+
+ for (c=0; c<8; ++c) {
+ *d++ = (bits & 0x80) ?
+ lcd_color_fg : lcd_color_bg;
+ bits <<= 1;
+ }
+ }
+ }
+}
+
+static void lcd_drawchars_24 (ushort x, ushort y, uchar *str, int count)
+{
+ uchar *dest;
+ ushort off, row;
+
+ dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_COLOR24) / 8);
+ off = x * (1 << LCD_COLOR24) % 8;
+
+ for (row=0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
+ uchar *s = str;
+ int i;
+ uint *d = (uint *)dest;
+
+ for (i=0; i<count; ++i) {
+ uchar c, bits;
+
+ c = *s++;
+ bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+
+ for (c=0; c<8; ++c) {
+ *d++ = (bits & 0x80) ?
+ lcd_color_fg : lcd_color_bg;
+ bits <<= 1;
+ }
+ }
+ }
+}
+
+
+
/*----------------------------------------------------------------------*/
static inline void lcd_puts_xy (ushort x, ushort y, uchar *s)
@@ -331,10 +549,33 @@ int drv_lcd_init (void)
lcd_base = (void *)(gd->fb_base);
+ debug("%s: lcd_base %p\n", __FUNCTION__, lcd_base);
+
lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+ debug("%s: vl_col %u vl_bpix %u lcd_line_length %u\n", __FUNCTION__,
+ panel_info.vl_col, panel_info.vl_bpix, lcd_line_length);
+
lcd_init (lcd_base); /* LCD initialization */
+ /* lcd_init may setup panel_info structure */
+ lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+ debug("%s: vl_col %u vl_bpix %u lcd_line_length %u\n", __FUNCTION__,
+ panel_info.vl_col, panel_info.vl_bpix, lcd_line_length);
+
+ switch(panel_info.vl_bpix) {
+ case LCD_COLOR16:
+ lcd_drawchars = lcd_drawchars_16;
+ break;
+ case LCD_COLOR24:
+ lcd_drawchars = lcd_drawchars_24;
+ break;
+ default:
+ lcd_drawchars = lcd_drawchars_unknown;
+ break;
+ }
+
/* Device initialization */
memset (&lcddev, 0, sizeof (lcddev));
@@ -352,35 +593,21 @@ int drv_lcd_init (void)
/*----------------------------------------------------------------------*/
static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
-#if LCD_BPP == LCD_MONOCHROME
- /* Setting the palette */
- lcd_initcolregs();
+ lcd_init_colors();
-#elif LCD_BPP == LCD_COLOR8
- /* Setting the palette */
- lcd_setcolreg (CONSOLE_COLOR_BLACK, 0, 0, 0);
- lcd_setcolreg (CONSOLE_COLOR_RED, 0xFF, 0, 0);
- lcd_setcolreg (CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
- lcd_setcolreg (CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
- lcd_setcolreg (CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
- lcd_setcolreg (CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
- lcd_setcolreg (CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
- lcd_setcolreg (CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
- lcd_setcolreg (CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
-#endif
-
-#ifndef CONFIG_SYS_WHITE_ON_BLACK
- lcd_setfgcolor (CONSOLE_COLOR_BLACK);
- lcd_setbgcolor (CONSOLE_COLOR_WHITE);
+#ifdef CONFIG_SYS_WHITE_ON_BLACK
+ lcd_setfgcolor (console_color_white);
+ lcd_setbgcolor (console_color_black);
#else
- lcd_setfgcolor (CONSOLE_COLOR_WHITE);
- lcd_setbgcolor (CONSOLE_COLOR_BLACK);
+ lcd_setfgcolor (console_color_black);
+ lcd_setbgcolor (console_color_white);
#endif /* CONFIG_SYS_WHITE_ON_BLACK */
#ifdef LCD_TEST_PATTERN
test_pattern();
#else
- /* set framebuffer to background color */
+ /* set framebuffer to background color (only works if depth is 8
+ * or background is black) */
memset ((char *)lcd_base,
COLOR_MASK(lcd_getbgcolor()),
lcd_line_length*panel_info.vl_row);
@@ -401,6 +628,45 @@ U_BOOT_CMD(
""
);
+static int lcd_init_colors(void)
+{
+ if (panel_info.vl_bpix == LCD_MONOCHROME) {
+ /* Setting the palette */
+ lcd_initcolregs();
+ console_color_black = 0;
+ console_color_white = 1;
+ } else if (panel_info.vl_bpix == LCD_COLOR8) {
+ /* Setting the palette */
+ lcd_setcolreg (0, 0, 0, 0); /* black */
+ lcd_setcolreg (1, 0xFF, 0, 0); /* red */
+ lcd_setcolreg (2, 0, 0xFF, 0); /* green */
+ lcd_setcolreg (3, 0xFF, 0xFF, 0); /* yellow */
+ lcd_setcolreg (4, 0, 0, 0xFF); /* blue */
+ lcd_setcolreg (5, 0xFF, 0, 0xFF); /* magenta */
+ lcd_setcolreg (6, 0, 0xFF, 0xFF); /* cyan */
+ lcd_setcolreg (14, 0xAA, 0xAA, 0xAA); /* grey */
+ lcd_setcolreg (15, 0xFF, 0xFF, 0xFF); /* white */
+ console_color_black = 0;
+ console_color_white = 15;
+ } else if (panel_info.vl_bpix == LCD_COLOR16) {
+ console_color_white = 0xffff;
+ console_color_black = 0x0000;
+ } else if (panel_info.vl_bpix == LCD_COLOR24) {
+ console_color_white = 0x00ffffff;
+ console_color_black = 0x00000000;
+ }
+
+#ifdef CONFIG_LCD_LOGO
+ if (panel_info.vl_bpix != LCD_COLOR16) {
+ if (console_color_white >= BMP_LOGO_OFFSET) {
+ printf("Default Color Map overlaps with Logo Color Map!\n");
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
/*----------------------------------------------------------------------*/
static int lcd_init (void *lcdbase)
@@ -409,6 +675,15 @@ static int lcd_init (void *lcdbase)
debug ("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
lcd_ctrl_init (lcdbase);
+
+
+ /* If no panel setup then return an error */
+ if (!panel_info.vl_row || !panel_info.vl_col)
+ return -1;
+
+ if (lcd_init_colors() < 0)
+ return -1;
+
lcd_is_enabled = 1;
lcd_clear (NULL, 1, 1, NULL); /* dummy args */
lcd_enable ();
@@ -435,6 +710,15 @@ static int lcd_init (void *lcdbase)
*
* Note that this is running from ROM, so no write access to global data.
*/
+#ifdef CONFIG_BOARD_LCD_SETMEM
+ulong lcd_setmem (ulong addr)
+{
+ ulong size;
+ size = board_lcd_setmem(addr);
+ addr -= size;
+ return addr;
+}
+#else
ulong lcd_setmem (ulong addr)
{
ulong size;
@@ -455,6 +739,7 @@ ulong lcd_setmem (ulong addr)
return (addr);
}
+#endif
/*----------------------------------------------------------------------*/
@@ -608,7 +893,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
ushort *cmap_base = NULL;
ushort i, j;
uchar *fb;
- bmp_image_t *bmp=(bmp_image_t *)bmp_image;
+ bmp_image_t *bmp;
uchar *bmap;
ushort padded_line;
unsigned long width, height, byte_width;
@@ -622,6 +907,10 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
volatile cpm8xx_t *cp = &(immr->im_cpm);
#endif
+ if (!bmp_image)
+ return 1;
+ bmp = (bmp_image_t *)bmp_image;
+
if (!((bmp->header.signature[0]=='B') &&
(bmp->header.signature[1]=='M'))) {
printf ("Error: no valid bmp image at %lx\n", bmp_image);
@@ -636,14 +925,14 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
bpix = NBITS(panel_info.vl_bpix);
- if ((bpix != 1) && (bpix != 8) && (bpix != 16)) {
+ if ((bpix != 1) && (bpix != 8) && (bpix != 16) && (bpix != 32)) {
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
bpix, bmp_bpix);
return 1;
}
/* We support displaying 8bpp BMPs on 16bpp LCDs */
- if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16)) {
+ if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16) && (bmp_bpix != 16 || bpix != 32)) {
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
bpix,
le16_to_cpu(bmp->header.bit_count));
@@ -714,14 +1003,15 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if (x == BMP_ALIGN_CENTER)
- x = max(0, (pwidth - width) / 2);
+ x = max(0, ((int)pwidth - (int)width) / 2);
else if (x < 0)
- x = max(0, pwidth - width + x + 1);
+ x = max(0, (int)pwidth - (int)width + x + 1);
if (y == BMP_ALIGN_CENTER)
- y = max(0, (panel_info.vl_row - height) / 2);
+ y = max(0, ((int)panel_info.vl_row - (int)height) / 2);
else if (y < 0)
- y = max(0, panel_info.vl_row - height + y + 1);
+ y = max(0, (int)panel_info.vl_row - (int)height + y + 1);
+
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
if ((x + width)>pwidth)
@@ -762,22 +1052,42 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
#if defined(CONFIG_BMP_16BPP)
case 16:
- for (i = 0; i < height; ++i) {
- WATCHDOG_RESET();
- for (j = 0; j < width; j++) {
+ if (bpix == 32) {
+ for (i = 0; i < height; ++i) {
+ WATCHDOG_RESET();
+ for (j = 0; j < width; j++) {
+ uint32_t color;
+
+ /* Convert bmp from 16bpp->32bpp */
+ /* Red */
+ color = (bmap[1] << 8) | bmap[0];
+ fb[2] = (color >> 8) & 0xf8;
+ fb[1] = (color >> 3) & 0xfc;
+ fb[0] = (color << 3) & 0xf8;
+ fb += 4;
+ bmap+=2;
+ }
+ bmap += (padded_line - width) * 2;
+ fb -= (width * 4 + lcd_line_length);
+ }
+ } else {
+ 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;
+ *(fb++) = ((bmap[0] & 0x1f) << 2) |
+ (bmap[1] & 0x03);
+ *(fb++) = (bmap[0] & 0xe0) |
+ ((bmap[1] & 0x7c) >> 2);
+ bmap += 2;
#else
- *(fb++) = *(bmap++);
- *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
+ *(fb++) = *(bmap++);
#endif
+ }
+ bmap += (padded_line - width) * 2;
+ fb -= (width * 2 + lcd_line_length);
}
- bmap += (padded_line - width) * 2;
- fb -= (width * 2 + lcd_line_length);
}
break;
#endif /* CONFIG_BMP_16BPP */
@@ -786,6 +1096,10 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
break;
};
+#ifdef CONFIG_ARM
+ /* Flush the cache to make sure display tracks content of memory */
+ flush_cache(0, ~0);
+#endif
return (0);
}
#endif
@@ -796,6 +1110,7 @@ static void *lcd_logo (void)
char *s;
ulong addr;
static int do_splash = 1;
+ int ret;
if (do_splash && (s = getenv("splashimage")) != NULL) {
int x = 0, y = 0;
@@ -828,7 +1143,12 @@ static void *lcd_logo (void)
}
#endif
- if (lcd_display_bitmap (addr, x, y) == 0) {
+ ret = lcd_display_bitmap (addr, x, y);
+#ifdef CONFIG_VIDEO_BMP_GZIP
+ if ((unsigned long)bmp != addr)
+ free((void *)addr);
+#endif
+ if (ret == 0) {
return ((void *)lcd_base);
}
}
@@ -853,3 +1173,79 @@ static void *lcd_logo (void)
/************************************************************************/
/************************************************************************/
+
+#ifdef CONFIG_LCD_PERCENT
+#define PERCENT_BUF_SIZE 128
+static struct {
+ int size;
+ int total;
+ ulong now, when;
+ int percent;
+ char string[PERCENT_BUF_SIZE];
+} percent_data;
+
+void lcd_percent_init(int size)
+{
+ percent_data.size = 0;
+ percent_data.percent = -1;
+ percent_data.total = size;
+ percent_data.when = get_timer(0);
+}
+
+void lcd_percent_update(int size)
+{
+ int percent;
+ char buf[PERCENT_BUF_SIZE];
+ char *src, *dst;
+
+ if (percent_data.string[0]) {
+ unsigned long long n = size * 100ULL;
+ do_div(n, percent_data.total);
+ percent = (int)n;
+ percent_data.now = get_timer(0);
+ if (percent != percent_data.percent) {
+ if (percent == 100
+ || !percent_data.size
+ || ((percent_data.now - percent_data.when) > (CONFIG_SYS_HZ/4))) {
+ percent_data.percent = percent;
+ /* copy string into buf, replace '/P' with percent value */
+ dst = buf;
+ src = percent_data.string;
+ while (*src && (dst < &buf[PERCENT_BUF_SIZE-10])) {
+ if (src[0] == '/' && src[1] == 'P') {
+ dst += sprintf(dst, "%d", percent);
+ src+=2;
+ } else
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+ output_lcd_string(buf);
+ percent_data.when = percent_data.now;
+ }
+ }
+ percent_data.size = size;
+ }
+}
+
+static int do_lcd_percent (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc > 1)
+ strncpy(percent_data.string, argv[1], sizeof(percent_data.string) - 1);
+ else
+ percent_data.string[0] = '\0';
+ return 0;
+}
+
+U_BOOT_CMD(
+ lcd_percent, 2, 1, do_lcd_percent,
+ "setup percentage output on LCD",
+ " - string to print when percent changes (/P is replaced with percent)"
+);
+#else
+void lcd_percent_init(int total_size)
+{
+}
+void lcd_percent_update(int size)
+{
+}
+#endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a5fa2b5d85..fc6eb59244 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -31,6 +31,8 @@ COBJS-$(CONFIG_MARVELL_MFP) += mvmfp.o
COBJS-$(CONFIG_MXC_GPIO) += mxc_gpio.o
COBJS-$(CONFIG_PCA953X) += pca953x.o
COBJS-$(CONFIG_S5P) += s5p_gpio.o
+COBJS-$(CONFIG_TWL4030_GPIO) += twl4030-gpio.o
+COBJS-$(CONFIG_TWL4030_PWM) += twl4030-pwm.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
new file mode 100644
index 0000000000..57c12fcfb9
--- /dev/null
+++ b/drivers/gpio/twl4030-gpio.c
@@ -0,0 +1,105 @@
+#include <common.h>
+#include <twl4030.h>
+
+#define BIT(x) (1 << (x))
+
+/* GPIO_CTRL Fields */
+#define MASK_GPIO_CTRL_GPIO_ON BIT(2)
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+ return twl4030_i2c_write_u8(TWL4030_CHIP_GPIO, data, address);
+}
+
+static inline int gpio_twl4030_read(u8 address)
+{
+ u8 data;
+ int ret = 0;
+
+ ret = twl4030_i2c_read_u8(TWL4030_CHIP_GPIO, &data, address);
+ return (ret < 0) ? ret : data;
+}
+
+int twl4030_set_gpio_direction(unsigned int gpio, unsigned int is_input)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 reg = 0;
+ u8 base = REG_GPIODATADIR1 + d_bnk;
+ int ret = 0;
+
+ ret = gpio_twl4030_read(base);
+ if (ret >= 0) {
+ if (is_input)
+ reg = ret & ~d_msk;
+ else
+ reg = ret | d_msk;
+
+ ret = gpio_twl4030_write(base, reg);
+ }
+
+ return ret;
+}
+
+int twl4030_set_gpio_dataout(unsigned int gpio, unsigned int enable)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 base = 0;
+
+ if (enable)
+ base = REG_SETGPIODATAOUT1 + d_bnk;
+ else
+ base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+ return gpio_twl4030_write(base, d_msk);
+}
+
+int twl4030_get_gpio_datain(unsigned int gpio)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_off = gpio & 0x7;
+ u8 base = 0;
+ int ret = 0;
+
+ if (unlikely((gpio >= TWL4030_GPIO_MAX)
+ || !(gpio_usage_count & BIT(gpio))))
+ return -1;
+
+ base = REG_GPIODATAIN1 + d_bnk;
+ ret = gpio_twl4030_read(base);
+ if (ret > 0)
+ ret = (ret >> d_off) & 0x1;
+
+ return ret;
+}
+
+int twl4030_request_gpio(unsigned int gpio)
+{
+ int status = 0;
+
+ /* on first use, turn GPIO module "on" */
+ if (!gpio_usage_count) {
+ // struct twl4030_gpio_platform_data *pdata;
+ u8 value = MASK_GPIO_CTRL_GPIO_ON;
+
+ status = gpio_twl4030_write(REG_GPIO_CTRL, value);
+ }
+
+ if (!status)
+ gpio_usage_count |= (0x1 << gpio);
+
+ return status;
+}
+
+void twl4030_free_gpio(unsigned int gpio)
+{
+ gpio_usage_count &= ~BIT(gpio);
+
+ /* on last use, switch off GPIO module */
+ if (!gpio_usage_count)
+ gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+}
diff --git a/drivers/gpio/twl4030-pwm.c b/drivers/gpio/twl4030-pwm.c
new file mode 100644
index 0000000000..dfbb7f5b59
--- /dev/null
+++ b/drivers/gpio/twl4030-pwm.c
@@ -0,0 +1,126 @@
+#include <common.h>
+#include <twl4030.h>
+
+/* INTRB register offsets (TWL4030_CHIP_INTBR) */
+#define TWL_INTBR_PMBR1 0x92
+#define TWL_INTBR_GPBR1 0x91
+
+/*PWM0 register offsets (TWL4030_CHIP_PWM0) */
+#define TWL_LED_PWMON 0xf8
+#define TWL_LED_PWMOFF 0xf9
+
+#if 0
+#define PWM_PRINT(fmt, args...) printf(fmt, ## args)
+#else
+#define PWM_PRINT(fmt, args...)
+#endif
+
+int twl4030_set_pwm0(int level, int max_brightness)
+{
+ u8 mux_pwm, enb_pwm;
+ unsigned char c;
+ int status;
+
+ PWM_PRINT("%s: level %d\n", __FUNCTION__, level);
+ if (level > max_brightness)
+ return -1;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &mux_pwm, TWL_INTBR_PMBR1);
+ twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &enb_pwm, TWL_INTBR_GPBR1);
+
+ PWM_PRINT("%s: enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+
+ if (level == 0) {
+ /* disable pwm0 output and clock */
+ enb_pwm &= ~0x05;
+ /* change pwm0 pin to gpio pin */
+ mux_pwm &= ~0x0c;
+
+ PWM_PRINT("%s: disable enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ enb_pwm, TWL_INTBR_GPBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -2;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ mux_pwm, TWL_INTBR_PMBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -3;
+ }
+#if 0
+ PWM_PRINT("%s: turn off GPIO_%d as backlight!\n", __FUNCTION__, omap3logic_dss_lcd_data.lcd_gpio_backlight);
+ /* Turn off the backlight! */
+ gpio_set_value(omap3logic_dss_lcd_data.lcd_gpio_backlight, 0);
+#endif
+ return 0;
+ }
+
+ if (((enb_pwm & 0x5) != 0x5) || ((mux_pwm & 0x0c) != 0x4)) {
+ /* change gpio pin to pwm0 pin */
+ mux_pwm = (mux_pwm & ~0xc) | 0x04;
+ /* enable pwm0 output and clock*/
+ enb_pwm = (enb_pwm & ~0x5) | 0x05;
+
+ PWM_PRINT("%s: enable enb_pwm %02x mux_pwm %02x\n", __FUNCTION__, enb_pwm, mux_pwm);
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ mux_pwm, TWL_INTBR_PMBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -4;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_INTBR,
+ enb_pwm, TWL_INTBR_GPBR1);
+ if (status) {
+ printf("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -5;
+ }
+#if 0
+ PWM_PRINT("%s: turn on GPIO_%d as backlight!\n", __FUNCTION__, omap3logic_dss_lcd_data.lcd_gpio_backlight);
+ /* Turn on the backlight! */
+ gpio_set_value(omap3logic_dss_lcd_data.lcd_gpio_backlight, 1);
+#endif
+ }
+
+ /* 255 -> 1, 1 -> 126 */
+ c = (max_brightness * 126 + (1 - 126) * level) / (max_brightness - 1);
+
+ PWM_PRINT("%s: c %d (%d%% on)\n", __FUNCTION__, c, (((max_brightness+1)-c) * 100)/(max_brightness+1));
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_PWM0, 0x7F, TWL_LED_PWMOFF);
+ if (status) {
+ PWM_PRINT("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -6;
+ }
+ status = twl4030_i2c_write_u8(TWL4030_CHIP_PWM0, c, TWL_LED_PWMON);
+ if (status) {
+ PWM_PRINT("%s:%d status %d\n", __FUNCTION__, __LINE__, status);
+ return -7;
+ }
+ return 0;
+}
+
+void twl4030_dump_pwm0(void)
+{
+ int result;
+ u8 mux_pwm, enb_pwm;
+ u8 off_period, on_period;
+
+ result = twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &mux_pwm,
+ TWL_INTBR_PMBR1);
+ result |= twl4030_i2c_read_u8(TWL4030_CHIP_INTBR, &enb_pwm,
+ TWL_INTBR_GPBR1);
+
+ result |= twl4030_i2c_read_u8(TWL4030_CHIP_PWM0, &off_period,
+ TWL_LED_PWMOFF);
+ result |=twl4030_i2c_read_u8(TWL4030_CHIP_PWM0, &on_period,
+ TWL_LED_PWMON);
+
+ if (result) {
+ printf("%s: failed to read TWL regitsters; result %d\n", __FUNCTION__, result);
+ return;
+ }
+ printf("%s: mux_pwm %02x enb_pwm %02x off_period %02x on_period %02x\n",
+ __FUNCTION__, mux_pwm, enb_pwm, off_period, on_period);
+}
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 71251d8007..ec02a5d33e 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -318,6 +318,10 @@ int i2c_probe (uchar chip)
return res;
}
+ // Pre-enable the peripheral. Otherwise it randomly would not transmit.
+ // When it doesn't tramsit the probe command reports spurious addresses.
+ writew(I2C_CON_EN, &i2c_base->con);
+
/* wait until bus not busy */
wait_for_bb ();
diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c
index 15d41e55bd..83d2791887 100644
--- a/drivers/mmc/omap3_mmc.c
+++ b/drivers/mmc/omap3_mmc.c
@@ -33,6 +33,36 @@
#include "omap3_mmc.h"
+#undef DEBUG_MMC
+
+#ifdef DEBUG_MMC
+#define MMC_PRINTF(fmt, args...) printf(fmt, ## args)
+#else
+#define MMC_PRINTF(fmt, args...)
+#endif
+
+#define USE_NEW_TRANSPEED_ENCODING
+
+#ifdef USE_NEW_TRANSPEED_ENCODING
+/* TRAN_SPEED Bit encoding:
+ * bits 2:0 transfer rate unit
+ * 0=100kbit/s, 1=1Mbit/s, 2=10Mbit/s, 3=100Mbit/s, 4... 7=reserved
+ * 6:3 time value
+ * 0=reserved, 1=1.0, 2=1.2, 3=1.3, 4=1.5, 5=2.0, 6=2.5, 7=3.0,
+ * 8=3.5, 9=4.0, A=4.5, B=5.0, C=5.5, D=6.0, E=7.0, F=8.0
+ */
+
+/* trans_rate is 1/10 of actual while trans_value is 10x actual.
+ * multiplication of both together gives speed, or negative if
+ * trans_rate is reserved */
+int trans_rate[8] = {
+ 10000, 100000, 1000000, 10000000, -1, -1 -1 -1
+};
+int trans_value[16] = {
+ -1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+#else
+
static const unsigned short mmc_transspeed_val[15][4] = {
{CLKD(10, 1), CLKD(10, 10), CLKD(10, 100), CLKD(10, 1000)},
{CLKD(12, 1), CLKD(12, 10), CLKD(12, 100), CLKD(12, 1000)},
@@ -50,6 +80,7 @@ static const unsigned short mmc_transspeed_val[15][4] = {
{CLKD(70, 1), CLKD(70, 10), CLKD(70, 100), CLKD(70, 1000)},
{CLKD(80, 1), CLKD(80, 10), CLKD(80, 100), CLKD(80, 1000)}
};
+#endif
static mmc_card_data cur_card_data;
static block_dev_desc_t mmc_blk_dev;
@@ -475,12 +506,13 @@ static unsigned long mmc_bread(int dev_num, unsigned long blknr,
return i;
}
-static unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
+/* static */ unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
{
unsigned char ret_val;
unsigned int argument;
- unsigned int trans_clk, trans_fact, trans_unit, retries = 2;
- unsigned char trans_speed;
+ unsigned int trans_clk, retries = 2;
+ unsigned int trans_fact, trans_unit;
+ int trans_speed;
mmc_resp_t mmc_resp;
ret_val = mmc_init_setup();
@@ -501,12 +533,40 @@ static unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
if (mmc_card_cur->card_type == MMC_CARD)
mmc_card_cur->version = mmc_resp.Card_CSD.spec_vers;
+ MMC_PRINTF("%s: %08x %08x %08x %08x\n", __FUNCTION__, mmc_resp.resp[0],
+ mmc_resp.resp[1], mmc_resp.resp[2], mmc_resp.resp[3]);
+
trans_speed = mmc_resp.Card_CSD.tran_speed;
+ MMC_PRINTF("%s: tran_speed %#x\n", __FUNCTION__, trans_speed);
+
ret_val = mmc_send_cmd(MMC_CMD4, MMC_DSR_DEFAULT << 16, mmc_resp.resp);
if (ret_val != 1)
return ret_val;
+ if (mmc_card_cur->max_freq && trans_speed > mmc_card_cur->max_freq) {
+ trans_speed = mmc_card_cur->max_freq;
+ }
+
+#ifdef USE_NEW_TRANSPEED_ENCODING
+ trans_unit = trans_speed & MMC_CSD_TRAN_SPEED_UNIT_MASK;
+ trans_fact = trans_speed & MMC_CSD_TRAN_SPEED_FACTOR_MASK;
+ trans_unit >>= 0;
+ trans_fact >>= 3;
+
+ MMC_PRINTF("%s: trans_unit %u trans_fact %u\n", __FUNCTION__, trans_unit, trans_fact);
+ trans_speed = trans_rate[trans_unit] * trans_value[trans_fact];
+ MMC_PRINTF("%s: trans_speed %d\n", __FUNCTION__, trans_speed);
+ if (trans_speed < 0)
+ return 0;
+ MMC_PRINTF("%s: MMC_CLOCK %u\n", __FUNCTION__, (MMC_CLOCK_REFERENCE * 1000000));
+ trans_clk = (MMC_CLOCK_REFERENCE * 1000000) / trans_speed;
+ MMC_PRINTF("%s: trans_clk %u\n", __FUNCTION__, trans_clk);
+ if (trans_speed * trans_clk < (MMC_CLOCK_REFERENCE * 1000000))
+ trans_clk++;
+ if (trans_clk > 1023)
+ trans_clk = 1023;
+#else
trans_unit = trans_speed & MMC_CSD_TRAN_SPEED_UNIT_MASK;
trans_fact = trans_speed & MMC_CSD_TRAN_SPEED_FACTOR_MASK;
@@ -521,6 +581,8 @@ static unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
trans_fact >>= 3;
trans_clk = mmc_transspeed_val[trans_fact - 1][trans_unit] * 2;
+#endif
+ MMC_PRINTF("%s:%d trans_clk %#x\n", __FUNCTION__, __LINE__, trans_clk);
ret_val = mmc_clock_config(CLK_MISC, trans_clk);
if (ret_val != 1)
@@ -547,9 +609,23 @@ static unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
int mmc_legacy_init(int dev)
{
+ char *p, *q, buf[32];
+
if (mmc_set_dev(dev) != 0)
return 1;
+ sprintf(buf, "mmc%d_max_freq_mhz", dev);
+ p = getenv(buf);
+ if (p) {
+ cur_card_data.max_freq = (unsigned int)simple_strtoull(p, &q, 0);
+ if (q && *q)
+ cur_card_data.max_freq = 0;
+ } else
+ cur_card_data.max_freq = 0;
+
+ if (cur_card_data.max_freq)
+ printf("MMC%d: max frequency limited to %uMHz\n", dev, cur_card_data.max_freq);
+
if (configure_mmc(&cur_card_data) != 1)
return 1;
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 5a5ecdfe3c..f01f157c15 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmtd.o
+COBJS-$(CONFIG_MTD_DEBUG) += mtd_debug.o
COBJS-$(CONFIG_MTD_DEVICE) += mtdcore.o
COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o
diff --git a/drivers/mtd/mtd_debug.c b/drivers/mtd/mtd_debug.c
new file mode 100644
index 0000000000..31913f0565
--- /dev/null
+++ b/drivers/mtd/mtd_debug.c
@@ -0,0 +1,18 @@
+/*
+ * MTD verbose debug
+ *
+ * (C) 2011 Peter Barada <peter.barada@logicpd.com>
+ *
+ * This code is GPL
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compat.h>
+#include <ubi_uboot.h>
+
+#ifdef CONFIG_MTD_DEBUG
+#ifndef CONFIG_MTD_DEBUG_VERBOSE
+#define CONFIG_MTD_DEBUG_VERBOSE -1
+#endif
+int mtd_debug_verbose = CONFIG_MTD_DEBUG_VERBOSE;
+#endif
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8b598f6bfe..975d152e79 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -50,6 +50,7 @@ COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o
COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
+COBJS-$(CONFIG_MTD_NAND_ECC_BCH) += nand_bch.o
endif
COBJS := $(COBJS-y)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 52f8575aac..1092a79732 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -43,6 +43,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand_bch.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
@@ -136,7 +137,11 @@ static void nand_release_device (struct mtd_info *mtd)
static uint8_t nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- return readb(chip->IO_ADDR_R);
+ uint8_t byte;
+
+ byte = readb(chip->IO_ADDR_R);
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND R %02x\n", byte);
+ return byte;
}
/**
@@ -149,7 +154,11 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
static uint8_t nand_read_byte16(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+ uint8_t byte;
+
+ byte = (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND R %02x\n", byte);
+ return byte;
}
/**
@@ -162,7 +171,11 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
static u16 nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- return readw(chip->IO_ADDR_R);
+ u16 word;
+
+ word = readw(chip->IO_ADDR_R);
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND R %04x\n", word);
+ return word;
}
/**
@@ -201,6 +214,8 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
int i;
struct nand_chip *chip = mtd->priv;
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND W %d bytes\n", len);
+
for (i = 0; i < len; i++)
writeb(buf[i], chip->IO_ADDR_W);
}
@@ -218,6 +233,8 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
int i;
struct nand_chip *chip = mtd->priv;
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND R %d bytes\n", len);
+
for (i = 0; i < len; i++)
buf[i] = readb(chip->IO_ADDR_R);
}
@@ -236,8 +253,10 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
struct nand_chip *chip = mtd->priv;
for (i = 0; i < len; i++)
- if (buf[i] != readb(chip->IO_ADDR_R))
+ if (buf[i] != readb(chip->IO_ADDR_R)) {
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND verify fail at offset %d\n", i);
return -EFAULT;
+ }
return 0;
}
@@ -256,6 +275,8 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
u16 *p = (u16 *) buf;
len >>= 1;
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND W %d words\n", len);
+
for (i = 0; i < len; i++)
writew(p[i], chip->IO_ADDR_W);
@@ -276,8 +297,20 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
u16 *p = (u16 *) buf;
len >>= 1;
- for (i = 0; i < len; i++)
- p[i] = readw(chip->IO_ADDR_R);
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND R %d words\n", len);
+
+ for (i = 0; i < len; i+=8) {
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ *p++ = readw(chip->IO_ADDR_R);
+ }
+ for (; i < len; ++i)
+ *p++ = readw(chip->IO_ADDR_R);
}
/**
@@ -399,11 +432,88 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
static int nand_check_wp(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- /* Check the WP bit */
+
+ /* Check the WP bit. To do so requires resetting the device to
+ force the status back to its reset value (so WP becomes whether
+ the WP pin is set). */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ /* Now check the WP bit */
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
+/*
+ * nand_get_features: - Read the features of the NAND chip
+ * @param mtd nand mtd instance
+ * @param faddr nand feature address
+ * @param features return 4-byte array of features
+ *
+ * @return 0 on success, -1 in case of errors
+ */
+int nand_get_features(struct mtd_info *mtd, uint8_t faddr, uint8_t *features)
+{
+ struct nand_chip *chip = mtd->priv;
+ int i;
+
+ chip->select_chip(mtd, 0);
+
+ /* Send the status command */
+ chip->cmd_ctrl(mtd, NAND_CMD_GET_FEATURES, NAND_CTRL_CHANGE | NAND_CTRL_CLE);
+
+ /* Send the feature address */
+ chip->cmd_ctrl(mtd, faddr, NAND_CTRL_CHANGE | NAND_CTRL_ALE);
+ /* Switch to data access */
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_CTRL_CHANGE | NAND_NCE);
+
+ ndelay(100);
+
+ for (i=0; i<4; ++i)
+ features[i] = chip->read_byte(mtd);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "%s: %02x %02x %02x %02x\n", __FUNCTION__, features[0],
+ features[1], features[2], features[3]);
+
+ return 0;
+}
+
+/**
+ * nand_set_features - [GENERIC] set features array
+ * @mtd: MTD device structure
+ * @faddr: feature address
+ * @params: 4-byte array of parameters to write
+ */
+int nand_set_features(struct mtd_info *mtd, uint8_t faddr, uint8_t *features)
+{
+ struct nand_chip *chip;
+
+ chip = mtd->priv;
+
+ chip->select_chip(mtd, 0);
+
+ /* Send the status command */
+ chip->cmd_ctrl(mtd, NAND_CMD_SET_FEATURES, NAND_CTRL_CHANGE | NAND_CTRL_CLE);
+ /* Send the feature address */
+ chip->cmd_ctrl(mtd, faddr, NAND_CTRL_CHANGE | NAND_CTRL_ALE);
+ /* Switch to data access */
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_CTRL_CHANGE | NAND_NCE);
+
+ ndelay(100);
+ if (chip->options & NAND_BUSWIDTH_16) {
+ uint16_t ftrs16[4];
+ int i;
+ for (i=0; i<4; ++i)
+ ftrs16[i] = features[i];
+ chip->write_buf(mtd, (uint8_t *)ftrs16, sizeof(ftrs16));
+ } else
+ chip->write_buf(mtd, features, 4);
+
+ udelay(2);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: faddr %02x [%02x %02x %02x %02x]\n", __FUNCTION__, faddr, features[0], features[1], features[2], features[3]);
+
+ return 0;
+}
+
/**
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure
@@ -751,7 +861,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
*
* Not for syndrome calculating ecc controllers, which use a special oob layout
*/
-static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
{
chip->read_buf(mtd, buf, mtd->writesize);
@@ -808,7 +918,7 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *c
* @buf: buffer to store read data
* @page: page number to read
*/
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
{
int i, eccsize = chip->ecc.size;
@@ -850,7 +960,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
* @readlen: data length
* @bufpoi: buffer to store read data
*/
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+/* static */ int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
{
int start_step, end_step, num_steps;
uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -1170,6 +1280,26 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
sndcmd = 0;
}
+ /* If in chipe ECC mode, need to read the status
+ to see if an ECC error occurred. */
+ if (chip->ecc.mode == NAND_ECC_CHIP) {
+ int status;
+ chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd,
+ NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ status = chip->read_byte(mtd);
+ chip->cmd_ctrl(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ if (status & 0x1)
+ mtd->ecc_stats.failed++;
+ else if (status & 0x10)
+ mtd->ecc_stats.corrected++;
+ }
+
/* Now read the page into the buffer */
if (unlikely(ops->mode == MTD_OOB_RAW))
ret = chip->ecc.read_page_raw(mtd, chip,
@@ -1306,7 +1436,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
* @page: page number to read
* @sndcmd: flag whether to issue read command or not
*/
-static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
{
if (sndcmd) {
@@ -1362,7 +1492,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @chip: nand chip info structure
* @page: page number to write
*/
-static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
int status = 0;
@@ -1586,7 +1716,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
*
* Not for syndrome calculating ecc controllers, which use a special oob layout
*/
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
{
chip->write_buf(mtd, buf, mtd->writesize);
@@ -1637,7 +1767,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip
* @chip: nand chip info structure
* @buf: data buffer
*/
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+/* static */ void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
{
int i, eccsize = chip->ecc.size;
@@ -1996,7 +2126,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) {
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: "
- "Attempt to write past end of page\n");
+ "Attempt to write past end of page(%d+%d>%d)\n", ops->ooboffs, ops->ooblen, len);
return -EINVAL;
}
@@ -2585,6 +2715,9 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
return ERR_PTR(-ENODEV);
}
+ chip->maf_id = tmp_manf;
+ chip->dev_id = tmp_id;
+
if (!type)
type = nand_flash_ids;
@@ -2763,7 +2896,7 @@ int nand_scan_tail(struct mtd_info *mtd)
/*
* If no default placement scheme is given, select an appropriate one
*/
- if (!chip->ecc.layout) {
+ if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
switch (mtd->oobsize) {
case 8:
chip->ecc.layout = &nand_oob_8;
@@ -2862,6 +2995,71 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
+ if (chip->has_chip_ecc) {
+ /* Put chip into no-ECC mode */
+ uint8_t params[4] = {0x00, 0x00, 0x00, 0x00};
+ nand_set_features(mtd, 0x90, params);
+ }
+ break;
+
+ case NAND_ECC_SOFT_BCH:
+ printk(KERN_INFO "NAND ECC: SOFT_BCH\n");
+ if (!mtd_nand_has_bch()) {
+ printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n");
+ BUG();
+ }
+ chip->ecc.calculate = nand_bch_calculate_ecc;
+ chip->ecc.correct = nand_bch_correct_data;
+ chip->ecc.read_page = nand_read_page_swecc;
+ chip->ecc.read_subpage = nand_read_subpage;
+ chip->ecc.write_page = nand_write_page_swecc;
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ chip->ecc.write_page_raw = nand_write_page_raw;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.write_oob = nand_write_oob_std;
+ /*
+ * Board driver should supply ecc.size and ecc.bytes values to
+ * select how many bits are correctable; see nand_bch_init()
+ * for details.
+ * Otherwise, default to 4 bits for large page devices
+ */
+ if (!chip->ecc.size && (mtd->oobsize >= 64)) {
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 7;
+ }
+ chip->ecc.priv = nand_bch_init(mtd,
+ chip->ecc.size,
+ chip->ecc.bytes,
+ &chip->ecc.layout);
+ if (!chip->ecc.priv) {
+ printk(KERN_WARNING "BCH ECC initialization failed!\n");
+ BUG();
+ }
+
+ if (chip->has_chip_ecc) {
+ /* Put chip into no-ECC mode */
+ uint8_t params[4] = {0x00, 0x00, 0x00, 0x00};
+ nand_set_features(mtd, 0x90, params);
+ }
+ break;
+
+ case NAND_ECC_CHIP:
+ if (!chip->ecc.read_page_raw)
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ if (!chip->ecc.write_page_raw)
+ chip->ecc.write_page_raw = nand_write_page_raw;
+ chip->ecc.read_page = nand_read_page_raw;
+ chip->ecc.write_page = nand_write_page_raw;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.write_oob = nand_write_oob_std;
+ chip->ecc.size = mtd->writesize;
+ chip->ecc.bytes = 0;
+
+ if (chip->has_chip_ecc) {
+ /* Put chip into ECC mode */
+ uint8_t params[4] = {0x08, 0x00, 0x00, 0x00};
+ nand_set_features(mtd, 0x90, params);
+ }
break;
case NAND_ECC_NONE:
@@ -2875,6 +3073,11 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
+ if (chip->has_chip_ecc) {
+ /* Put chip into ECC mode */
+ uint8_t params[4] = {0x08, 0x00, 0x00, 0x00};
+ nand_set_features(mtd, 0x90, params);
+ }
break;
default:
@@ -2893,6 +3096,7 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.layout->oobavail +=
chip->ecc.layout->oobfree[i].length;
mtd->oobavail = chip->ecc.layout->oobavail;
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: oobavail %d\n", __FUNCTION__, mtd->oobavail);
/*
* Set the number of read / write steps for one page depending on ECC
@@ -2994,6 +3198,9 @@ void nand_release(struct mtd_info *mtd)
del_mtd_partitions(mtd);
#endif
+ if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
+ nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+
/* Free bad block table memory */
kfree(chip->bbt);
if (!(chip->options & NAND_OWN_BUFFERS))
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
new file mode 100644
index 0000000000..632dc7ae7c
--- /dev/null
+++ b/drivers/mtd/nand/nand_bch.c
@@ -0,0 +1,287 @@
+/*
+ * This file provides ECC correction for more than 1 bit per block of data,
+ * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
+ *
+ * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * This file 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 or (at your option) any
+ * later version.
+ *
+ * This file 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 file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#if 1
+#if 1
+#include <config.h>
+#include <common.h>
+#include <linux/mtd/compat.h>
+#include <malloc.h>
+#endif
+#include <linux/types.h>
+// #include <linux/kernel.h>
+// #include <linux/module.h>
+// #include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/bch.h>
+#else
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/bch.h>
+#endif
+
+/**
+ * struct nand_bch_control - private NAND BCH control structure
+ * @bch: BCH control structure
+ * @ecclayout: private ecc layout for this BCH configuration
+ * @errloc: error location array
+ * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
+ */
+struct nand_bch_control {
+ struct bch_control *bch;
+ struct nand_ecclayout ecclayout;
+ unsigned int *errloc;
+ unsigned char *eccmask;
+};
+
+/**
+ * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
+ * @mtd: MTD block structure
+ * @buf: input buffer with raw data
+ * @code: output buffer with ECC
+ */
+int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+ unsigned char *code)
+{
+ const struct nand_chip *chip = mtd->priv;
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int i;
+
+#ifdef DEBUG_BCH
+ printf("%s:%d buf %p code %p\n", __FUNCTION__, __LINE__, buf, code);
+ for (i=0; i<16; ++i)
+ printf("%s%02x", !i?"dat: ":" ", buf[i]);
+ printf("\n");
+#endif
+ memset(code, 0, chip->ecc.bytes);
+ encode_bch(nbc->bch, buf, chip->ecc.size, code);
+
+ /* apply mask so that an erased page is a valid codeword */
+ for (i = 0; i < chip->ecc.bytes; i++)
+ code[i] ^= nbc->eccmask[i];
+
+#ifdef DEBUG_BCH
+ printf("%s:%d code:", __FUNCTION__, __LINE__);
+ for (i=0; i<7; ++i)
+ printf(" %02x", code[i]);
+ printf("\n");
+#endif
+
+ return 0;
+}
+// EXPORT_SYMBOL(nand_bch_calculate_ecc);
+
+/**
+ * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd: MTD block structure
+ * @buf: raw data read from the chip
+ * @read_ecc: ECC from the chip
+ * @calc_ecc: the ECC calculated from raw data
+ *
+ * Detect and correct bit errors for a data byte block
+ */
+int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+ const struct nand_chip *chip = mtd->priv;
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int *errloc = nbc->errloc;
+ int i, count;
+
+#ifdef DEBUG_BCH
+ printf("%s:%d buf %p read_ecc %p calc_ecc %p\n", __FUNCTION__, __LINE__, buf, read_ecc, calc_ecc);
+ for (i=0; i<16; ++i)
+ printf("%s%02x", !i?"dat: ":" ", buf[i]);
+ printf("\n");
+ for (i=0; i<7; ++i)
+ printf("%s%02x", !i?"read_ecc: ":" ", read_ecc[i]);
+ printf("\n");
+ for (i=0; i<7; ++i)
+ printf("%s%02x", !i?"calc_ecc: ":" ", calc_ecc[i]);
+ printf("\n");
+#endif
+
+ count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
+ NULL, errloc);
+ if (count > 0) {
+ for (i = 0; i < count; i++) {
+ if (errloc[i] < (chip->ecc.size*8))
+ /* error is located in data, correct it */
+ buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
+ /* else error in ecc, no action needed */
+
+ MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n",
+ __func__, errloc[i]);
+ }
+ } else if (count < 0) {
+ printk(KERN_ERR "ecc unrecoverable error\n");
+ count = -1;
+ }
+ return count;
+}
+// EXPORT_SYMBOL(nand_bch_correct_data);
+
+/**
+ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+ * @mtd: MTD block structure
+ * @eccsize: ecc block size in bytes
+ * @eccbytes: ecc length in bytes
+ * @ecclayout: output default layout
+ *
+ * Returns:
+ * a pointer to a new NAND BCH control structure, or NULL upon failure
+ *
+ * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
+ * are used to compute BCH parameters m (Galois field order) and t (error
+ * correction capability). @eccbytes should be equal to the number of bytes
+ * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
+ *
+ * Example: to configure 4 bit correction per 512 bytes, you should pass
+ * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+ * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
+ */
+struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
+ struct nand_ecclayout **ecclayout)
+{
+ unsigned int m, t, eccsteps, i;
+ struct nand_ecclayout *layout;
+ struct nand_bch_control *nbc = NULL;
+ unsigned char *erased_page;
+
+ if (!eccsize || !eccbytes) {
+ printk(KERN_WARNING "ecc parameters not supplied\n");
+ goto fail;
+ }
+
+ m = fls(1+8*eccsize);
+ t = (eccbytes*8)/m;
+
+ nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
+ if (!nbc)
+ goto fail;
+
+ nbc->bch = init_bch(m, t, 0);
+ if (!nbc->bch)
+ goto fail;
+
+ /* verify that eccbytes has the expected value */
+ if (nbc->bch->ecc_bytes != eccbytes) {
+ printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
+ eccbytes, nbc->bch->ecc_bytes);
+ goto fail;
+ }
+
+ eccsteps = mtd->writesize/eccsize;
+
+ /* if no ecc placement scheme was provided, build one */
+ if (!*ecclayout) {
+
+ /* handle large page devices only */
+ if (mtd->oobsize < 64) {
+ printk(KERN_WARNING "must provide an oob scheme for "
+ "oobsize %d\n", mtd->oobsize);
+ goto fail;
+ }
+
+ layout = &nbc->ecclayout;
+ layout->eccbytes = eccsteps*eccbytes;
+
+ /* reserve 2 bytes for bad block marker */
+ if (layout->eccbytes+2 > mtd->oobsize) {
+ printk(KERN_WARNING "no suitable oob scheme available "
+ "for oobsize %d eccbytes %u\n", mtd->oobsize,
+ eccbytes);
+ goto fail;
+ }
+ /* put ecc bytes at oob tail */
+ for (i = 0; i < layout->eccbytes; i++)
+ layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
+
+ layout->oobfree[0].offset = 2;
+ layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
+
+ *ecclayout = layout;
+ }
+
+ /* sanity checks */
+ if (8*(eccsize+eccbytes) >= (1 << m)) {
+ printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+ goto fail;
+ }
+ if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+ printk(KERN_WARNING "invalid ecc layout\n");
+ goto fail;
+ }
+
+ nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+ nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
+ if (!nbc->eccmask || !nbc->errloc)
+ goto fail;
+ /*
+ * compute and store the inverted ecc of an erased ecc block
+ */
+ erased_page = kmalloc(eccsize, GFP_KERNEL);
+ if (!erased_page)
+ goto fail;
+
+ memset(erased_page, 0xff, eccsize);
+ memset(nbc->eccmask, 0, eccbytes);
+ encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
+ kfree(erased_page);
+
+ for (i = 0; i < eccbytes; i++)
+ nbc->eccmask[i] ^= 0xff;
+
+ return nbc;
+fail:
+ nand_bch_free(nbc);
+ return NULL;
+}
+// EXPORT_SYMBOL(nand_bch_init);
+
+/**
+ * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
+ * @nbc: NAND BCH control structure
+ */
+void nand_bch_free(struct nand_bch_control *nbc)
+{
+ if (nbc) {
+ free_bch(nbc->bch);
+ kfree(nbc->errloc);
+ kfree(nbc->eccmask);
+ kfree(nbc);
+ }
+}
+// EXPORT_SYMBOL(nand_bch_free);
+
+// MODULE_LICENSE("GPL");
+// MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
+// MODULE_DESCRIPTION("NAND software BCH ECC support");
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 5a6f7aec88..82e661d39c 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -120,6 +120,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
priv_nand->bbt = NULL;
}
+ lcd_percent_init(erase_length);
+
for (erased_length = 0;
erased_length < erase_length;
erase.addr += meminfo->erasesize) {
@@ -138,6 +140,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
if (!opts->spread)
erased_length++;
+ lcd_percent_update(erased_length);
+
continue;
} else if (ret < 0) {
@@ -157,6 +161,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
continue;
}
+
/* format for JFFS2 ? */
if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
chip->ops.ooblen = 8;
@@ -197,10 +202,13 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
erase.addr);
}
}
+ lcd_percent_update(erased_length);
}
+ lcd_percent_update(erased_length);
if (!opts->quiet)
printf("\n");
+
if (nand_block_bad_old) {
struct nand_chip *priv_nand = meminfo->priv;
@@ -337,8 +345,11 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
int status;
int page;
struct nand_chip *chip = mtd->priv;
+
+#if 0
printf ("nand_unlock: start: %08x, length: %d!\n",
(int)start, (int)length);
+#endif
/* select the NAND device */
chipnr = (int)(start >> chip->chip_shift);
@@ -455,7 +466,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
u_char *buffer, int withoob)
{
int rval = 0, blocksize;
- size_t left_to_write = *length;
+ size_t left_to_write = *length, total_to_write;
u_char *p_buffer = buffer;
int need_skip;
@@ -499,7 +510,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
return -EINVAL;
}
- if (!need_skip) {
+ if (!need_skip && !withoob) {
rval = nand_write (nand, offset, length, buffer);
if (rval == 0)
return 0;
@@ -510,6 +521,9 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
return rval;
}
+ total_to_write = left_to_write;
+ lcd_percent_init(total_to_write);
+
while (left_to_write > 0) {
size_t block_offset = offset & (nand->erasesize - 1);
size_t write_size;
@@ -548,7 +562,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
ops.oobbuf = ops.datbuf + pagesize;
rval = nand->write_oob(nand, offset, &ops);
- if (!rval)
+ if (rval)
break;
offset += pagesize;
@@ -571,8 +585,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
}
left_to_write -= write_size;
+ lcd_percent_update(total_to_write - left_to_write);
}
+ lcd_percent_update(total_to_write);
+
return 0;
}
@@ -594,7 +611,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
u_char *buffer)
{
int rval;
- size_t left_to_read = *length;
+ size_t left_to_read = *length, total_to_read;
u_char *p_buffer = buffer;
int need_skip;
@@ -622,6 +639,9 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
return rval;
}
+ total_to_read = left_to_read;
+ lcd_percent_init(total_to_read);
+
while (left_to_read > 0) {
size_t block_offset = offset & (nand->erasesize - 1);
size_t read_length;
@@ -651,7 +671,11 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
left_to_read -= read_length;
offset += read_length;
p_buffer += read_length;
+
+ lcd_percent_update(total_to_read - left_to_read);
}
+ lcd_percent_update(total_to_read);
+
return 0;
}
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 99b9cef17c..d5ee9bc583 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -26,11 +26,15 @@
#include <asm/errno.h>
#include <asm/arch/mem.h>
#include <asm/arch/omap_gpmc.h>
+#include <asm/arch/sys_proto.h>
+#include <linux/mtd/mtd.h>
#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand_bch.h>
#include <nand.h>
static uint8_t cs;
static struct nand_ecclayout hw_nand_oob = GPMC_NAND_HW_ECC_LAYOUT;
+static struct nand_ecclayout chip_nand_oob = GPMC_NAND_CHIP_ECC_LAYOUT;
/*
* omap_nand_hwcontrol - Set the address pointers corretly for the
@@ -57,8 +61,17 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
break;
}
- if (cmd != NAND_CMD_NONE)
+ if (cmd != NAND_CMD_NONE) {
+#ifdef CONFIG_MTD_DEBUG
+ if (this->IO_ADDR_W == &gpmc_cfg->cs[cs].nand_cmd)
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND C: %02x\n", cmd & 0xff);
+ else if (this->IO_ADDR_W == &gpmc_cfg->cs[cs].nand_adr)
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND A: %02x\n", cmd & 0xff);
+ else if (this->IO_ADDR_W == &gpmc_cfg->cs[cs].nand_dat)
+ MTDDEBUG(MTD_DEBUG_LEVEL4, "NAND D: %02x\n", cmd & 0xff);
+#endif
writeb(cmd, this->IO_ADDR_W);
+ }
}
/*
@@ -156,6 +169,25 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
return 0;
}
+static int omap_correct_chip_hwecc(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *chip;
+
+ chip = mtd->priv;
+
+ printf("%s: ecc_status %02x\n", __func__, chip->ecc_status);
+ /* We stored the read status in info->ecc_status in the read.
+ If bit 0 is set, then there was an uncorrectable ECC error.
+ If bit 3 is set, then there was a correctable error (up to
+ four bits of correction). */
+ if (chip->ecc_status & 0x01)
+ return -1;
+ if (chip->ecc_status & 0x08)
+ return 4;
+ return 0;
+}
+
/*
* omap_calculate_ecc - Generate non-inverted ECC bytes.
*
@@ -192,6 +224,14 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+static int omap_calculate_chip_hwecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:\n", __func__);
+ return 0;
+}
+
+
/*
* omap_enable_ecc - This function enables the hardware ecc functionality
* @mtd: MTD device structure
@@ -224,14 +264,308 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
}
}
+static void omap_enable_chip_hwecc(struct mtd_info *mtd, int mode)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:\n", __func__);
+}
+
+/*
+ * omap_nand_chip_has_ecc - return true if chip has internal ECC
+ */
+int omap_nand_chip_has_ecc(void)
+{
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ int i;
+ uint8_t ident[5];
+
+ if (nand_curr_device < 0 ||
+ nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[nand_curr_device].name) {
+ printf("Error: Can't switch ecc, no devices available\n");
+ return 0;
+ }
+
+ mtd = &nand_info[nand_curr_device];
+ chip = mtd->priv;
+
+#if 1
+ chip->select_chip(mtd, 0);
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Wait for the chip to get the ID ready */
+ ndelay(100);
+
+ for (i=0; i<2; ++i)
+ ident[i] = chip->read_byte(mtd);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d %02x %02x\n", __FUNCTION__, __LINE__, ident[0], ident[1]);
+ if (ident[0] == NAND_MFR_MICRON) {
+ for (i=2; i<5; ++i)
+ ident[i] = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d %02x %02x %02x\n", __FUNCTION__, __LINE__, ident[2], ident[3], ident[4]);
+ if (ident[4] & 0x3)
+ chip->has_chip_ecc = 1;
+ }
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: has_chip_ecc %d\n", __FUNCTION__, chip->has_chip_ecc);
+#else
+ if (nand->maf_id == NAND_MFR_MICRON) {
+ switch(nand->dev_id) {
+ case 0x2c:
+ case 0xdc:
+ case 0xcc:
+ case 0xac:
+ case 0xbc:
+ case 0xa3:
+ case 0xb3:
+ case 0xd3:
+ case 0xc3:
+ nand->has_chip_ecc = 1;
+ return 1;
+ default:
+ break;
+ }
+ }
+#endif
+ return chip->has_chip_ecc;
+}
+
+
+static void micron_set_chip_ecc(struct mtd_info *mtd, int enable)
+{
+ uint8_t params[4];
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3,"%s:%d enable %d\n", __FUNCTION__, __LINE__, enable);
+
+ memset(params, 0x00, sizeof(params));
+ if (enable)
+ params[0] = 0x08;
+ nand_set_features(mtd, 0x90, params);
+
+#if 1
+ nand_get_features(mtd, 0x90, params);
+ MTDDEBUG(MTD_DEBUG_LEVEL4,"%s: %02x %02x %02x %02x\n", __FUNCTION__, params[0], params[1], params[2], params[3]);
+#endif
+}
+
+/**
+ * nand_read_oob_chipecc - read; get status to seeif chip ECC error
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int omap_read_oob_chipecc(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ struct nand_chip *nand;
+
+ nand = mtd->priv;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: page = %d, len = %i\n",
+ __func__, page, mtd->oobsize);
+
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+
+ /* Send the status command */
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ chip->ecc_status = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: ecc_status %02x\n", __func__, chip->ecc_status);
+ if (chip->ecc_status & (0x8|0x1)) {
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d page %d ecc_status %02x\n", __FUNCTION__, __LINE__, page, chip->ecc_status);
+ if (chip->ecc_status & 0x1)
+ mtd->ecc_stats.failed++;
+ else if (chip->ecc_status & 0x80)
+ mtd->ecc_stats.corrected += 4;
+ }
+
+ /* Send the read prefix */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
+
+/**
+ * omap_nand_command_lp - Send command to NAND large page device
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices We dont have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ register struct nand_chip *chip = mtd->priv;
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Command latch cycle */
+ omap_nand_hwcontrol(mtd, command & 0xff,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+ if (column != -1 || page_addr != -1) {
+ int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16)
+ column >>= 1;
+ omap_nand_hwcontrol(mtd, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ omap_nand_hwcontrol(mtd, column >> 8, ctrl);
+ }
+ if (page_addr != -1) {
+ omap_nand_hwcontrol(mtd, page_addr, ctrl);
+ omap_nand_hwcontrol(mtd, page_addr >> 8,
+ NAND_NCE | NAND_ALE);
+ /* One more address cycle for devices > 128MiB */
+ if (chip->chipsize > (128 << 20))
+ omap_nand_hwcontrol(mtd, page_addr >> 16,
+ NAND_NCE | NAND_ALE);
+ }
+ }
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * program and erase have their own busy handlers
+ * status, sequential in, and deplete1 need no delay
+ */
+ switch (command) {
+
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_RNDIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
+ return;
+
+ /*
+ * read error status commands require only a short delay
+ */
+ case NAND_CMD_STATUS_ERROR:
+ case NAND_CMD_STATUS_ERROR0:
+ case NAND_CMD_STATUS_ERROR1:
+ case NAND_CMD_STATUS_ERROR2:
+ case NAND_CMD_STATUS_ERROR3:
+ udelay(chip->chip_delay);
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->dev_ready)
+ break;
+ udelay(chip->chip_delay);
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
+ return;
+
+ case NAND_CMD_RNDOUT:
+ /* No ready / busy check necessary */
+ omap_nand_hwcontrol(mtd, NAND_CMD_RNDOUTSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ return;
+
+ case NAND_CMD_READ0:
+
+ /* Send the read start */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /* This applies to read commands */
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay
+ */
+ if (!chip->dev_ready) {
+ udelay(chip->chip_delay);
+ goto ready_exit;
+ }
+ }
+
+ /* Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine. */
+ ndelay(100);
+
+ nand_wait_ready(mtd);
+
+ready_exit:
+ /* If the chip has internal ECC, then we need to read the status
+ to determin if there's an ECC error - capture it for handling by
+ omap_nand_correct_chip_hwecc() later */
+ if (command == NAND_CMD_READ0) {
+ if (chip->has_chip_ecc) {
+
+ /* Send the status command */
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ chip->ecc_status = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: ecc_status %02x\n", __func__, chip->ecc_status);
+#if 0
+ if (chip->ecc_status & (0x8|0x1))
+ printk("%s:%d page %d column %d ecc_status %02x\n", __FUNCTION__, __LINE__, page_addr, column, chip->ecc_status);
+#endif
+
+ /* Send the read prefix */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ }
+ }
+
+}
+
+static enum omap_nand_ecc_mode current_ecc_method;
+enum omap_nand_ecc_mode omap_nand_current_ecc_method(void)
+{
+ return current_ecc_method;
+}
+
/*
* omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc.
* The default is to come up on s/w ecc
*
- * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc
+ * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc, 2 - chip ecc
*
*/
-void omap_nand_switch_ecc(int32_t hardware)
+void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode)
{
struct nand_chip *nand;
struct mtd_info *mtd;
@@ -257,8 +591,50 @@ void omap_nand_switch_ecc(int32_t hardware)
nand->ecc.correct = NULL;
nand->ecc.calculate = NULL;
+ /* If currently in BCH then free the priv pointer */
+ if (nand->ecc.mode == NAND_ECC_SOFT_BCH && nand->ecc.priv) {
+ nand_bch_free((struct nand_bch_control *)nand->ecc.priv);
+ nand->ecc.priv = NULL;
+ }
+
/* Setup the ecc configurations again */
- if (hardware) {
+ if (mode == OMAP_ECC_SOFT_BCH) {
+ nand->ecc.mode = NAND_ECC_SOFT_BCH;
+ nand->ecc.calculate = nand_bch_calculate_ecc;
+ nand->ecc.correct = nand_bch_correct_data;
+ nand->ecc.read_page = nand_read_page_swecc;
+ nand->ecc.read_subpage = nand_read_subpage;
+ nand->ecc.write_page = nand_write_page_swecc;
+ nand->ecc.read_page_raw = nand_read_page_raw;
+ nand->ecc.write_page_raw = nand_write_page_raw;
+ nand->ecc.read_oob = nand_read_oob_std;
+ nand->ecc.write_oob = nand_write_oob_std;
+ /*
+ * Board driver should supply ecc.size and ecc.bytes values to
+ * select how many bits are correctable; see nand_bch_init()
+ * for details.
+ * Otherwise, default to 4 bits for large page devices
+ */
+#if 1
+ /* Since switching, clear out previous ECC setup and let
+ * BCH figure it out */
+ nand->ecc.size = 0;
+ nand->ecc.bytes = 0;
+ nand->ecc.layout = NULL;
+#endif
+ if (!nand->ecc.size && (mtd->oobsize >= 64)) {
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 7;
+ }
+ nand->ecc.priv = nand_bch_init(mtd,
+ nand->ecc.size,
+ nand->ecc.bytes,
+ &nand->ecc.layout);
+ if (!nand->ecc.priv) {
+ printk(KERN_WARNING "BCH ECC initialization failed!\n");
+ BUG();
+ }
+ } else if (mode == OMAP_ECC_HW) {
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.layout = &hw_nand_oob;
nand->ecc.size = 512;
@@ -267,13 +643,41 @@ void omap_nand_switch_ecc(int32_t hardware)
nand->ecc.correct = omap_correct_data;
nand->ecc.calculate = omap_calculate_ecc;
omap_hwecc_init(nand);
- printf("HW ECC selected\n");
- } else {
+ printf("NAND: HW ECC selected\n");
+ if (nand->has_chip_ecc)
+ micron_set_chip_ecc(mtd, 0);
+ } else if (mode == OMAP_ECC_SOFT) {
nand->ecc.mode = NAND_ECC_SOFT;
/* Use mtd default settings */
nand->ecc.layout = NULL;
- printf("SW ECC selected\n");
- }
+ printf("NAND: SW ECC selected\n");
+ if (nand->has_chip_ecc)
+ micron_set_chip_ecc(mtd, 0);
+ } else if (mode == OMAP_ECC_CHIP) {
+ if (!nand->has_chip_ecc) {
+ printf("NAND: Chip does not have internal ECC!\n");
+ return;
+ }
+ nand->ecc.bytes = 0;
+ nand->ecc.size = 2048;
+ nand->ecc.calculate = omap_calculate_chip_hwecc;
+ nand->ecc.hwctl = omap_enable_chip_hwecc;
+ nand->ecc.correct = omap_correct_chip_hwecc;
+ nand->ecc.read_oob = omap_read_oob_chipecc;
+ nand->ecc.mode = NAND_ECC_CHIP; /* internal to chip */
+ nand->ecc.layout = &chip_nand_oob;
+ if (nand->options & NAND_BUSWIDTH_16)
+ nand->cmdfunc = omap_nand_command_lp;
+ else
+ printf("%s: Huh? not 16-bit wide\n", __FUNCTION__);
+ micron_set_chip_ecc(mtd, 1);
+ printf("NAND: Internal to NAND ECC selected\n");
+ } else {
+ printf("NAND: unknown ECC mode %d\n", mode);
+ return;
+ }
+
+ current_ecc_method = mode;
/* Update NAND handling after ECC mode switch */
nand_scan_tail(mtd);
@@ -336,6 +740,11 @@ int board_nand_init(struct nand_chip *nand)
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
nand->options |= NAND_BUSWIDTH_16;
+#ifdef CONFIG_MTD_SKIP_BBTSCAN
+ /* Skip the bad block scan */
+ nand->options |= NAND_SKIP_BBTSCAN;
+#endif
+
nand->chip_delay = 100;
/* Default ECC mode */
nand->ecc.mode = NAND_ECC_SOFT;
diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c
index 5a7323a715..cf79161aaf 100644
--- a/drivers/power/twl4030.c
+++ b/drivers/power/twl4030.c
@@ -103,3 +103,520 @@ void twl4030_power_mmc_init(void)
TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_P1);
}
+
+void twl4030_power_off(void)
+{
+ u8 val = 0;
+ if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &val,
+ TWL4030_PM_MASTER_P1_SW_EVENTS)) {
+ printf("Error:TWL4030: failed to read the power register\n");
+ } else {
+ val |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, val,
+ TWL4030_PM_MASTER_P1_SW_EVENTS)) {
+ printf("Error:TWL4030: failed to write the power register\n");
+ printf("Could not power off\n");
+ }
+ }
+}
+
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ printf("Power down.\n");
+ twl4030_power_off();
+ return 0;
+}
+
+U_BOOT_CMD(poweroff, 1, 1, do_poweroff,
+ "Power down board",
+ ""
+);
+
+#ifdef CONFIG_TWL4030_CHARGING
+int twl4030_enable_charging(void)
+{
+ u8 val = 0;
+ /* write 0x57 to 0x4a, 0x85 (BCIMFKEY)*/
+ /* Enabel access to BCIMFEN1 register access */
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, 0x57,
+ TWL4030_MAIN_CHARGE_BCIMFKEY)) {
+ printf("Error:TWL4030: failed to write BCIMFKEY\n");
+ return 1;
+ }
+
+ /* read 0x4a, 0x86 */
+ if (twl4030_i2c_read_u8(TWL4030_CHIP_MAIN_CHARGE, &val,
+ TWL4030_MAIN_CHARGE_BCIMFEN1)) {
+ printf("Error:TWL4030: failed to read BCIMFEN1\n");
+ return 1;
+ }
+
+ /* or in 0x80 */
+ /* write to 0x4a, 0x86 (TWL_BCIMFEN1) */
+ val |= TWL4030_MAIN_CHARGE_BCIMFEN1_VBATOV1EN;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, val,
+ TWL4030_MAIN_CHARGE_BCIMFEN1)) {
+ printf("Error:TWL4030: failed to write BCIMFEN1\n");
+ return 1;
+ }
+
+ /* write 0xd2 to 0x4a, 0x85 (BCIMFKEY) */
+ val = TWL4030_MAIN_CHARGE_BCIMFKEY_MFKEY5;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE,
+ val,
+ TWL4030_MAIN_CHARGE_BCIMFKEY)) {
+ printf("Error:TWL4030: failed to write BCIMFKEY\n");
+ return 1;
+ }
+
+ /* clear low four bits in 0x4a, 0x8a (BCIMFTH1) */
+ if (twl4030_i2c_read_u8(TWL4030_CHIP_MAIN_CHARGE, &val,
+ TWL4030_MAIN_CHARGE_BCIMFTH1)) {
+ printf("Error:TWL4030: failed to read BCIMFTH1\n");
+ return 1;
+ }
+ val = (val & ~TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_MASK) |
+ TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_2636_mV;
+ /* clear low four bits in 0x4a, 0x8a (BCIMFTH1) */
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_MAIN_CHARGE, val,
+ TWL4030_MAIN_CHARGE_BCIMFTH1)) {
+ printf("Error:TWL4030: failed to write BCIMFTH1\n");
+ return 1;
+ }
+
+ /* read 0x4a, 0x86; 0x4a, 0x8a (???) */
+
+ /* Turn on AC charging */
+ /* write 0x90 to 0x49, 0x91 (MADC_HFCLK_EN, DEFAULTMADC_CLK_EN) */
+ val = TWL4030_INTBR_GPBR1_MADC_HFCLK_EN;
+ val |= TWL4030_INTBR_GPBR1_DEFAULT_MADC_CLK_EN;
+ if (twl4030_i2c_write_u8(TWL4030_CHIP_INTBR, val,
+ TWL4030_INTBR_GPBR1)) {
+ printf("Error:TWL4030: failed to write BCIMFTH1\n");
+ return 1;
+ }
+ return 0;
+}
+
+
+struct {
+ u8 idx;
+ u8 reg_base;
+ char *str;
+ u16 mul;
+} adc_regs[] = {
+ {
+ 0,
+ 0x37,
+ "(GP analog input/Bat type)",
+ 1466
+ },
+ {
+ 1,
+ 0x39,
+ "(GP analog input/Bat temp)",
+ 1446
+ },
+ {
+ 2,
+ 0x3b,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 3,
+ 0x3d,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 4,
+ 0x3f,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 5,
+ 0x41,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 6,
+ 0x43,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 7,
+ 0x45,
+ "(GP analog input)\t",
+ 2444,
+ },
+ {
+ 8,
+ 0x47,
+ "(VBUS voltage)\t",
+ 6843,
+ },
+ {
+ 9,
+ 0x49,
+ "(Charger backup bat volt)",
+ 4399,
+ },
+ {
+ 11,
+ 0x4d,
+ "(Battery charger voltage)",
+ 9775,
+ },
+ {
+ 12,
+ 0x4f,
+ "(Main battery voltage)",
+ 5865,
+ },
+ {
+ 15,
+ 0x55,
+ "(VRUSB supply/spkr pol)",
+ 3225,
+ },
+};
+
+struct
+{
+ u8 val;
+ char *str;
+ u8 pr_info;
+} charge_state[] = {
+ {
+ 0x00,
+ "No charging device",
+ 0,
+ },
+ {
+ 0x01,
+ "Off mode",
+ 0,
+ },
+ {
+ 0x02,
+ "Standby mode",
+ 0,
+ },
+ {
+ 0x03,
+ "Open bat or USB not debounced",
+ 0,
+ },
+ {
+ 0x21,
+ "Constant voltage AC",
+ 1,
+ },
+ {
+ 0x22,
+ "Quick charge AC 1",
+ 1,
+ },
+ {
+ 0x23,
+ "Quick charge AC 2",
+ 1,
+ },
+ {
+ 0x24,
+ "Quick charge AC 3",
+ 1,
+ },
+ {
+ 0x25,
+ "Quick charge AC 4",
+ 1,
+ },
+ {
+ 0x26,
+ "Quick charge AC 5",
+ 1,
+ },
+ {
+ 0x27,
+ "Quick charge AC 6",
+ 1,
+ },
+ {
+ 0x28,
+ "Charge stop AC 1",
+ 1,
+ },
+ {
+ 0x29,
+ "Charge stop AC 1",
+ 1,
+ },
+ {
+ 0x2a,
+ "Charge stop AC 1",
+ 1,
+ },
+ {
+ 0x2b,
+ "Charge AC comp 1",
+ 1,
+ },
+ {
+ 0x2c,
+ "Charge AC comp 2",
+ 1,
+ },
+ {
+ 0x2d,
+ "Charge AC comp 3",
+ 1,
+ },
+ {
+ 0x2e,
+ "Charge AC comp 4",
+ 1,
+ },
+ {
+ 0x2f,
+ "AC adapter overvoltage",
+ 0,
+ },
+ {
+ 0x12,
+ "Quick charge USB 1",
+ 1,
+ },
+ {
+ 0x13,
+ "Quick charge USB 2",
+ 1,
+ },
+ {
+ 0x14,
+ "Quick charge USB 3",
+ 1,
+ },
+ {
+ 0x15,
+ "Quick charge USB 4",
+ 1,
+ },
+ {
+ 0x16,
+ "Quick charge USB 5",
+ 1,
+ },
+ {
+ 0x17,
+ "Quick charge USB 6",
+ 1,
+ },
+ {
+ 0x18,
+ "Charge stop USB 1",
+ 1,
+ },
+ {
+ 0x19,
+ "Charge stop USB 2",
+ 1,
+ },
+ {
+ 0x1a,
+ "Charge stop USB 3",
+ 1,
+ },
+ {
+ 0x1b,
+ "Charge USB comp 1",
+ 1,
+ },
+ {
+ 0x1c,
+ "Charge USB comp 2",
+ 1,
+ },
+ {
+ 0x1d,
+ "Charge USB comp 3",
+ 1,
+ },
+ {
+ 0x1e,
+ "Charge USB comp 4",
+ 1,
+ },
+ {
+ 0x1f,
+ "USB adapter overvoltage",
+ 0,
+ },
+};
+
+int read_madc_msblsb(u8 reg)
+{
+ u8 val;
+ int temp;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, reg+1);
+ temp = ((int)(val & 0x3)) << 8;
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, reg);
+ return temp | val;
+}
+
+#define VOLT_STEP_SIZE 588
+#define VOLT_PSR_R 100
+
+int pm_battery_voltage(void)
+{
+ int volt = read_madc_msblsb(0x78);
+ return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
+}
+
+#define CURR_SLOPE 1194
+
+int pm_battery_current(void)
+{
+ int curr = read_madc_msblsb(0x7c);
+ u8 val;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x98);
+ if (val & 0x20)
+ return (curr * 1000) / (2 * CURR_SLOPE);
+ else
+ return (curr * 1000) / (1 * CURR_SLOPE);
+}
+
+static int batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
+8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
+5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
+4040, 3910, 3790, 3670, 3550
+};
+
+#define TEMP_STEP_SIZE 147
+#define TEMP_PSR_R 100
+
+int pm_battery_temp(void)
+{
+ u8 val;
+ int temp, curr, volt, res, ret;
+
+ ret = read_madc_msblsb(0x7a);
+
+ volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x98);
+ curr = ((val & 0x07) + 1) * 10;
+ res = volt * 1000 / curr;
+ for (temp = 58; temp >= 0; temp--) {
+ int actual = batt_table[temp];
+ if ((actual - res) >= 0)
+ break;
+ }
+
+ if (temp < 3) {
+ if (temp == 2)
+ temp = -1;
+ else if (temp == 1)
+ temp = -2;
+ else
+ temp = -3;
+ }
+ return temp + 1;
+}
+
+void print_charge_info(void)
+{
+ printf("\n");
+
+ printf("Charger main battery voltage\t\t %4u mV\n", pm_battery_voltage());
+
+ printf("Charger current\t\t\t\t %4u mA\n", pm_battery_current());
+
+ printf("\n");
+
+ printf("Battery temperature (if using Logic battery)\t%2u deg C\n", pm_battery_temp());
+
+}
+
+int twl4030_info(void)
+{
+ u8 val;
+ int i;
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_INTBR, 0x90, TWL4030_INTBR_GPBR1);
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x01, 0x00);
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0xff, 0x06);
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0xff, 0x07);
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x02, 0x97);
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_MADC, 0x20, 0x12);
+
+ udelay(200000);
+
+ for (i=0; i<sizeof(adc_regs)/sizeof(adc_regs[0]); ++i) {
+ u8 lsb, msb;
+ u32 adc, v;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &lsb, adc_regs[i].reg_base);
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &msb, adc_regs[i].reg_base+1);
+ adc = lsb / 64 + msb * 4;
+ v = (adc * adc_regs[i].mul) / 1000;
+ printf("ADC%d %s\tvalue 0x%03x = %4u mV\n", adc_regs[i].idx, adc_regs[i].str, adc, v);
+ }
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_MADC, &val, 0x76);
+
+ for (i=0; i<sizeof(charge_state)/sizeof(charge_state[0]);++i) {
+ if (val == charge_state[i].val) {
+ printf("Charge state \t\t\tvalue 0x%02x = %s\n", val, charge_state[i].str);
+ if (charge_state[i].pr_info) {
+ print_charge_info();
+ }
+ break;
+ }
+ }
+ if (i >= sizeof(charge_state)/sizeof(charge_state[0])) {
+ printf("Charge state \t\t\tvalue 0x%02x = %s\n", val, "Unknown charge state");
+ }
+ return 0;
+}
+
+
+int adc_cmd(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ char *cmd;
+
+ if (argc < 2)
+ goto usage;
+
+ cmd = argv[1];
+ if (strcmp(cmd, "enable") == 0)
+ return twl4030_enable_charging();
+ if (strcmp(cmd, "info") == 0)
+ return twl4030_info();
+usage:
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+ madc, 2, 1, adc_cmd,
+ "MADC subsytem",
+ "madc enable - enable charging\n"
+ "madc info - print information on ADC registers/charging state"
+);
+#endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 086dc05383..691d55602e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -41,6 +41,8 @@ COBJS-$(CONFIG_SED156X) += sed156x.o
COBJS-$(CONFIG_VIDEO_SM501) += sm501.o
COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
+COBJS-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o
+
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/video/omap3_dss.c b/drivers/video/omap3_dss.c
new file mode 100644
index 0000000000..6b33250d3a
--- /dev/null
+++ b/drivers/video/omap3_dss.c
@@ -0,0 +1,343 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ * Syed Mohammed Khasim <khasim <at> ti.com>
+ *
+ * Referred to Linux Kernel DSS driver files for OMAP3 by
+ * Tomi Valkeinen from drivers/video/omap2/dss/
+ *
+ * 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's version 2 and any
+ * later version the License.
+ *
+ * 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/arch/dss.h>
+#include <asm/arch/sys_proto.h>
+
+#ifdef DEBUG
+#define DSS_DBG_CLK(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define DSS_DBG_CLK(fmt, ...)
+#endif
+
+/*
+ * Configure VENC for a given Mode (NTSC / PAL)
+ */
+void omap3_dss_venc_config(const struct venc_regs *venc_cfg,
+ u32 height, u32 width)
+{
+ struct venc_regs *venc = (struct venc_regs *) OMAP3_VENC_BASE;
+ struct dss_regs *dss = (struct dss_regs *) OMAP3_DSS_BASE;
+ struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
+
+ writel(venc_cfg->status, &venc->status);
+ writel(venc_cfg->f_control, &venc->f_control);
+ writel(venc_cfg->vidout_ctrl, &venc->vidout_ctrl);
+ writel(venc_cfg->sync_ctrl, &venc->sync_ctrl);
+ writel(venc_cfg->llen, &venc->llen);
+ writel(venc_cfg->flens, &venc->flens);
+ writel(venc_cfg->hfltr_ctrl, &venc->hfltr_ctrl);
+ writel(venc_cfg->cc_carr_wss_carr, &venc->cc_carr_wss_carr);
+ writel(venc_cfg->c_phase, &venc->c_phase);
+ writel(venc_cfg->gain_u, &venc->gain_u);
+ writel(venc_cfg->gain_v, &venc->gain_v);
+ writel(venc_cfg->gain_y, &venc->gain_y);
+ writel(venc_cfg->black_level, &venc->black_level);
+ writel(venc_cfg->blank_level, &venc->blank_level);
+ writel(venc_cfg->x_color, &venc->x_color);
+ writel(venc_cfg->m_control, &venc->m_control);
+ writel(venc_cfg->bstamp_wss_data, &venc->bstamp_wss_data);
+ writel(venc_cfg->s_carr, &venc->s_carr);
+ writel(venc_cfg->line21, &venc->line21);
+ writel(venc_cfg->ln_sel, &venc->ln_sel);
+ writel(venc_cfg->l21__wc_ctl, &venc->l21__wc_ctl);
+ writel(venc_cfg->htrigger_vtrigger, &venc->htrigger_vtrigger);
+ writel(venc_cfg->savid__eavid, &venc->savid__eavid);
+ writel(venc_cfg->flen__fal, &venc->flen__fal);
+ writel(venc_cfg->lal__phase_reset, &venc->lal__phase_reset);
+ writel(venc_cfg->hs_int_start_stop_x,
+ &venc->hs_int_start_stop_x);
+ writel(venc_cfg->hs_ext_start_stop_x,
+ &venc->hs_ext_start_stop_x);
+ writel(venc_cfg->vs_int_start_x,
+ &venc->vs_int_start_x);
+ writel(venc_cfg->vs_int_stop_x__vs_int_start_y,
+ &venc->vs_int_stop_x__vs_int_start_y);
+ writel(venc_cfg->vs_int_stop_y__vs_ext_start_x,
+ &venc->vs_int_stop_y__vs_ext_start_x);
+ writel(venc_cfg->vs_ext_stop_x__vs_ext_start_y,
+ &venc->vs_ext_stop_x__vs_ext_start_y);
+ writel(venc_cfg->vs_ext_stop_y,
+ &venc->vs_ext_stop_y);
+ writel(venc_cfg->avid_start_stop_x,
+ &venc->avid_start_stop_x);
+ writel(venc_cfg->avid_start_stop_y,
+ &venc->avid_start_stop_y);
+ writel(venc_cfg->fid_int_start_x__fid_int_start_y,
+ &venc->fid_int_start_x__fid_int_start_y);
+ writel(venc_cfg->fid_int_offset_y__fid_ext_start_x,
+ &venc->fid_int_offset_y__fid_ext_start_x);
+ writel(venc_cfg->fid_ext_start_y__fid_ext_offset_y,
+ &venc->fid_ext_start_y__fid_ext_offset_y);
+ writel(venc_cfg->tvdetgp_int_start_stop_x,
+ &venc->tvdetgp_int_start_stop_x);
+ writel(venc_cfg->tvdetgp_int_start_stop_y,
+ &venc->tvdetgp_int_start_stop_y);
+ writel(venc_cfg->gen_ctrl, &venc->gen_ctrl);
+ writel(venc_cfg->output_control, &venc->output_control);
+ writel(venc_cfg->dac_b__dac_c, &venc->dac_b__dac_c);
+
+ /* Configure DSS for VENC Settings */
+ writel(VENC_DSS_CONFIG, &dss->control);
+
+ /* Configure height and width for Digital out */
+ writel(((height << DIG_LPP_SHIFT) | width), &dispc->size_dig);
+}
+
+/*
+ * Configure Panel Specific Parameters
+ */
+void omap3_dss_panel_config(const struct panel_config *panel_cfg)
+{
+ struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+ struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
+ int ret;
+ u32 divisor, cm_clksel_dss;
+ u32 fck_div;
+
+ /* Calculate timing of DISPC_DIVISOR; LCD in 16:23, PCD in 0:7 */
+ ret = omap3_dss_calc_divisor(panel_cfg->panel_type == 1,
+ panel_cfg->pixel_clock * 1000, &divisor, &fck_div);
+ DSS_DBG_CLK("%s: Need to program CM_CLKSEL_DSS:clksel_dss1 to %u !\n", __FUNCTION__, fck_div);
+ cm_clksel_dss = readl(&prcm_base->clksel_dss);
+ DSS_DBG_CLK("%s: &cm_clksel_dss %p val %#x\n", __FUNCTION__, &prcm_base->clksel_dss, cm_clksel_dss);
+ cm_clksel_dss &= ~0x3f; /* clear CLKSELDSS1 */
+ cm_clksel_dss |= fck_div; /* or in new clksel_dss1 */
+ writel(cm_clksel_dss, &prcm_base->clksel_dss);
+ DSS_DBG_CLK("%s: cm_clksel_dss %#x\n", __FUNCTION__, cm_clksel_dss);
+
+ writel(panel_cfg->timing_h, &dispc->timing_h);
+ writel(panel_cfg->timing_v, &dispc->timing_v);
+ writel(panel_cfg->pol_freq, &dispc->pol_freq);
+#if 1
+ writel(divisor, &dispc->divisor);
+#else
+ writel(panel_cfg->divisor, &dispc->divisor);
+#endif
+ writel(panel_cfg->lcd_size, &dispc->size_lcd);
+ writel((panel_cfg->load_mode << FRAME_MODE_SHIFT), &dispc->config);
+ writel(((panel_cfg->panel_type << TFTSTN_SHIFT) |
+ (panel_cfg->data_lines << DATALINES_SHIFT)), &dispc->control);
+ writel(panel_cfg->panel_color, &dispc->default_color0);
+}
+
+struct dss_clock_info {
+ /* rates that we get with dividers below */
+ unsigned long fck;
+
+ /* dividers */
+ u16 fck_div;
+};
+
+struct dispc_clock_info {
+ /* rates that we get with dividers below */
+ unsigned long lck;
+ unsigned long pck;
+
+ /* dividers */
+ u16 lck_div;
+ u16 pck_div;
+};
+
+static inline int abs(int x)
+{
+ if (x < 0)
+ return -x;
+ return x;
+}
+
+/* with fck as input clock rate, find dispc dividers that produce req_pck */
+void dispc_find_clk_divs(int is_tft, unsigned long req_pck, unsigned long fck,
+ struct dispc_clock_info *cinfo)
+{
+ u16 pcd_min = is_tft ? 2 : 3;
+ unsigned long best_pck;
+ u16 best_ld, cur_ld;
+ u16 best_pd, cur_pd;
+
+ best_pck = 0;
+ best_ld = 0;
+ best_pd = 0;
+
+ for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
+ unsigned long lck = fck / cur_ld;
+
+ for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
+ unsigned long pck = lck / cur_pd;
+ long old_delta, new_delta;
+
+ old_delta = abs(best_pck - req_pck);
+ new_delta = abs(pck - req_pck);
+
+ if (best_pck == 0 || new_delta < old_delta) {
+ DSS_DBG_CLK("%s: cur_ld %u cur_pd %u old_delta %ld new_delta %ld\n", __FUNCTION__, cur_ld, cur_pd, old_delta, new_delta);
+
+ best_pck = pck;
+ best_ld = cur_ld;
+ best_pd = cur_pd;
+
+ DSS_DBG_CLK("%s: best_ld %u best_pd %u\n", __FUNCTION__, best_ld, best_pd);
+
+ if (pck == req_pck)
+ goto found;
+ }
+
+ if (pck < req_pck)
+ break;
+ }
+
+ if (lck / pcd_min < req_pck)
+ break;
+ }
+
+found:
+ cinfo->lck_div = best_ld;
+ cinfo->pck_div = best_pd;
+ cinfo->lck = fck / cinfo->lck_div;
+ cinfo->pck = cinfo->lck / cinfo->pck_div;
+ DSS_DBG_CLK("%s: %d best_ld %u best_pd %u pck %lu\n", __FUNCTION__, __LINE__, best_ld, best_pd, cinfo->pck);
+}
+
+int omap3_dss_calc_divisor(int is_tft, unsigned int req_pck,
+ unsigned int *dispc_divisor,
+ unsigned int *result_fck_div)
+{
+ unsigned long prate;
+ u16 fck_div, fck_div_max, fck_min_div = 1, fck_div_factor;
+ int min_fck_per_pck;
+ unsigned long fck, max_dss_fck = 173000000; /* max DSS VP_CLK */
+ u32 cpu_family = get_cpu_family();
+ struct dispc_clock_info cur_dispc;
+ struct dss_clock_info best_dss;
+ struct dispc_clock_info best_dispc;
+
+ prate = 864000000; /* Fclk of DSS (864Mhz) */
+
+ memset(&best_dss, 0, sizeof(best_dss));
+ memset(&best_dispc, 0, sizeof(best_dispc));
+
+ min_fck_per_pck = 1;
+
+#ifdef CONFIG_OMAP44XX
+ fck_div_max = 32;
+ fck_div_factor = 2;
+#else
+ fck_div_max = 16;
+ fck_div_factor = 1;
+#endif
+
+ for (fck_div = fck_div_max; fck_div >= fck_min_div; --fck_div) {
+ DSS_DBG_CLK("%s:%d fck_div %d\n", __FUNCTION__, __LINE__, fck_div);
+ fck = prate / fck_div * fck_div_factor;
+
+ if (fck > max_dss_fck) {
+ DSS_DBG_CLK("%s:%d fck %lu > max_dss_fck %lu\n", __FUNCTION__, __LINE__, fck, max_dss_fck);
+ continue;
+ }
+
+ if (min_fck_per_pck &&
+ fck < req_pck * min_fck_per_pck) {
+ DSS_DBG_CLK("%s:%d\n", __FUNCTION__, __LINE__);
+ continue;
+ }
+
+ dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
+
+ DSS_DBG_CLK("%s:%d cur.pck %u < best_pck %u?\n", __FUNCTION__, __LINE__,
+ abs(cur_dispc.pck - req_pck),
+ abs(best_dispc.pck - req_pck));
+
+ if (abs(cur_dispc.pck - req_pck) <
+ abs(best_dispc.pck - req_pck)) {
+
+ DSS_DBG_CLK("%s:%d yes fck %lu fck_div %u\n", __FUNCTION__, __LINE__, fck, fck_div);
+ best_dss.fck = fck;
+ best_dss.fck_div = fck_div;
+
+ best_dispc = cur_dispc;
+
+ if (cur_dispc.pck == req_pck)
+ break;
+ }
+ }
+
+ /* Setup divisor */
+ *dispc_divisor = (cur_dispc.lck_div << 16) | cur_dispc.pck_div;
+ DSS_DBG_CLK("%s: fck_div %u best_dss.fck_div %u\n", __FUNCTION__, fck_div, best_dss.fck_div);
+ *result_fck_div = best_dss.fck_div;
+ return 0;
+}
+
+/*
+ * Enable LCD and DIGITAL OUT in DSS
+ */
+void omap3_dss_enable(void)
+{
+ struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
+ u32 l = 0;
+
+ l = readl(&dispc->control);
+ l |= DISPC_ENABLE;
+ writel(l, &dispc->control);
+}
+
+#ifdef CONFIG_DSS_DUMP
+
+#define DUMP_IT(offset) printf("%p = %08x " #offset "\n", &dispc->offset, readl(&dispc->offset))
+
+void omap3_dss_dump(void)
+{
+ struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
+ struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+
+ DUMP_IT(control);
+ DUMP_IT(config);
+ DUMP_IT(timing_h);
+ DUMP_IT(timing_v);
+ DUMP_IT(pol_freq);
+ DUMP_IT(divisor);
+ DUMP_IT(size_lcd);
+ DUMP_IT(gfx_attributes);
+ DUMP_IT(default_color0);
+ printf("%p = %08x cd_clksel_dss\n", &prcm_base->clksel_dss, readl(&prcm_base->clksel_dss));
+}
+
+static int do_dss_dump (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ omap3_dss_dump();
+ return (0);
+}
+
+U_BOOT_CMD(
+ dss_dump, 1, 1, do_dss_dump,
+ "dump DSS registers",
+ ""
+);
+
+#endif
diff --git a/fs/Makefile b/fs/Makefile
index 22aad126bc..f32931a707 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -29,6 +29,7 @@ subdirs-$(CONFIG_CMD_FDOS) += fdos
subdirs-$(CONFIG_CMD_JFFS2) += jffs2
subdirs-$(CONFIG_CMD_REISER) += reiserfs
subdirs-$(CONFIG_YAFFS2) += yaffs2
+subdirs-$(CONFIG_YAFFS2_NEW) += yaffs2-new
subdirs-$(CONFIG_CMD_UBIFS) += ubifs
SUBDIRS := $(subdirs-y)
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index c450bf6924..5b312993c3 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -277,7 +277,7 @@ static __u32 get_fatent (fsdata *mydata, __u32 entry)
*/
static int
get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
- unsigned long size)
+ unsigned long size, __u8 *start_buffer)
{
__u32 idx = 0;
__u32 startsect;
@@ -291,24 +291,52 @@ get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
- if (disk_read(startsect, size / FS_BLOCK_SIZE, buffer) < 0) {
- debug("Error reading data\n");
- return -1;
- }
- if (size % FS_BLOCK_SIZE) {
- __u8 tmpbuf[FS_BLOCK_SIZE];
+ if (start_buffer) {
+ while (size >= FS_BLOCK_SIZE) {
+ if (disk_read(startsect, 1, buffer) < 0) {
+ debug("Error reading data\n");
+ return -1;
+ }
+ buffer += FS_BLOCK_SIZE;
+ startsect++;
+ size -= FS_BLOCK_SIZE;
+ lcd_percent_update(buffer - start_buffer);
+ }
+ if (size % FS_BLOCK_SIZE) {
+ __u8 tmpbuf[FS_BLOCK_SIZE];
- idx = size / FS_BLOCK_SIZE;
- if (disk_read(startsect + idx, 1, tmpbuf) < 0) {
+ idx = size / FS_BLOCK_SIZE;
+ if (disk_read(startsect, 1, tmpbuf) < 0) {
+ debug("Error reading data\n");
+ return -1;
+ }
+ memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
+
+ buffer += size % FS_BLOCK_SIZE;
+ lcd_percent_update(buffer - start_buffer);
+ return 0;
+ }
+ } else {
+ if (disk_read(startsect, size / FS_BLOCK_SIZE, buffer) < 0) {
debug("Error reading data\n");
return -1;
}
- buffer += idx * FS_BLOCK_SIZE;
+ lcd_percent_update(buffer + (size & ~FS_BLOCK_SIZE) - start_buffer);
+ if (size % FS_BLOCK_SIZE) {
+ __u8 tmpbuf[FS_BLOCK_SIZE];
- memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
- return 0;
- }
+ idx = size / FS_BLOCK_SIZE;
+ if (disk_read(startsect + idx, 1, tmpbuf) < 0) {
+ debug("Error reading data\n");
+ return -1;
+ }
+ buffer += idx * FS_BLOCK_SIZE;
+ memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
+ lcd_percent_update(buffer + size - start_buffer);
+ return 0;
+ }
+ }
return 0;
}
@@ -326,7 +354,9 @@ get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
__u32 curclust = START(dentptr);
__u32 endclust, newclust;
unsigned long actsize;
+ __u8 *start_buffer = buffer;
+ lcd_percent_init(filesize);
debug("Filesize: %ld bytes\n", filesize);
if (maxsize > 0 && filesize > maxsize)
@@ -348,6 +378,7 @@ get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
debug("Invalid FAT entry\n");
return gotsize;
}
+ lcd_percent_update(actsize);
endclust = newclust;
actsize += bytesperclust;
}
@@ -356,7 +387,7 @@ get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
actsize -= bytesperclust;
/* get remaining clusters */
- if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
+ if (get_cluster(mydata, curclust, buffer, (int)actsize, start_buffer) != 0) {
printf("Error reading cluster\n");
return -1;
}
@@ -366,20 +397,23 @@ get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
filesize -= actsize;
buffer += actsize;
actsize = filesize;
- if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
+ lcd_percent_update(gotsize);
+ if (get_cluster(mydata, endclust, buffer, (int)actsize, start_buffer) != 0) {
printf("Error reading cluster\n");
return -1;
}
gotsize += actsize;
+ lcd_percent_update(gotsize);
return gotsize;
getit:
- if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
+ if (get_cluster(mydata, curclust, buffer, (int)actsize, start_buffer) != 0) {
printf("Error reading cluster\n");
return -1;
}
gotsize += (int)actsize;
filesize -= actsize;
buffer += actsize;
+ lcd_percent_update(gotsize);
curclust = get_fatent(mydata, endclust);
if (CHECK_CLUST(curclust, mydata->fatsize)) {
@@ -473,7 +507,7 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster,
}
if (get_cluster(mydata, curclust, get_vfatname_block,
- mydata->clust_size * SECTOR_SIZE) != 0) {
+ mydata->clust_size * SECTOR_SIZE, NULL) != 0) {
debug("Error: reading directory block\n");
return -1;
}
@@ -555,7 +589,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect,
int i;
if (get_cluster(mydata, curclust, get_dentfromdir_block,
- mydata->clust_size * SECTOR_SIZE) != 0) {
+ mydata->clust_size * SECTOR_SIZE, NULL) != 0) {
debug("Error: reading directory block\n");
return NULL;
}
diff --git a/fs/yaffs2-new/Makefile b/fs/yaffs2-new/Makefile
new file mode 100644
index 0000000000..2ed148c026
--- /dev/null
+++ b/fs/yaffs2-new/Makefile
@@ -0,0 +1,63 @@
+# Makefile for YAFFS direct test
+#
+#
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2003 Aleph One Ltd.
+#
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# 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.
+#
+# NB Warning this Makefile does not include header dependencies.
+#
+# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $
+
+#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libyaffs2-new.o
+
+COBJS-$(CONFIG_YAFFS2_NEW) := \
+ yaffs_uboot.o yaffs_guts.o yaffs_summary.o yaffs_yaffs2.o \
+ yaffs_allocator.o yaffs_nand.o yaffs_verify.o yaffs_nameval.o \
+ yaffs_checkptrw.o yaffs_tagscompat.o yaffs_bitmap.o yaffs_attribs.o \
+ yaffs_packedtags2.o yaffs_qsort.o yaffs_yaffs1.o yaffs_ecc.o \
+ yaffs_mtdif.o yaffs_mtdif2_single.o \
+ yaffsfs.o yaffsfs_errno.o
+
+#COBJS-$(CONFIG_YAFFS2) := \
+# yaffscfg.o yaffs_ecc.o yaffsfs.o yaffs_guts.o yaffs_packedtags1.o \
+# yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o \
+# yaffs_nand.o yaffs_checkptrw.o yaffs_qsort.o yaffs_mtdif.o \
+# yaffs_mtdif2.o
+
+SRCS := $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS-y))
+
+# -DCONFIG_YAFFS_NO_YAFFS1
+CFLAGS += -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -DNO_Y_INLINE -DLINUX_VERSION_CODE=0x20622
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+.PHONY: clean distclean
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/fs/yaffs2-new/devextras.h b/fs/yaffs2-new/devextras.h
new file mode 100644
index 0000000000..b0147b85a4
--- /dev/null
+++ b/fs/yaffs2-new/devextras.h
@@ -0,0 +1,113 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations used during development.
+ * Most of these are from kernel includes placed here so we can use them in
+ * applications.
+ *
+ */
+
+#ifndef __EXTRAS_H__
+#define __EXTRAS_H__
+
+#if defined WIN32
+#define __inline__ __inline
+#define new newHack
+#endif
+
+/* XXX U-BOOT XXX */
+#if 1 /* !(defined __KERNEL__) || (defined WIN32) */
+
+/* User space defines */
+
+/* XXX U-BOOT XXX */
+#if 0
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+#endif
+
+#include <asm/types.h>
+#include <linux/list.h>
+
+/*
+ * File types
+ */
+#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
+
+#ifndef WIN32
+/* XXX U-BOOT XXX */
+#if 0
+#include <sys/stat.h>
+#else
+#include "common.h"
+#endif
+#endif
+
+/*
+ * Attribute flags. These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE 1
+#define ATTR_UID 2
+#define ATTR_GID 4
+#define ATTR_SIZE 8
+#define ATTR_ATIME 16
+#define ATTR_MTIME 32
+#define ATTR_CTIME 64
+#define ATTR_ATIME_SET 128
+#define ATTR_MTIME_SET 256
+#define ATTR_FORCE 512 /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
+
+struct iattr {
+ unsigned int ia_valid;
+ unsigned ia_mode;
+ unsigned ia_uid;
+ unsigned ia_gid;
+ unsigned ia_size;
+ unsigned ia_atime;
+ unsigned ia_mtime;
+ unsigned ia_ctime;
+ unsigned int ia_attr_flags;
+};
+
+#define KERN_DEBUG
+
+#else
+
+#ifndef WIN32
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#endif
+
+#endif
+
+#if defined WIN32
+#undef new
+#endif
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_allocator.c b/fs/yaffs2-new/yaffs_allocator.c
new file mode 100644
index 0000000000..c8f2861c53
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_allocator.c
@@ -0,0 +1,357 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_allocator.h"
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+
+/*
+ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
+ * of approx 100 objects that are themn allocated singly.
+ * This is basically a simplified slab allocator.
+ *
+ * We don't use the Linux slab allocator because slab does not allow
+ * us to dump all the objects in one hit when we do a umount and tear
+ * down all the tnodes and objects. slab requires that we first free
+ * the individual objects.
+ *
+ * Once yaffs has been mainlined I shall try to motivate for a change
+ * to slab to provide the extra features we need here.
+ */
+
+struct yaffs_tnode_list {
+ struct yaffs_tnode_list *next;
+ struct yaffs_tnode *tnodes;
+};
+
+struct yaffs_obj_list {
+ struct yaffs_obj_list *next;
+ struct yaffs_obj *objects;
+};
+
+struct yaffs_allocator {
+ int n_tnodes_created;
+ struct yaffs_tnode *free_tnodes;
+ int n_free_tnodes;
+ struct yaffs_tnode_list *alloc_tnode_list;
+
+ int n_obj_created;
+ struct list_head free_objs;
+ int n_free_objects;
+
+ struct yaffs_obj_list *allocated_obj_list;
+};
+
+static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator =
+ (struct yaffs_allocator *)dev->allocator;
+ struct yaffs_tnode_list *tmp;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ while (allocator->alloc_tnode_list) {
+ tmp = allocator->alloc_tnode_list->next;
+
+ kfree(allocator->alloc_tnode_list->tnodes);
+ kfree(allocator->alloc_tnode_list);
+ allocator->alloc_tnode_list = tmp;
+ }
+
+ allocator->free_tnodes = NULL;
+ allocator->n_free_tnodes = 0;
+ allocator->n_tnodes_created = 0;
+}
+
+static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ allocator->alloc_tnode_list = NULL;
+ allocator->free_tnodes = NULL;
+ allocator->n_free_tnodes = 0;
+ allocator->n_tnodes_created = 0;
+}
+
+static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
+{
+ struct yaffs_allocator *allocator =
+ (struct yaffs_allocator *)dev->allocator;
+ int i;
+ struct yaffs_tnode *new_tnodes;
+ u8 *mem;
+ struct yaffs_tnode *curr;
+ struct yaffs_tnode *next;
+ struct yaffs_tnode_list *tnl;
+
+ if (!allocator) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+
+ if (n_tnodes < 1)
+ return YAFFS_OK;
+
+ /* make these things */
+ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
+ mem = (u8 *) new_tnodes;
+
+ if (!new_tnodes) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs: Could not allocate Tnodes");
+ return YAFFS_FAIL;
+ }
+
+ /* New hookup for wide tnodes */
+ for (i = 0; i < n_tnodes - 1; i++) {
+ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
+ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
+ curr->internal[0] = next;
+ }
+
+ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
+ curr->internal[0] = allocator->free_tnodes;
+ allocator->free_tnodes = (struct yaffs_tnode *)mem;
+
+ allocator->n_free_tnodes += n_tnodes;
+ allocator->n_tnodes_created += n_tnodes;
+
+ /* Now add this bunch of tnodes to a list for freeing up.
+ * NB If we can't add this to the management list it isn't fatal
+ * but it just means we can't free this bunch of tnodes later.
+ */
+ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
+ if (!tnl) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Could not add tnodes to management list");
+ return YAFFS_FAIL;
+ } else {
+ tnl->tnodes = new_tnodes;
+ tnl->next = allocator->alloc_tnode_list;
+ allocator->alloc_tnode_list = tnl;
+ }
+
+ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
+
+ return YAFFS_OK;
+}
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator =
+ (struct yaffs_allocator *)dev->allocator;
+ struct yaffs_tnode *tn = NULL;
+
+ if (!allocator) {
+ BUG();
+ return NULL;
+ }
+
+ /* If there are none left make more */
+ if (!allocator->free_tnodes)
+ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
+
+ if (allocator->free_tnodes) {
+ tn = allocator->free_tnodes;
+ allocator->free_tnodes = allocator->free_tnodes->internal[0];
+ allocator->n_free_tnodes--;
+ }
+
+ return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ if (tn) {
+ tn->internal[0] = allocator->free_tnodes;
+ allocator->free_tnodes = tn;
+ allocator->n_free_tnodes++;
+ }
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+}
+
+/*--------------- yaffs_obj alloaction ------------------------
+ *
+ * Free yaffs_objs are stored in a list using obj->siblings.
+ * The blocks of allocated objects are stored in a linked list.
+ */
+
+static void yaffs_init_raw_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ allocator->allocated_obj_list = NULL;
+ INIT_LIST_HEAD(&allocator->free_objs);
+ allocator->n_free_objects = 0;
+}
+
+static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator = dev->allocator;
+ struct yaffs_obj_list *tmp;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ while (allocator->allocated_obj_list) {
+ tmp = allocator->allocated_obj_list->next;
+ kfree(allocator->allocated_obj_list->objects);
+ kfree(allocator->allocated_obj_list);
+ allocator->allocated_obj_list = tmp;
+ }
+
+ INIT_LIST_HEAD(&allocator->free_objs);
+ allocator->n_free_objects = 0;
+ allocator->n_obj_created = 0;
+}
+
+static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
+{
+ struct yaffs_allocator *allocator = dev->allocator;
+ int i;
+ struct yaffs_obj *new_objs;
+ struct yaffs_obj_list *list;
+
+ if (!allocator) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+
+ if (n_obj < 1)
+ return YAFFS_OK;
+
+ /* make these things */
+ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
+ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
+
+ if (!new_objs || !list) {
+ kfree(new_objs);
+ new_objs = NULL;
+ kfree(list);
+ list = NULL;
+ yaffs_trace(YAFFS_TRACE_ALLOCATE,
+ "Could not allocate more objects");
+ return YAFFS_FAIL;
+ }
+
+ /* Hook them into the free list */
+ for (i = 0; i < n_obj; i++)
+ list_add(&new_objs[i].siblings, &allocator->free_objs);
+
+ allocator->n_free_objects += n_obj;
+ allocator->n_obj_created += n_obj;
+
+ /* Now add this bunch of Objects to a list for freeing up. */
+
+ list->objects = new_objs;
+ list->next = allocator->allocated_obj_list;
+ allocator->allocated_obj_list = list;
+
+ return YAFFS_OK;
+}
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj = NULL;
+ struct list_head *lh;
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return obj;
+ }
+
+ /* If there are none left make more */
+ if (list_empty(&allocator->free_objs))
+ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
+
+ if (!list_empty(&allocator->free_objs)) {
+ lh = allocator->free_objs.next;
+ obj = list_entry(lh, struct yaffs_obj, siblings);
+ list_del_init(lh);
+ allocator->n_free_objects--;
+ }
+
+ return obj;
+}
+
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+
+ struct yaffs_allocator *allocator = dev->allocator;
+
+ if (!allocator) {
+ BUG();
+ return;
+ }
+
+ /* Link into the free list. */
+ list_add(&obj->siblings, &allocator->free_objs);
+ allocator->n_free_objects++;
+}
+
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+
+ if (!dev->allocator) {
+ BUG();
+ return;
+ }
+
+ yaffs_deinit_raw_tnodes(dev);
+ yaffs_deinit_raw_objs(dev);
+ kfree(dev->allocator);
+ dev->allocator = NULL;
+}
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_allocator *allocator;
+
+ if (dev->allocator) {
+ BUG();
+ return;
+ }
+
+ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
+ if (allocator) {
+ dev->allocator = allocator;
+ yaffs_init_raw_tnodes(dev);
+ yaffs_init_raw_objs(dev);
+ }
+}
+
diff --git a/fs/yaffs2-new/yaffs_allocator.h b/fs/yaffs2-new/yaffs_allocator.h
new file mode 100644
index 0000000000..a8cc322642
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_allocator.h
@@ -0,0 +1,30 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ALLOCATOR_H__
+#define __YAFFS_ALLOCATOR_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_attribs.c b/fs/yaffs2-new/yaffs_attribs.c
new file mode 100644
index 0000000000..fe914e558b
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_attribs.c
@@ -0,0 +1,124 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_attribs.h"
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
+{
+ obj->yst_uid = oh->yst_uid;
+ obj->yst_gid = oh->yst_gid;
+ obj->yst_atime = oh->yst_atime;
+ obj->yst_mtime = oh->yst_mtime;
+ obj->yst_ctime = oh->yst_ctime;
+ obj->yst_rdev = oh->yst_rdev;
+}
+
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
+{
+ oh->yst_uid = obj->yst_uid;
+ oh->yst_gid = obj->yst_gid;
+ oh->yst_atime = obj->yst_atime;
+ oh->yst_mtime = obj->yst_mtime;
+ oh->yst_ctime = obj->yst_ctime;
+ oh->yst_rdev = obj->yst_rdev;
+
+}
+
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
+{
+ obj->yst_mtime = Y_CURRENT_TIME;
+ if (do_a)
+ obj->yst_atime = obj->yst_mtime;
+ if (do_c)
+ obj->yst_ctime = obj->yst_mtime;
+}
+
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
+{
+ yaffs_load_current_time(obj, 1, 1);
+ obj->yst_rdev = rdev;
+ obj->yst_uid = uid;
+ obj->yst_gid = gid;
+}
+
+loff_t yaffs_get_file_size(struct yaffs_obj *obj)
+{
+ YCHAR *alias = NULL;
+ obj = yaffs_get_equivalent_obj(obj);
+
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return obj->variant.file_variant.file_size;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ alias = obj->variant.symlink_variant.alias;
+ if (!alias)
+ return 0;
+ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
+ default:
+ return 0;
+ }
+}
+
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+ unsigned int valid = attr->ia_valid;
+
+ if (valid & ATTR_MODE)
+ obj->yst_mode = attr->ia_mode;
+ if (valid & ATTR_UID)
+ obj->yst_uid = attr->ia_uid;
+ if (valid & ATTR_GID)
+ obj->yst_gid = attr->ia_gid;
+
+ if (valid & ATTR_ATIME)
+ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+ if (valid & ATTR_CTIME)
+ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+ if (valid & ATTR_MTIME)
+ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+ if (valid & ATTR_SIZE)
+ yaffs_resize_file(obj, attr->ia_size);
+
+ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+ return YAFFS_OK;
+
+}
+
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+ unsigned int valid = 0;
+
+ attr->ia_mode = obj->yst_mode;
+ valid |= ATTR_MODE;
+ attr->ia_uid = obj->yst_uid;
+ valid |= ATTR_UID;
+ attr->ia_gid = obj->yst_gid;
+ valid |= ATTR_GID;
+
+ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+ valid |= ATTR_ATIME;
+ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+ valid |= ATTR_CTIME;
+ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+ valid |= ATTR_MTIME;
+
+ attr->ia_size = yaffs_get_file_size(obj);
+ valid |= ATTR_SIZE;
+
+ attr->ia_valid = valid;
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_attribs.h b/fs/yaffs2-new/yaffs_attribs.h
new file mode 100644
index 0000000000..5b21b085b7
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_attribs.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ATTRIBS_H__
+#define __YAFFS_ATTRIBS_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_bitmap.c b/fs/yaffs2-new/yaffs_bitmap.c
new file mode 100644
index 0000000000..4440e930d6
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_bitmap.c
@@ -0,0 +1,97 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_bitmap.h"
+#include "yaffs_trace.h"
+/*
+ * Chunk bitmap manipulations
+ */
+
+static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
+{
+ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "BlockBits block %d is not valid",
+ blk);
+ BUG();
+ }
+ return dev->chunk_bits +
+ (dev->chunk_bit_stride * (blk - dev->internal_start_block));
+}
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
+{
+ if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
+ chunk < 0 || chunk >= dev->param.chunks_per_block) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Chunk Id (%d:%d) invalid",
+ blk, chunk);
+ BUG();
+ }
+}
+
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+ memset(blk_bits, 0, dev->chunk_bit_stride);
+}
+
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+ yaffs_verify_chunk_bit_id(dev, blk, chunk);
+ blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+ yaffs_verify_chunk_bit_id(dev, blk, chunk);
+ blk_bits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+ yaffs_verify_chunk_bit_id(dev, blk, chunk);
+ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+ int i;
+
+ for (i = 0; i < dev->chunk_bit_stride; i++) {
+ if (*blk_bits)
+ return 1;
+ blk_bits++;
+ }
+ return 0;
+}
+
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+ u8 *blk_bits = yaffs_block_bits(dev, blk);
+ int i;
+ int n = 0;
+
+ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
+ n += hweight8(*blk_bits);
+
+ return n;
+}
diff --git a/fs/yaffs2-new/yaffs_bitmap.h b/fs/yaffs2-new/yaffs_bitmap.h
new file mode 100644
index 0000000000..e26b37d89a
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+#ifndef __YAFFS_BITMAP_H__
+#define __YAFFS_BITMAP_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_checkptrw.c b/fs/yaffs2-new/yaffs_checkptrw.c
new file mode 100644
index 0000000000..997a618aee
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_checkptrw.c
@@ -0,0 +1,408 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_checkptrw.h"
+#include "yaffs_getblockinfo.h"
+
+static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
+{
+ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "checkpt blocks_avail = %d", blocks_avail);
+
+ return (blocks_avail <= 0) ? 0 : 1;
+}
+
+static int yaffs_checkpt_erase(struct yaffs_dev *dev)
+{
+ int i;
+
+ if (!dev->param.erase_fn)
+ return 0;
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "checking blocks %d to %d",
+ dev->internal_start_block, dev->internal_end_block);
+
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "erasing checkpt block %d", i);
+
+ dev->n_erasures++;
+
+ if (dev->param.
+ erase_fn(dev,
+ i - dev->block_offset /* realign */)) {
+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->n_erased_blocks++;
+ dev->n_free_chunks +=
+ dev->param.chunks_per_block;
+ } else {
+ dev->param.bad_block_fn(dev, i);
+ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+ }
+ }
+ }
+
+ dev->blocks_in_checkpt = 0;
+
+ return 1;
+}
+
+static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
+{
+ int i;
+ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "allocating checkpt block: erased %d reserved %d avail %d next %d ",
+ dev->n_erased_blocks, dev->param.n_reserved_blocks,
+ blocks_avail, dev->checkpt_next_block);
+
+ if (dev->checkpt_next_block >= 0 &&
+ dev->checkpt_next_block <= dev->internal_end_block &&
+ blocks_avail > 0) {
+
+ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+ i++) {
+ struct yaffs_block_info *bi =
+ yaffs_get_block_info(dev, i);
+ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+ dev->checkpt_next_block = i + 1;
+ dev->checkpt_cur_block = i;
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "allocating checkpt block %d", i);
+ return;
+ }
+ }
+ }
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
+
+ dev->checkpt_next_block = -1;
+ dev->checkpt_cur_block = -1;
+}
+
+static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
+{
+ int i;
+ struct yaffs_ext_tags tags;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "find next checkpt block: start: blocks %d next %d",
+ dev->blocks_in_checkpt, dev->checkpt_next_block);
+
+ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
+ for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+ i++) {
+ int chunk = i * dev->param.chunks_per_block;
+ int realigned_chunk = chunk - dev->chunk_offset;
+
+ dev->param.read_chunk_tags_fn(dev, realigned_chunk,
+ NULL, &tags);
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "find next checkpt block: search: block %d oid %d seq %d eccr %d",
+ i, tags.obj_id, tags.seq_number,
+ tags.ecc_result);
+
+ if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
+ /* Right kind of block */
+ dev->checkpt_next_block = tags.obj_id;
+ dev->checkpt_cur_block = i;
+ dev->checkpt_block_list[dev->
+ blocks_in_checkpt] = i;
+ dev->blocks_in_checkpt++;
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "found checkpt block %d", i);
+ return;
+ }
+ }
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
+
+ dev->checkpt_next_block = -1;
+ dev->checkpt_cur_block = -1;
+}
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
+{
+ int i;
+
+ dev->checkpt_open_write = writing;
+
+ /* Got the functions we need? */
+ if (!dev->param.write_chunk_tags_fn ||
+ !dev->param.read_chunk_tags_fn ||
+ !dev->param.erase_fn || !dev->param.bad_block_fn)
+ return 0;
+
+ if (writing && !yaffs2_checkpt_space_ok(dev))
+ return 0;
+
+ if (!dev->checkpt_buffer)
+ dev->checkpt_buffer =
+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+ if (!dev->checkpt_buffer)
+ return 0;
+
+ dev->checkpt_page_seq = 0;
+ dev->checkpt_byte_count = 0;
+ dev->checkpt_sum = 0;
+ dev->checkpt_xor = 0;
+ dev->checkpt_cur_block = -1;
+ dev->checkpt_cur_chunk = -1;
+ dev->checkpt_next_block = dev->internal_start_block;
+
+ /* Erase all the blocks in the checkpoint area */
+ if (writing) {
+ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+ dev->checkpt_byte_offs = 0;
+ return yaffs_checkpt_erase(dev);
+ }
+
+ /* Set to a value that will kick off a read */
+ dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
+ /* A checkpoint block list of 1 checkpoint block per 16 block is
+ * (hopefully) going to be way more than we need */
+ dev->blocks_in_checkpt = 0;
+ dev->checkpt_max_blocks =
+ (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
+ dev->checkpt_block_list =
+ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
+
+ if (!dev->checkpt_block_list)
+ return 0;
+
+ for (i = 0; i < dev->checkpt_max_blocks; i++)
+ dev->checkpt_block_list[i] = -1;
+
+ return 1;
+}
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
+{
+ u32 composite_sum;
+
+ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
+ *sum = composite_sum;
+ return 1;
+}
+
+static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
+{
+ int chunk;
+ int realigned_chunk;
+ struct yaffs_ext_tags tags;
+
+ if (dev->checkpt_cur_block < 0) {
+ yaffs2_checkpt_find_erased_block(dev);
+ dev->checkpt_cur_chunk = 0;
+ }
+
+ if (dev->checkpt_cur_block < 0)
+ return 0;
+
+ tags.is_deleted = 0;
+ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
+ tags.chunk_id = dev->checkpt_page_seq + 1;
+ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
+ tags.n_bytes = dev->data_bytes_per_chunk;
+ if (dev->checkpt_cur_chunk == 0) {
+ /* First chunk we write for the block? Set block state to
+ checkpoint */
+ struct yaffs_block_info *bi =
+ yaffs_get_block_info(dev, dev->checkpt_cur_block);
+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ dev->blocks_in_checkpt++;
+ }
+
+ chunk =
+ dev->checkpt_cur_block * dev->param.chunks_per_block +
+ dev->checkpt_cur_chunk;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
+ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
+ tags.obj_id, tags.chunk_id);
+
+ realigned_chunk = chunk - dev->chunk_offset;
+
+ dev->n_page_writes++;
+
+ dev->param.write_chunk_tags_fn(dev, realigned_chunk,
+ dev->checkpt_buffer, &tags);
+ dev->checkpt_byte_offs = 0;
+ dev->checkpt_page_seq++;
+ dev->checkpt_cur_chunk++;
+ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
+ dev->checkpt_cur_chunk = 0;
+ dev->checkpt_cur_block = -1;
+ }
+ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+
+ return 1;
+}
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
+{
+ int i = 0;
+ int ok = 1;
+ u8 *data_bytes = (u8 *) data;
+
+ if (!dev->checkpt_buffer)
+ return 0;
+
+ if (!dev->checkpt_open_write)
+ return -1;
+
+ while (i < n_bytes && ok) {
+ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
+ dev->checkpt_sum += *data_bytes;
+ dev->checkpt_xor ^= *data_bytes;
+
+ dev->checkpt_byte_offs++;
+ i++;
+ data_bytes++;
+ dev->checkpt_byte_count++;
+
+ if (dev->checkpt_byte_offs < 0 ||
+ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
+ ok = yaffs2_checkpt_flush_buffer(dev);
+ }
+
+ return i;
+}
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
+{
+ int i = 0;
+ int ok = 1;
+ struct yaffs_ext_tags tags;
+ int chunk;
+ int realigned_chunk;
+ u8 *data_bytes = (u8 *) data;
+
+ if (!dev->checkpt_buffer)
+ return 0;
+
+ if (dev->checkpt_open_write)
+ return -1;
+
+ while (i < n_bytes && ok) {
+
+ if (dev->checkpt_byte_offs < 0 ||
+ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
+
+ if (dev->checkpt_cur_block < 0) {
+ yaffs2_checkpt_find_block(dev);
+ dev->checkpt_cur_chunk = 0;
+ }
+
+ if (dev->checkpt_cur_block < 0) {
+ ok = 0;
+ break;
+ }
+
+ chunk = dev->checkpt_cur_block *
+ dev->param.chunks_per_block +
+ dev->checkpt_cur_chunk;
+
+ realigned_chunk = chunk - dev->chunk_offset;
+ dev->n_page_reads++;
+
+ /* read in the next chunk */
+ dev->param.read_chunk_tags_fn(dev,
+ realigned_chunk,
+ dev->checkpt_buffer,
+ &tags);
+
+ if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
+ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+ tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
+ ok = 0;
+ break;
+ }
+
+ dev->checkpt_byte_offs = 0;
+ dev->checkpt_page_seq++;
+ dev->checkpt_cur_chunk++;
+
+ if (dev->checkpt_cur_chunk >=
+ dev->param.chunks_per_block)
+ dev->checkpt_cur_block = -1;
+ }
+
+ *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
+ dev->checkpt_sum += *data_bytes;
+ dev->checkpt_xor ^= *data_bytes;
+ dev->checkpt_byte_offs++;
+ i++;
+ data_bytes++;
+ dev->checkpt_byte_count++;
+ }
+
+ return i;
+}
+
+int yaffs_checkpt_close(struct yaffs_dev *dev)
+{
+ int i;
+
+ if (dev->checkpt_open_write) {
+ if (dev->checkpt_byte_offs != 0)
+ yaffs2_checkpt_flush_buffer(dev);
+ } else if (dev->checkpt_block_list) {
+ for (i = 0;
+ i < dev->blocks_in_checkpt &&
+ dev->checkpt_block_list[i] >= 0; i++) {
+ int blk = dev->checkpt_block_list[i];
+ struct yaffs_block_info *bi = NULL;
+
+ if (dev->internal_start_block <= blk &&
+ blk <= dev->internal_end_block)
+ bi = yaffs_get_block_info(dev, blk);
+ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ }
+ kfree(dev->checkpt_block_list);
+ dev->checkpt_block_list = NULL;
+ }
+
+ dev->n_free_chunks -=
+ dev->blocks_in_checkpt * dev->param.chunks_per_block;
+ dev->n_erased_blocks -= dev->blocks_in_checkpt;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
+ dev->checkpt_byte_count);
+
+ if (dev->checkpt_buffer) {
+ /* free the buffer */
+ kfree(dev->checkpt_buffer);
+ dev->checkpt_buffer = NULL;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
+{
+ /* Erase the checkpoint data */
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "checkpoint invalidate of %d blocks",
+ dev->blocks_in_checkpt);
+
+ return yaffs_checkpt_erase(dev);
+}
diff --git a/fs/yaffs2-new/yaffs_checkptrw.h b/fs/yaffs2-new/yaffs_checkptrw.h
new file mode 100644
index 0000000000..cdbaba7153
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_checkptrw.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
+
+int yaffs_checkpt_close(struct yaffs_dev *dev);
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_direct.h b/fs/yaffs2-new/yaffs_direct.h
new file mode 100644
index 0000000000..28008a608d
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_direct.h
@@ -0,0 +1,8 @@
+
+struct yaffs_direct_context {
+ struct yaffs_dev *dev;
+ u8 *spare_buffer;
+};
+
+#define yaffs_dev_to_lc(dev) ((struct yaffs_direct_context *)((dev)->os_context))
+#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
diff --git a/fs/yaffs2-new/yaffs_ecc.c b/fs/yaffs2-new/yaffs_ecc.c
new file mode 100644
index 0000000000..9294107c15
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_ecc.c
@@ -0,0 +1,281 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
+ * such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
+ * and therefore this bytes influence on the line parity.
+ */
+
+static const unsigned char column_parity_table[] = {
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+
+/* Calculate the ECC for a 256-byte block of data */
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
+{
+ unsigned int i;
+ unsigned char col_parity = 0;
+ unsigned char line_parity = 0;
+ unsigned char line_parity_prime = 0;
+ unsigned char t;
+ unsigned char b;
+
+ for (i = 0; i < 256; i++) {
+ b = column_parity_table[*data++];
+ col_parity ^= b;
+
+ if (b & 0x01) { /* odd number of bits in the byte */
+ line_parity ^= i;
+ line_parity_prime ^= ~i;
+ }
+ }
+
+ ecc[2] = (~col_parity) | 0x03;
+
+ t = 0;
+ if (line_parity & 0x80)
+ t |= 0x80;
+ if (line_parity_prime & 0x80)
+ t |= 0x40;
+ if (line_parity & 0x40)
+ t |= 0x20;
+ if (line_parity_prime & 0x40)
+ t |= 0x10;
+ if (line_parity & 0x20)
+ t |= 0x08;
+ if (line_parity_prime & 0x20)
+ t |= 0x04;
+ if (line_parity & 0x10)
+ t |= 0x02;
+ if (line_parity_prime & 0x10)
+ t |= 0x01;
+ ecc[1] = ~t;
+
+ t = 0;
+ if (line_parity & 0x08)
+ t |= 0x80;
+ if (line_parity_prime & 0x08)
+ t |= 0x40;
+ if (line_parity & 0x04)
+ t |= 0x20;
+ if (line_parity_prime & 0x04)
+ t |= 0x10;
+ if (line_parity & 0x02)
+ t |= 0x08;
+ if (line_parity_prime & 0x02)
+ t |= 0x04;
+ if (line_parity & 0x01)
+ t |= 0x02;
+ if (line_parity_prime & 0x01)
+ t |= 0x01;
+ ecc[0] = ~t;
+
+}
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+ const unsigned char *test_ecc)
+{
+ unsigned char d0, d1, d2; /* deltas */
+
+ d0 = read_ecc[0] ^ test_ecc[0];
+ d1 = read_ecc[1] ^ test_ecc[1];
+ d2 = read_ecc[2] ^ test_ecc[2];
+
+ if ((d0 | d1 | d2) == 0)
+ return 0; /* no error */
+
+ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+ /* Single bit (recoverable) error in data */
+
+ unsigned byte;
+ unsigned bit;
+
+ bit = byte = 0;
+
+ if (d1 & 0x80)
+ byte |= 0x80;
+ if (d1 & 0x20)
+ byte |= 0x40;
+ if (d1 & 0x08)
+ byte |= 0x20;
+ if (d1 & 0x02)
+ byte |= 0x10;
+ if (d0 & 0x80)
+ byte |= 0x08;
+ if (d0 & 0x20)
+ byte |= 0x04;
+ if (d0 & 0x08)
+ byte |= 0x02;
+ if (d0 & 0x02)
+ byte |= 0x01;
+
+ if (d2 & 0x80)
+ bit |= 0x04;
+ if (d2 & 0x20)
+ bit |= 0x02;
+ if (d2 & 0x08)
+ bit |= 0x01;
+
+ data[byte] ^= (1 << bit);
+
+ return 1; /* Corrected the error */
+ }
+
+ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
+ /* Reccoverable error in ecc */
+
+ read_ecc[0] = test_ecc[0];
+ read_ecc[1] = test_ecc[1];
+ read_ecc[2] = test_ecc[2];
+
+ return 1; /* Corrected the error */
+ }
+
+ /* Unrecoverable error */
+
+ return -1;
+
+}
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+ struct yaffs_ecc_other *ecc_other)
+{
+ unsigned int i;
+ unsigned char col_parity = 0;
+ unsigned line_parity = 0;
+ unsigned line_parity_prime = 0;
+ unsigned char b;
+
+ for (i = 0; i < n_bytes; i++) {
+ b = column_parity_table[*data++];
+ col_parity ^= b;
+
+ if (b & 0x01) {
+ /* odd number of bits in the byte */
+ line_parity ^= i;
+ line_parity_prime ^= ~i;
+ }
+
+ }
+
+ ecc_other->col_parity = (col_parity >> 2) & 0x3f;
+ ecc_other->line_parity = line_parity;
+ ecc_other->line_parity_prime = line_parity_prime;
+}
+
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+ struct yaffs_ecc_other *read_ecc,
+ const struct yaffs_ecc_other *test_ecc)
+{
+ unsigned char delta_col; /* column parity delta */
+ unsigned delta_line; /* line parity delta */
+ unsigned delta_line_prime; /* line parity delta */
+ unsigned bit;
+
+ delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
+ delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
+ delta_line_prime =
+ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
+
+ if ((delta_col | delta_line | delta_line_prime) == 0)
+ return 0; /* no error */
+
+ if (delta_line == ~delta_line_prime &&
+ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
+ /* Single bit (recoverable) error in data */
+
+ bit = 0;
+
+ if (delta_col & 0x20)
+ bit |= 0x04;
+ if (delta_col & 0x08)
+ bit |= 0x02;
+ if (delta_col & 0x02)
+ bit |= 0x01;
+
+ if (delta_line >= n_bytes)
+ return -1;
+
+ data[delta_line] ^= (1 << bit);
+
+ return 1; /* corrected */
+ }
+
+ if ((hweight32(delta_line) +
+ hweight32(delta_line_prime) +
+ hweight8(delta_col)) == 1) {
+ /* Reccoverable error in ecc */
+
+ *read_ecc = *test_ecc;
+ return 1; /* corrected */
+ }
+
+ /* Unrecoverable error */
+
+ return -1;
+}
diff --git a/fs/yaffs2-new/yaffs_ecc.h b/fs/yaffs2-new/yaffs_ecc.h
new file mode 100644
index 0000000000..17d47bd80f
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_ecc.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data.
+ * Thus, two such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+struct yaffs_ecc_other {
+ unsigned char col_parity;
+ unsigned line_parity;
+ unsigned line_parity_prime;
+};
+
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+ const unsigned char *test_ecc);
+
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+ struct yaffs_ecc_other *ecc);
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+ struct yaffs_ecc_other *read_ecc,
+ const struct yaffs_ecc_other *test_ecc);
+#endif
diff --git a/fs/yaffs2-new/yaffs_getblockinfo.h b/fs/yaffs2-new/yaffs_getblockinfo.h
new file mode 100644
index 0000000000..8fd0802bdd
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_getblockinfo.h
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GETBLOCKINFO_H__
+#define __YAFFS_GETBLOCKINFO_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+
+/* Function to manipulate block info */
+static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
+ *dev, int blk)
+{
+ if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs: get_block_info block %d is not valid",
+ blk);
+ BUG();
+ }
+ return &dev->block_info[blk - dev->internal_start_block];
+}
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_guts.c b/fs/yaffs2-new/yaffs_guts.c
new file mode 100644
index 0000000000..ec95812ba6
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_guts.c
@@ -0,0 +1,4991 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* XXX U-BOOT XXX */
+#include <common.h>
+#include "linux/stat.h"
+
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "yaffs_guts.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_nand.h"
+#include "yaffs_yaffs1.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_verify.h"
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nameval.h"
+#include "yaffs_allocator.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
+#define YAFFS_GC_GOOD_ENOUGH 2
+#define YAFFS_GC_PASSIVE_THRESHOLD 4
+
+#include "yaffs_ecc.h"
+
+/* Forward declarations */
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+ const u8 *buffer, int n_bytes, int use_reserve);
+
+
+
+/* Function to calculate chunk and offset */
+
+static inline void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+ int *chunk_out, u32 *offset_out)
+{
+ int chunk;
+ u32 offset;
+
+ chunk = (u32) (addr >> dev->chunk_shift);
+
+ if (dev->chunk_div == 1) {
+ /* easy power of 2 case */
+ offset = (u32) (addr & dev->chunk_mask);
+ } else {
+ /* Non power-of-2 case */
+
+ loff_t chunk_base;
+
+ chunk /= dev->chunk_div;
+
+ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
+ offset = (u32) (addr - chunk_base);
+ }
+
+ *chunk_out = chunk;
+ *offset_out = offset;
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or
+ * equal to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+
+static inline u32 calc_shifts_ceiling(u32 x)
+{
+ int extra_bits;
+ int shifts;
+
+ shifts = extra_bits = 0;
+
+ while (x > 1) {
+ if (x & 1)
+ extra_bits++;
+ x >>= 1;
+ shifts++;
+ }
+
+ if (extra_bits)
+ shifts++;
+
+ return shifts;
+}
+
+/* Function to return the number of shifts to get a 1 in bit 0
+ */
+
+static inline u32 calc_shifts(u32 x)
+{
+ u32 shifts;
+
+ shifts = 0;
+
+ if (!x)
+ return 0;
+
+ while (!(x & 1)) {
+ x >>= 1;
+ shifts++;
+ }
+
+ return shifts;
+}
+
+/*
+ * Temporary buffer manipulations.
+ */
+
+static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
+{
+ int i;
+ u8 *buf = (u8 *) 1;
+
+ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
+
+ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
+ dev->temp_buffer[i].in_use = 0;
+ buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+ dev->temp_buffer[i].buffer = buf;
+ }
+
+ return buf ? YAFFS_OK : YAFFS_FAIL;
+}
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
+{
+ int i;
+
+ dev->temp_in_use++;
+ if (dev->temp_in_use > dev->max_temp)
+ dev->max_temp = dev->temp_in_use;
+
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->temp_buffer[i].in_use == 0) {
+ dev->temp_buffer[i].in_use = 1;
+ return dev->temp_buffer[i].buffer;
+ }
+ }
+
+ yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
+ /*
+ * If we got here then we have to allocate an unmanaged one
+ * This is not good.
+ */
+
+ dev->unmanaged_buffer_allocs++;
+ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
+
+}
+
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
+{
+ int i;
+
+ dev->temp_in_use--;
+
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->temp_buffer[i].buffer == buffer) {
+ dev->temp_buffer[i].in_use = 0;
+ return;
+ }
+ }
+
+ if (buffer) {
+ /* assume it is an unmanaged one. */
+ yaffs_trace(YAFFS_TRACE_BUFFERS, "Releasing unmanaged temp buffer");
+ kfree(buffer);
+ dev->unmanaged_buffer_deallocs++;
+ }
+
+}
+
+/*
+ * Determine if we have a managed buffer.
+ */
+int yaffs_is_managed_tmp_buffer(struct yaffs_dev *dev, const u8 *buffer)
+{
+ int i;
+
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->temp_buffer[i].buffer == buffer)
+ return 1;
+ }
+
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].data == buffer)
+ return 1;
+ }
+
+ if (buffer == dev->checkpt_buffer)
+ return 1;
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: unmaged buffer detected.");
+ return 0;
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+
+static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data,
+ const struct yaffs_ext_tags *tags)
+{
+ dev = dev;
+ nand_chunk = nand_chunk;
+ data = data;
+ tags = tags;
+}
+
+static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
+ const struct yaffs_ext_tags *tags)
+{
+ dev = dev;
+ nand_chunk = nand_chunk;
+ tags = tags;
+}
+
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi)
+{
+ if (!bi->gc_prioritise) {
+ bi->gc_prioritise = 1;
+ dev->has_pending_prioritised_gc = 1;
+ bi->chunk_error_strikes++;
+
+ if (bi->chunk_error_strikes > 3) {
+ bi->needs_retiring = 1; /* Too many stikes, so retire */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Block struck out");
+
+ }
+ }
+}
+
+static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
+ int erased_ok)
+{
+ int flash_block = nand_chunk / dev->param.chunks_per_block;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+ yaffs_handle_chunk_error(dev, bi);
+
+ if (erased_ok) {
+ /* Was an actual write failure,
+ * so mark the block for retirement.*/
+ bi->needs_retiring = 1;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Block %d needs retiring", flash_block);
+ }
+
+ /* Delete the chunk */
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ yaffs_skip_rest_of_block(dev);
+}
+
+/*
+ * Verification code
+ */
+
+/*
+ * Simple hash function. Needs to have a reasonable spread
+ */
+
+static inline int yaffs_hash_fn(int n)
+{
+ n = abs(n);
+ return n % YAFFS_NOBJECT_BUCKETS;
+}
+
+/*
+ * Access functions to useful fake objects.
+ * Note that root might have a presence in NAND if permissions are set.
+ */
+
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
+{
+ return dev->root_dir;
+}
+
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
+{
+ return dev->lost_n_found;
+}
+
+/*
+ * Erased NAND checking functions
+ */
+
+int yaffs_check_ff(u8 *buffer, int n_bytes)
+{
+ /* Horrible, slow implementation */
+ while (n_bytes--) {
+ if (*buffer != 0xff)
+ return 0;
+ buffer++;
+ }
+ return 1;
+}
+
+static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
+{
+ int retval = YAFFS_OK;
+ u8 *data = yaffs_get_temp_buffer(dev);
+ struct yaffs_ext_tags tags;
+ int result;
+
+ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
+
+ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
+ retval = YAFFS_FAIL;
+
+ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
+ tags.chunk_used) {
+ yaffs_trace(YAFFS_TRACE_NANDACCESS,
+ "Chunk %d not erased", nand_chunk);
+ retval = YAFFS_FAIL;
+ }
+
+ yaffs_release_temp_buffer(dev, data);
+
+ return retval;
+
+}
+
+static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data,
+ struct yaffs_ext_tags *tags)
+{
+ int retval = YAFFS_OK;
+ struct yaffs_ext_tags temp_tags;
+ u8 *buffer = yaffs_get_temp_buffer(dev);
+ int result;
+
+ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
+ if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
+ temp_tags.obj_id != tags->obj_id ||
+ temp_tags.chunk_id != tags->chunk_id ||
+ temp_tags.n_bytes != tags->n_bytes)
+ retval = YAFFS_FAIL;
+
+ yaffs_release_temp_buffer(dev, buffer);
+
+ return retval;
+}
+
+
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
+{
+ int reserved_chunks;
+ int reserved_blocks = dev->param.n_reserved_blocks;
+ int checkpt_blocks;
+
+ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
+
+ reserved_chunks =
+ (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
+
+ return (dev->n_free_chunks > (reserved_chunks + n_chunks));
+}
+
+static int yaffs_find_alloc_block(struct yaffs_dev *dev)
+{
+ int i;
+ struct yaffs_block_info *bi;
+
+ if (dev->n_erased_blocks < 1) {
+ /* Hoosterman we've got a problem.
+ * Can't get space to gc
+ */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: no more erased blocks");
+
+ return -1;
+ }
+
+ /* Find an empty block. */
+
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ dev->alloc_block_finder++;
+ if (dev->alloc_block_finder < dev->internal_start_block
+ || dev->alloc_block_finder > dev->internal_end_block) {
+ dev->alloc_block_finder = dev->internal_start_block;
+ }
+
+ bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->seq_number++;
+ bi->seq_number = dev->seq_number;
+ dev->n_erased_blocks--;
+ yaffs_trace(YAFFS_TRACE_ALLOCATE,
+ "Allocated block %d, seq %d, %d left" ,
+ dev->alloc_block_finder, dev->seq_number,
+ dev->n_erased_blocks);
+ return dev->alloc_block_finder;
+ }
+ }
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs tragedy: no more erased blocks, but there should have been %d",
+ dev->n_erased_blocks);
+
+ return -1;
+}
+
+static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
+ struct yaffs_block_info **block_ptr)
+{
+ int ret_val;
+ struct yaffs_block_info *bi;
+
+ if (dev->alloc_block < 0) {
+ /* Get next block to allocate off */
+ dev->alloc_block = yaffs_find_alloc_block(dev);
+ dev->alloc_page = 0;
+ }
+
+ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
+ /* No space unless we're allowed to use the reserve. */
+ return -1;
+ }
+
+ if (dev->n_erased_blocks < dev->param.n_reserved_blocks
+ && dev->alloc_page == 0)
+ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
+
+ /* Next page please.... */
+ if (dev->alloc_block >= 0) {
+ bi = yaffs_get_block_info(dev, dev->alloc_block);
+
+ ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
+ dev->alloc_page;
+ bi->pages_in_use++;
+ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
+
+ dev->alloc_page++;
+
+ dev->n_free_chunks--;
+
+ /* If the block is full set the state to full */
+ if (dev->alloc_page >= dev->param.chunks_per_block) {
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ dev->alloc_block = -1;
+ }
+
+ if (block_ptr)
+ *block_ptr = bi;
+
+ return ret_val;
+ }
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
+
+ return -1;
+}
+
+static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
+{
+ int n;
+
+ n = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+ if (dev->alloc_block > 0)
+ n += (dev->param.chunks_per_block - dev->alloc_page);
+
+ return n;
+
+}
+
+/*
+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
+{
+ struct yaffs_block_info *bi;
+
+ if (dev->alloc_block > 0) {
+ bi = yaffs_get_block_info(dev, dev->alloc_block);
+ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ dev->alloc_block = -1;
+ }
+ }
+}
+
+static int yaffs_write_new_chunk(struct yaffs_dev *dev,
+ const u8 *data,
+ struct yaffs_ext_tags *tags, int use_reserver)
+{
+ int attempts = 0;
+ int write_ok = 0;
+ int chunk;
+
+ yaffs2_checkpt_invalidate(dev);
+
+ do {
+ struct yaffs_block_info *bi = 0;
+ int erased_ok = 0;
+
+ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
+ if (chunk < 0) {
+ /* no space */
+ break;
+ }
+
+ /* First check this chunk is erased, if it needs
+ * checking. The checking policy (unless forced
+ * always on) is as follows:
+ *
+ * Check the first page we try to write in a block.
+ * If the check passes then we don't need to check any
+ * more. If the check fails, we check again...
+ * If the block has been erased, we don't need to check.
+ *
+ * However, if the block has been prioritised for gc,
+ * then we think there might be something odd about
+ * this block and stop using it.
+ *
+ * Rationale: We should only ever see chunks that have
+ * not been erased if there was a partially written
+ * chunk due to power loss. This checking policy should
+ * catch that case with very few checks and thus save a
+ * lot of checks that are most likely not needed.
+ *
+ * Mods to the above
+ * If an erase check fails or the write fails we skip the
+ * rest of the block.
+ */
+
+ /* let's give it a try */
+ attempts++;
+
+ if (dev->param.always_check_erased)
+ bi->skip_erased_check = 0;
+
+ if (!bi->skip_erased_check) {
+ erased_ok = yaffs_check_chunk_erased(dev, chunk);
+ if (erased_ok != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs chunk %d was not erased",
+ chunk);
+
+ /* If not erased, delete this one,
+ * skip rest of block and
+ * try another chunk */
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ yaffs_skip_rest_of_block(dev);
+ continue;
+ }
+ }
+
+ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
+
+ if (!bi->skip_erased_check)
+ write_ok =
+ yaffs_verify_chunk_written(dev, chunk, data, tags);
+
+ if (write_ok != YAFFS_OK) {
+ /* Clean up aborted write, skip to next block and
+ * try another chunk */
+ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
+ continue;
+ }
+
+ bi->skip_erased_check = 1;
+
+ /* Copy the data into the robustification buffer */
+ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
+
+ } while (write_ok != YAFFS_OK &&
+ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+
+ if (!write_ok)
+ chunk = -1;
+
+ if (attempts > 1) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs write required %d attempts",
+ attempts);
+ dev->n_retried_writes += (attempts - 1);
+ }
+
+ return chunk;
+}
+
+/*
+ * Block retiring for handling a broken block.
+ */
+
+static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
+{
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+ yaffs2_checkpt_invalidate(dev);
+
+ yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
+ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Failed to mark bad and erase block %d",
+ flash_block);
+ } else {
+ struct yaffs_ext_tags tags;
+ int chunk_id =
+ flash_block * dev->param.chunks_per_block;
+
+ u8 *buffer = yaffs_get_temp_buffer(dev);
+
+ memset(buffer, 0xff, dev->data_bytes_per_chunk);
+ memset(&tags, 0, sizeof(tags));
+ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
+ if (dev->param.write_chunk_tags_fn(dev, chunk_id -
+ dev->chunk_offset,
+ buffer,
+ &tags) != YAFFS_OK)
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Failed to write bad block marker to block %d",
+ flash_block);
+
+ yaffs_release_temp_buffer(dev, buffer);
+ }
+ }
+
+ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+ bi->gc_prioritise = 0;
+ bi->needs_retiring = 0;
+
+ dev->n_retired_blocks++;
+}
+
+/*---------------- Name handling functions ------------*/
+
+static u16 yaffs_calc_name_sum(const YCHAR *name)
+{
+ u16 sum = 0;
+ u16 i = 1;
+
+ if (!name)
+ return 0;
+
+ while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
+
+ /* 0x1f mask is case insensitive */
+ sum += ((*name) & 0x1f) * i;
+ i++;
+ name++;
+ }
+ return sum;
+}
+
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
+{
+ memset(obj->short_name, 0, sizeof(obj->short_name));
+ if (name &&
+ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
+ YAFFS_SHORT_NAME_LENGTH)
+ strcpy(obj->short_name, name);
+ else
+ obj->short_name[0] = _Y('\0');
+ obj->sum = yaffs_calc_name_sum(name);
+}
+
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+ const struct yaffs_obj_hdr *oh)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
+ memset(tmp_name, 0, sizeof(tmp_name));
+ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ yaffs_set_obj_name(obj, tmp_name);
+#else
+ yaffs_set_obj_name(obj, oh->name);
+#endif
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * The list is hooked together using the first pointer
+ * in the tnode.
+ */
+
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
+{
+ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
+
+ if (tn) {
+ memset(tn, 0, dev->tnode_size);
+ dev->n_tnodes++;
+ }
+
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+
+ return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+ yaffs_free_raw_tnode(dev, tn);
+ dev->n_tnodes--;
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+}
+
+static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
+{
+ yaffs_deinit_raw_tnodes_and_objs(dev);
+ dev->n_obj = 0;
+ dev->n_tnodes = 0;
+}
+
+void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos, unsigned val)
+{
+ u32 *map = (u32 *) tn;
+ u32 bit_in_map;
+ u32 bit_in_word;
+ u32 word_in_map;
+ u32 mask;
+
+ pos &= YAFFS_TNODES_LEVEL0_MASK;
+ val >>= dev->chunk_grp_bits;
+
+ bit_in_map = pos * dev->tnode_width;
+ word_in_map = bit_in_map / 32;
+ bit_in_word = bit_in_map & (32 - 1);
+
+ mask = dev->tnode_mask << bit_in_word;
+
+ map[word_in_map] &= ~mask;
+ map[word_in_map] |= (mask & (val << bit_in_word));
+
+ if (dev->tnode_width > (32 - bit_in_word)) {
+ bit_in_word = (32 - bit_in_word);
+ word_in_map++;
+ mask =
+ dev->tnode_mask >> bit_in_word;
+ map[word_in_map] &= ~mask;
+ map[word_in_map] |= (mask & (val >> bit_in_word));
+ }
+}
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos)
+{
+ u32 *map = (u32 *) tn;
+ u32 bit_in_map;
+ u32 bit_in_word;
+ u32 word_in_map;
+ u32 val;
+
+ pos &= YAFFS_TNODES_LEVEL0_MASK;
+
+ bit_in_map = pos * dev->tnode_width;
+ word_in_map = bit_in_map / 32;
+ bit_in_word = bit_in_map & (32 - 1);
+
+ val = map[word_in_map] >> bit_in_word;
+
+ if (dev->tnode_width > (32 - bit_in_word)) {
+ bit_in_word = (32 - bit_in_word);
+ word_in_map++;
+ val |= (map[word_in_map] << bit_in_word);
+ }
+
+ val &= dev->tnode_mask;
+ val <<= dev->chunk_grp_bits;
+
+ return val;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of top_level
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id)
+{
+ struct yaffs_tnode *tn = file_struct->top;
+ u32 i;
+ int required_depth;
+ int level = file_struct->top_level;
+
+ dev = dev;
+
+ /* Check sane level and chunk Id */
+ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
+ return NULL;
+
+ if (chunk_id > YAFFS_MAX_CHUNK_ID)
+ return NULL;
+
+ /* First check we're tall enough (ie enough top_level) */
+
+ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+ required_depth = 0;
+ while (i) {
+ i >>= YAFFS_TNODES_INTERNAL_BITS;
+ required_depth++;
+ }
+
+ if (required_depth > file_struct->top_level)
+ return NULL; /* Not tall enough, so we can't find it */
+
+ /* Traverse down to level 0 */
+ while (level > 0 && tn) {
+ tn = tn->internal[(chunk_id >>
+ (YAFFS_TNODES_LEVEL0_BITS +
+ (level - 1) *
+ YAFFS_TNODES_INTERNAL_BITS)) &
+ YAFFS_TNODES_INTERNAL_MASK];
+ level--;
+ }
+
+ return tn;
+}
+
+/* add_find_tnode_0 finds the level 0 tnode if it exists,
+ * otherwise first expands the tree.
+ * This happens in two steps:
+ * 1. If the tree isn't tall enough, then make it taller.
+ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ * If the tn argument is NULL, then a fresh tnode will be added otherwise the
+ * specified tn will be plugged into the ttree.
+ */
+
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id,
+ struct yaffs_tnode *passed_tn)
+{
+ int required_depth;
+ int i;
+ int l;
+ struct yaffs_tnode *tn;
+ u32 x;
+
+ /* Check sane level and page Id */
+ if (file_struct->top_level < 0 ||
+ file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
+ return NULL;
+
+ if (chunk_id > YAFFS_MAX_CHUNK_ID)
+ return NULL;
+
+ /* First check we're tall enough (ie enough top_level) */
+
+ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+ required_depth = 0;
+ while (x) {
+ x >>= YAFFS_TNODES_INTERNAL_BITS;
+ required_depth++;
+ }
+
+ if (required_depth > file_struct->top_level) {
+ /* Not tall enough, gotta make the tree taller */
+ for (i = file_struct->top_level; i < required_depth; i++) {
+
+ tn = yaffs_get_tnode(dev);
+
+ if (tn) {
+ tn->internal[0] = file_struct->top;
+ file_struct->top = tn;
+ file_struct->top_level++;
+ } else {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs: no more tnodes");
+ return NULL;
+ }
+ }
+ }
+
+ /* Traverse down to level 0, adding anything we need */
+
+ l = file_struct->top_level;
+ tn = file_struct->top;
+
+ if (l > 0) {
+ while (l > 0 && tn) {
+ x = (chunk_id >>
+ (YAFFS_TNODES_LEVEL0_BITS +
+ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+ YAFFS_TNODES_INTERNAL_MASK;
+
+ if ((l > 1) && !tn->internal[x]) {
+ /* Add missing non-level-zero tnode */
+ tn->internal[x] = yaffs_get_tnode(dev);
+ if (!tn->internal[x])
+ return NULL;
+ } else if (l == 1) {
+ /* Looking from level 1 at level 0 */
+ if (passed_tn) {
+ /* If we already have one, release it */
+ if (tn->internal[x])
+ yaffs_free_tnode(dev,
+ tn->internal[x]);
+ tn->internal[x] = passed_tn;
+
+ } else if (!tn->internal[x]) {
+ /* Don't have one, none passed in */
+ tn->internal[x] = yaffs_get_tnode(dev);
+ if (!tn->internal[x])
+ return NULL;
+ }
+ }
+
+ tn = tn->internal[x];
+ l--;
+ }
+ } else {
+ /* top is level 0 */
+ if (passed_tn) {
+ memcpy(tn, passed_tn,
+ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
+ yaffs_free_tnode(dev, passed_tn);
+ }
+ }
+
+ return tn;
+}
+
+static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
+ int chunk_obj)
+{
+ return (tags->chunk_id == chunk_obj &&
+ tags->obj_id == obj_id &&
+ !tags->is_deleted) ? 1 : 0;
+
+}
+
+static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
+ struct yaffs_ext_tags *tags, int obj_id,
+ int inode_chunk)
+{
+ int j;
+
+ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
+ if (yaffs_check_chunk_bit
+ (dev, the_chunk / dev->param.chunks_per_block,
+ the_chunk % dev->param.chunks_per_block)) {
+
+ if (dev->chunk_grp_size == 1)
+ return the_chunk;
+ else {
+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+ tags);
+ if (yaffs_tags_match(tags,
+ obj_id, inode_chunk)) {
+ /* found it; */
+ return the_chunk;
+ }
+ }
+ }
+ the_chunk++;
+ }
+ return -1;
+}
+
+static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ struct yaffs_ext_tags *tags)
+{
+ /*Get the Tnode, then get the level 0 offset chunk offset */
+ struct yaffs_tnode *tn;
+ int the_chunk = -1;
+ struct yaffs_ext_tags local_tags;
+ int ret_val = -1;
+ struct yaffs_dev *dev = in->my_dev;
+
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &local_tags;
+ }
+
+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+ if (!tn)
+ return ret_val;
+
+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+ inode_chunk);
+ return ret_val;
+}
+
+static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
+ struct yaffs_ext_tags *tags)
+{
+ /* Get the Tnode, then get the level 0 offset chunk offset */
+ struct yaffs_tnode *tn;
+ int the_chunk = -1;
+ struct yaffs_ext_tags local_tags;
+ struct yaffs_dev *dev = in->my_dev;
+ int ret_val = -1;
+
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &local_tags;
+ }
+
+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+ if (!tn)
+ return ret_val;
+
+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+ ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+ inode_chunk);
+
+ /* Delete the entry in the filestructure (if found) */
+ if (ret_val != -1)
+ yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
+
+ return ret_val;
+}
+
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ int nand_chunk, int in_scan)
+{
+ /* NB in_scan is zero unless scanning.
+ * For forward scanning, in_scan is > 0;
+ * for backward scanning in_scan is < 0
+ *
+ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
+ */
+
+ struct yaffs_tnode *tn;
+ struct yaffs_dev *dev = in->my_dev;
+ int existing_cunk;
+ struct yaffs_ext_tags existing_tags;
+ struct yaffs_ext_tags new_tags;
+ unsigned existing_serial, new_serial;
+
+ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
+ /* Just ignore an attempt at putting a chunk into a non-file
+ * during scanning.
+ * If it is not during Scanning then something went wrong!
+ */
+ if (!in_scan) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy:attempt to put data chunk into a non-file"
+ );
+ BUG();
+ }
+
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ return YAFFS_OK;
+ }
+
+ tn = yaffs_add_find_tnode_0(dev,
+ &in->variant.file_variant,
+ inode_chunk, NULL);
+ if (!tn)
+ return YAFFS_FAIL;
+
+ if (!nand_chunk)
+ /* Dummy insert, bail now */
+ return YAFFS_OK;
+
+ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+ if (in_scan != 0) {
+ /* If we're scanning then we need to test for duplicates
+ * NB This does not need to be efficient since it should only
+ * happen when the power fails during a write, then only one
+ * chunk should ever be affected.
+ *
+ * Correction for YAFFS2: This could happen quite a lot and we
+ * need to think about efficiency! TODO
+ * Update: For backward scanning we don't need to re-read tags
+ * so this is quite cheap.
+ */
+
+ if (existing_cunk > 0) {
+ /* NB Right now existing chunk will not be real
+ * chunk_id if the chunk group size > 1
+ * thus we have to do a FindChunkInFile to get the
+ * real chunk id.
+ *
+ * We have a duplicate now we need to decide which
+ * one to use:
+ *
+ * Backwards scanning YAFFS2: The old one is what
+ * we use, dump the new one.
+ * YAFFS1: Get both sets of tags and compare serial
+ * numbers.
+ */
+
+ if (in_scan > 0) {
+ /* Only do this for forward scanning */
+ yaffs_rd_chunk_tags_nand(dev,
+ nand_chunk,
+ NULL, &new_tags);
+
+ /* Do a proper find */
+ existing_cunk =
+ yaffs_find_chunk_in_file(in, inode_chunk,
+ &existing_tags);
+ }
+
+ if (existing_cunk <= 0) {
+ /*Hoosterman - how did this happen? */
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: existing chunk < 0 in scan"
+ );
+
+ }
+
+ /* NB The deleted flags should be false, otherwise
+ * the chunks will not be loaded during a scan
+ */
+
+ if (in_scan > 0) {
+ new_serial = new_tags.serial_number;
+ existing_serial = existing_tags.serial_number;
+ }
+
+ if ((in_scan > 0) &&
+ (existing_cunk <= 0 ||
+ ((existing_serial + 1) & 3) == new_serial)) {
+ /* Forward scanning.
+ * Use new
+ * Delete the old one and drop through to
+ * update the tnode
+ */
+ yaffs_chunk_del(dev, existing_cunk, 1,
+ __LINE__);
+ } else {
+ /* Backward scanning or we want to use the
+ * existing one
+ * Delete the new one and return early so that
+ * the tnode isn't changed
+ */
+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+ return YAFFS_OK;
+ }
+ }
+
+ }
+
+ if (existing_cunk == 0)
+ in->n_data_chunks++;
+
+ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
+
+ return YAFFS_OK;
+}
+
+static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
+{
+ struct yaffs_block_info *the_block;
+ unsigned block_no;
+
+ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
+
+ block_no = chunk / dev->param.chunks_per_block;
+ the_block = yaffs_get_block_info(dev, block_no);
+ if (the_block) {
+ the_block->soft_del_pages++;
+ dev->n_free_chunks++;
+ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
+ }
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
+ * the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls
+ * the chunk out of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks
+ * are soft deleted.
+ */
+
+static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
+ u32 level, int chunk_offset)
+{
+ int i;
+ int the_chunk;
+ int all_done = 1;
+ struct yaffs_dev *dev = in->my_dev;
+
+ if (!tn)
+ return 1;
+
+ if (level > 0) {
+ for (i = YAFFS_NTNODES_INTERNAL - 1;
+ all_done && i >= 0;
+ i--) {
+ if (tn->internal[i]) {
+ all_done =
+ yaffs_soft_del_worker(in,
+ tn->internal[i],
+ level - 1,
+ (chunk_offset <<
+ YAFFS_TNODES_INTERNAL_BITS)
+ + i);
+ if (all_done) {
+ yaffs_free_tnode(dev,
+ tn->internal[i]);
+ tn->internal[i] = NULL;
+ } else {
+ /* Can this happen? */
+ }
+ }
+ }
+ return (all_done) ? 1 : 0;
+ }
+
+ /* level 0 */
+ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+ the_chunk = yaffs_get_group_base(dev, tn, i);
+ if (the_chunk) {
+ yaffs_soft_del_chunk(dev, the_chunk);
+ yaffs_load_tnode_0(dev, tn, i, 0);
+ }
+ }
+ return 1;
+}
+
+static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ struct yaffs_obj *parent;
+
+ yaffs_verify_obj_in_dir(obj);
+ parent = obj->parent;
+
+ yaffs_verify_dir(parent);
+
+ if (dev && dev->param.remove_obj_fn)
+ dev->param.remove_obj_fn(obj);
+
+ list_del_init(&obj->siblings);
+ obj->parent = NULL;
+
+ yaffs_verify_dir(parent);
+}
+
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
+{
+ if (!directory) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: Trying to add an object to a null pointer directory"
+ );
+ BUG();
+ return;
+ }
+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: Trying to add an object to a non-directory"
+ );
+ BUG();
+ }
+
+ if (obj->siblings.prev == NULL) {
+ /* Not initialised */
+ BUG();
+ }
+
+ yaffs_verify_dir(directory);
+
+ yaffs_remove_obj_from_dir(obj);
+
+ /* Now add it */
+ list_add(&obj->siblings, &directory->variant.dir_variant.children);
+ obj->parent = directory;
+
+ if (directory == obj->my_dev->unlinked_dir
+ || directory == obj->my_dev->del_dir) {
+ obj->unlinked = 1;
+ obj->my_dev->n_unlinked_files++;
+ obj->rename_allowed = 0;
+ }
+
+ yaffs_verify_dir(directory);
+ yaffs_verify_obj_in_dir(obj);
+}
+
+static int yaffs_change_obj_name(struct yaffs_obj *obj,
+ struct yaffs_obj *new_dir,
+ const YCHAR *new_name, int force, int shadows)
+{
+ int unlink_op;
+ int del_op;
+ struct yaffs_obj *existing_target;
+
+ if (new_dir == NULL)
+ new_dir = obj->parent; /* use the old directory */
+
+ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_change_obj_name: new_dir is not a directory"
+ );
+ BUG();
+ }
+
+ unlink_op = (new_dir == obj->my_dev->unlinked_dir);
+ del_op = (new_dir == obj->my_dev->del_dir);
+
+ existing_target = yaffs_find_by_name(new_dir, new_name);
+
+ /* If the object is a file going into the unlinked directory,
+ * then it is OK to just stuff it in since duplicate names are OK.
+ * else only proceed if the new name does not exist and we're putting
+ * it into a directory.
+ */
+ if (!(unlink_op || del_op || force ||
+ shadows > 0 || !existing_target) ||
+ new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ return YAFFS_FAIL;
+
+ yaffs_set_obj_name(obj, new_name);
+ obj->dirty = 1;
+ yaffs_add_obj_to_dir(new_dir, obj);
+
+ if (unlink_op)
+ obj->unlinked = 1;
+
+ /* If it is a deletion then we mark it as a shrink for gc */
+ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+/*------------------------ Short Operations Cache ------------------------------
+ * In many situations where there is no high level buffering a lot of
+ * reads might be short sequential reads, and a lot of writes may be short
+ * sequential writes. eg. scanning/writing a jpeg file.
+ * In these cases, a short read/write cache can provide a huge perfomance
+ * benefit with dumb-as-a-rock code.
+ * In Linux, the page cache provides read buffering and the short op cache
+ * provides write buffering.
+ *
+ * There are a small number (~10) of cache chunks per device so that we don't
+ * need a very intelligent search.
+ */
+
+static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ int i;
+ struct yaffs_cache *cache;
+ int n_caches = obj->my_dev->param.n_caches;
+
+ for (i = 0; i < n_caches; i++) {
+ cache = &dev->cache[i];
+ if (cache->object == obj && cache->dirty)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void yaffs_flush_file_cache(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ int lowest = -99; /* Stop compiler whining. */
+ int i;
+ struct yaffs_cache *cache;
+ int chunk_written = 0;
+ int n_caches = obj->my_dev->param.n_caches;
+
+ if (n_caches < 1)
+ return;
+ do {
+ cache = NULL;
+
+ /* Find the lowest dirty chunk for this object */
+ for (i = 0; i < n_caches; i++) {
+ if (dev->cache[i].object == obj &&
+ dev->cache[i].dirty) {
+ if (!cache ||
+ dev->cache[i].chunk_id < lowest) {
+ cache = &dev->cache[i];
+ lowest = cache->chunk_id;
+ }
+ }
+ }
+
+ if (cache && !cache->locked) {
+ /* Write it out and free it up */
+ chunk_written =
+ yaffs_wr_data_obj(cache->object,
+ cache->chunk_id,
+ cache->data,
+ cache->n_bytes, 1);
+ cache->dirty = 0;
+ cache->object = NULL;
+ }
+ } while (cache && chunk_written > 0);
+
+ if (cache)
+ /* Hoosterman, disk full while writing cache out. */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: no space during cache write");
+}
+
+/*yaffs_flush_whole_cache(dev)
+ *
+ *
+ */
+
+void yaffs_flush_whole_cache(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ int n_caches = dev->param.n_caches;
+ int i;
+
+ /* Find a dirty object in the cache and flush it...
+ * until there are no further dirty objects.
+ */
+ do {
+ obj = NULL;
+ for (i = 0; i < n_caches && !obj; i++) {
+ if (dev->cache[i].object && dev->cache[i].dirty)
+ obj = dev->cache[i].object;
+ }
+ if (obj)
+ yaffs_flush_file_cache(obj);
+ } while (obj);
+
+}
+
+/* Grab us a cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
+{
+ int i;
+
+ if (dev->param.n_caches > 0) {
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (!dev->cache[i].object)
+ return &dev->cache[i];
+ }
+ }
+ return NULL;
+}
+
+static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
+{
+ struct yaffs_cache *cache;
+ struct yaffs_obj *the_obj;
+ int usage;
+ int i;
+ int pushout;
+
+ if (dev->param.n_caches < 1)
+ return NULL;
+
+ /* Try find a non-dirty one... */
+
+ cache = yaffs_grab_chunk_worker(dev);
+
+ if (!cache) {
+ /* They were all dirty, find the LRU object and flush
+ * its cache, then find again.
+ * NB what's here is not very accurate,
+ * we actually flush the object with the LRU chunk.
+ */
+
+ /* With locking we can't assume we can use entry zero,
+ * Set the_obj to a valid pointer for Coverity. */
+ the_obj = dev->cache[0].object;
+ usage = -1;
+ cache = NULL;
+ pushout = -1;
+
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object &&
+ !dev->cache[i].locked &&
+ (dev->cache[i].last_use < usage ||
+ !cache)) {
+ usage = dev->cache[i].last_use;
+ the_obj = dev->cache[i].object;
+ cache = &dev->cache[i];
+ pushout = i;
+ }
+ }
+
+ if (!cache || cache->dirty) {
+ /* Flush and try again */
+ yaffs_flush_file_cache(the_obj);
+ cache = yaffs_grab_chunk_worker(dev);
+ }
+ }
+ return cache;
+}
+
+/* Find a cached chunk */
+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
+ int chunk_id)
+{
+ struct yaffs_dev *dev = obj->my_dev;
+ int i;
+
+ if (dev->param.n_caches < 1)
+ return NULL;
+
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object == obj &&
+ dev->cache[i].chunk_id == chunk_id) {
+ dev->cache_hits++;
+
+ return &dev->cache[i];
+ }
+ }
+ return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
+ int is_write)
+{
+ int i;
+
+ if (dev->param.n_caches < 1)
+ return;
+
+ if (dev->cache_last_use < 0 ||
+ dev->cache_last_use > 100000000) {
+ /* Reset the cache usages */
+ for (i = 1; i < dev->param.n_caches; i++)
+ dev->cache[i].last_use = 0;
+
+ dev->cache_last_use = 0;
+ }
+ dev->cache_last_use++;
+ cache->last_use = dev->cache_last_use;
+
+ if (is_write)
+ cache->dirty = 1;
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
+{
+ struct yaffs_cache *cache;
+
+ if (object->my_dev->param.n_caches > 0) {
+ cache = yaffs_find_chunk_cache(object, chunk_id);
+
+ if (cache)
+ cache->object = NULL;
+ }
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
+{
+ int i;
+ struct yaffs_dev *dev = in->my_dev;
+
+ if (dev->param.n_caches > 0) {
+ /* Invalidate it. */
+ for (i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].object == in)
+ dev->cache[i].object = NULL;
+ }
+ }
+}
+
+static void yaffs_unhash_obj(struct yaffs_obj *obj)
+{
+ int bucket;
+ struct yaffs_dev *dev = obj->my_dev;
+
+ /* If it is still linked into the bucket list, free from the list */
+ if (!list_empty(&obj->hash_link)) {
+ list_del_init(&obj->hash_link);
+ bucket = yaffs_hash_fn(obj->obj_id);
+ dev->obj_bucket[bucket].count--;
+ }
+}
+
+/* FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_free_obj(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev;
+
+ if (!obj) {
+ BUG();
+ return;
+ }
+ dev = obj->my_dev;
+ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
+ obj, obj->my_inode);
+ if (obj->parent)
+ BUG();
+ if (!list_empty(&obj->siblings))
+ BUG();
+
+ if (obj->my_inode) {
+ /* We're still hooked up to a cached inode.
+ * Don't delete now, but mark for later deletion
+ */
+ obj->defered_free = 1;
+ return;
+ }
+
+ yaffs_unhash_obj(obj);
+
+ yaffs_free_raw_obj(dev, obj);
+ dev->n_obj--;
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+}
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj)
+{
+ if (obj->defered_free)
+ yaffs_free_obj(obj);
+}
+
+static int yaffs_generic_obj_del(struct yaffs_obj *in)
+{
+ /* Iinvalidate the file's data in the cache, without flushing. */
+ yaffs_invalidate_whole_cache(in);
+
+ if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
+ /* Move to unlinked directory so we have a deletion record */
+ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
+ 0);
+ }
+
+ yaffs_remove_obj_from_dir(in);
+ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
+ in->hdr_chunk = 0;
+
+ yaffs_free_obj(in);
+ return YAFFS_OK;
+
+}
+
+static void yaffs_soft_del_file(struct yaffs_obj *obj)
+{
+ if (!obj->deleted ||
+ obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
+ obj->soft_del)
+ return;
+
+ if (obj->n_data_chunks <= 0) {
+ /* Empty file with no duplicate object headers,
+ * just delete it immediately */
+ yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+ obj->variant.file_variant.top = NULL;
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: Deleting empty file %d",
+ obj->obj_id);
+ yaffs_generic_obj_del(obj);
+ } else {
+ yaffs_soft_del_worker(obj,
+ obj->variant.file_variant.top,
+ obj->variant.
+ file_variant.top_level, 0);
+ obj->soft_del = 1;
+ }
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ *
+ * This function is recursive. For levels > 0 the function is called again on
+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
+ * If there is no data in a subtree then it is pruned.
+ */
+
+static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
+ struct yaffs_tnode *tn, u32 level,
+ int del0)
+{
+ int i;
+ int has_data;
+
+ if (!tn)
+ return tn;
+
+ has_data = 0;
+
+ if (level > 0) {
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i]) {
+ tn->internal[i] =
+ yaffs_prune_worker(dev,
+ tn->internal[i],
+ level - 1,
+ (i == 0) ? del0 : 1);
+ }
+
+ if (tn->internal[i])
+ has_data++;
+ }
+ } else {
+ int tnode_size_u32 = dev->tnode_size / sizeof(u32);
+ u32 *map = (u32 *) tn;
+
+ for (i = 0; !has_data && i < tnode_size_u32; i++) {
+ if (map[i])
+ has_data++;
+ }
+ }
+
+ if (has_data == 0 && del0) {
+ /* Free and return NULL */
+ yaffs_free_tnode(dev, tn);
+ tn = NULL;
+ }
+ return tn;
+}
+
+static int yaffs_prune_tree(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct)
+{
+ int i;
+ int has_data;
+ int done = 0;
+ struct yaffs_tnode *tn;
+
+ if (file_struct->top_level < 1)
+ return YAFFS_OK;
+
+ file_struct->top =
+ yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
+
+ /* Now we have a tree with all the non-zero branches NULL but
+ * the height is the same as it was.
+ * Let's see if we can trim internal tnodes to shorten the tree.
+ * We can do this if only the 0th element in the tnode is in use
+ * (ie all the non-zero are NULL)
+ */
+
+ while (file_struct->top_level && !done) {
+ tn = file_struct->top;
+
+ has_data = 0;
+ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i])
+ has_data++;
+ }
+
+ if (!has_data) {
+ file_struct->top = tn->internal[0];
+ file_struct->top_level--;
+ yaffs_free_tnode(dev, tn);
+ } else {
+ done = 1;
+ }
+ }
+
+ return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* alloc_empty_obj gets us a clean Object.*/
+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
+
+ if (!obj)
+ return obj;
+
+ dev->n_obj++;
+
+ /* Now sweeten it up... */
+
+ memset(obj, 0, sizeof(struct yaffs_obj));
+ obj->being_created = 1;
+
+ obj->my_dev = dev;
+ obj->hdr_chunk = 0;
+ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
+ INIT_LIST_HEAD(&(obj->hard_links));
+ INIT_LIST_HEAD(&(obj->hash_link));
+ INIT_LIST_HEAD(&obj->siblings);
+
+ /* Now make the directory sane */
+ if (dev->root_dir) {
+ obj->parent = dev->root_dir;
+ list_add(&(obj->siblings),
+ &dev->root_dir->variant.dir_variant.children);
+ }
+
+ /* Add it to the lost and found directory.
+ * NB Can't put root or lost-n-found in lost-n-found so
+ * check if lost-n-found exists first
+ */
+ if (dev->lost_n_found)
+ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+
+ obj->being_created = 0;
+
+ dev->checkpoint_blocks_required = 0; /* force recalculation */
+
+ return obj;
+}
+
+static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
+{
+ int i;
+ int l = 999;
+ int lowest = 999999;
+
+ /* Search for the shortest list or one that
+ * isn't too long.
+ */
+
+ for (i = 0; i < 10 && lowest > 4; i++) {
+ dev->bucket_finder++;
+ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
+ if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
+ lowest = dev->obj_bucket[dev->bucket_finder].count;
+ l = dev->bucket_finder;
+ }
+ }
+
+ return l;
+}
+
+static int yaffs_new_obj_id(struct yaffs_dev *dev)
+{
+ int bucket = yaffs_find_nice_bucket(dev);
+ int found = 0;
+ struct list_head *i;
+ u32 n = (u32) bucket;
+
+ /* Now find an object value that has not already been taken
+ * by scanning the list.
+ */
+
+ while (!found) {
+ found = 1;
+ n += YAFFS_NOBJECT_BUCKETS;
+ if (1 || dev->obj_bucket[bucket].count > 0) {
+ list_for_each(i, &dev->obj_bucket[bucket].list) {
+ /* If there is already one in the list */
+ if (i && list_entry(i, struct yaffs_obj,
+ hash_link)->obj_id == n) {
+ found = 0;
+ }
+ }
+ }
+ }
+ return n;
+}
+
+static void yaffs_hash_obj(struct yaffs_obj *in)
+{
+ int bucket = yaffs_hash_fn(in->obj_id);
+ struct yaffs_dev *dev = in->my_dev;
+
+ list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
+ dev->obj_bucket[bucket].count++;
+}
+
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
+{
+ int bucket = yaffs_hash_fn(number);
+ struct list_head *i;
+ struct yaffs_obj *in;
+
+ list_for_each(i, &dev->obj_bucket[bucket].list) {
+ /* Look if it is in the list */
+ in = list_entry(i, struct yaffs_obj, hash_link);
+ if (in->obj_id == number) {
+ /* Don't show if it is defered free */
+ if (in->defered_free)
+ return NULL;
+ return in;
+ }
+ }
+
+ return NULL;
+}
+
+struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
+ enum yaffs_obj_type type)
+{
+ struct yaffs_obj *the_obj = NULL;
+ struct yaffs_tnode *tn = NULL;
+
+ if (number < 0)
+ number = yaffs_new_obj_id(dev);
+
+ if (type == YAFFS_OBJECT_TYPE_FILE) {
+ tn = yaffs_get_tnode(dev);
+ if (!tn)
+ return NULL;
+ }
+
+ the_obj = yaffs_alloc_empty_obj(dev);
+ if (!the_obj) {
+ if (tn)
+ yaffs_free_tnode(dev, tn);
+ return NULL;
+ }
+
+ the_obj->fake = 0;
+ the_obj->rename_allowed = 1;
+ the_obj->unlink_allowed = 1;
+ the_obj->obj_id = number;
+ yaffs_hash_obj(the_obj);
+ the_obj->variant_type = type;
+ yaffs_load_current_time(the_obj, 1, 1);
+
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ the_obj->variant.file_variant.file_size = 0;
+ the_obj->variant.file_variant.scanned_size = 0;
+ the_obj->variant.file_variant.shrink_size = ~0; /* max */
+ the_obj->variant.file_variant.top_level = 0;
+ the_obj->variant.file_variant.top = tn;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* No action required */
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* todo this should not happen */
+ break;
+ }
+ return the_obj;
+}
+
+static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
+ int number, u32 mode)
+{
+
+ struct yaffs_obj *obj =
+ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+
+ if (!obj)
+ return NULL;
+
+ obj->fake = 1; /* it is fake so it might not use NAND */
+ obj->rename_allowed = 0;
+ obj->unlink_allowed = 0;
+ obj->deleted = 0;
+ obj->unlinked = 0;
+ obj->yst_mode = mode;
+ obj->my_dev = dev;
+ obj->hdr_chunk = 0; /* Not a valid chunk. */
+ return obj;
+
+}
+
+
+static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
+{
+ int i;
+
+ dev->n_obj = 0;
+ dev->n_tnodes = 0;
+ yaffs_init_raw_tnodes_and_objs(dev);
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ INIT_LIST_HEAD(&dev->obj_bucket[i].list);
+ dev->obj_bucket[i].count = 0;
+ }
+}
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+ int number,
+ enum yaffs_obj_type type)
+{
+ struct yaffs_obj *the_obj = NULL;
+
+ if (number > 0)
+ the_obj = yaffs_find_by_number(dev, number);
+
+ if (!the_obj)
+ the_obj = yaffs_new_obj(dev, number, type);
+
+ return the_obj;
+
+}
+
+YCHAR *yaffs_clone_str(const YCHAR *str)
+{
+ YCHAR *new_str = NULL;
+ int len;
+
+ if (!str)
+ str = _Y("");
+
+ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
+ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
+ if (new_str) {
+ strncpy(new_str, str, len);
+ new_str[len] = 0;
+ }
+ return new_str;
+
+}
+/*
+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ * create dir/a : update dir's mtime/ctime
+ * rm dir/a: update dir's mtime/ctime
+ * modify dir/a: don't update dir's mtimme/ctime
+ *
+ * This can be handled immediately or defered. Defering helps reduce the number
+ * of updates when many files in a directory are changed within a brief period.
+ *
+ * If the directory updating is defered then yaffs_update_dirty_dirs must be
+ * called periodically.
+ */
+
+static void yaffs_update_parent(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev;
+
+ if (!obj)
+ return;
+ dev = obj->my_dev;
+ obj->dirty = 1;
+ yaffs_load_current_time(obj, 0, 1);
+ if (dev->param.defered_dir_update) {
+ struct list_head *link = &obj->variant.dir_variant.dirty;
+
+ if (list_empty(link)) {
+ list_add(link, &dev->dirty_dirs);
+ yaffs_trace(YAFFS_TRACE_BACKGROUND,
+ "Added object %d to dirty directories",
+ obj->obj_id);
+ }
+
+ } else {
+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+ }
+}
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
+{
+ struct list_head *link;
+ struct yaffs_obj *obj;
+ struct yaffs_dir_var *d_s;
+ union yaffs_obj_var *o_v;
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
+
+ while (!list_empty(&dev->dirty_dirs)) {
+ link = dev->dirty_dirs.next;
+ list_del_init(link);
+
+ d_s = list_entry(link, struct yaffs_dir_var, dirty);
+ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
+ obj = list_entry(o_v, struct yaffs_obj, variant);
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
+ obj->obj_id);
+
+ if (obj->dirty)
+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+ }
+}
+
+/*
+ * Mknod (create) a new object.
+ * equiv_obj only has meaning for a hard link;
+ * alias_str only has meaning for a symlink.
+ * rdev only has meaning for devices (a subset of special objects)
+ */
+
+static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
+ struct yaffs_obj *parent,
+ const YCHAR *name,
+ u32 mode,
+ u32 uid,
+ u32 gid,
+ struct yaffs_obj *equiv_obj,
+ const YCHAR *alias_str, u32 rdev)
+{
+ struct yaffs_obj *in;
+ YCHAR *str = NULL;
+ struct yaffs_dev *dev = parent->my_dev;
+
+ /* Check if the entry exists.
+ * If it does then fail the call since we don't want a dup. */
+ if (yaffs_find_by_name(parent, name))
+ return NULL;
+
+ if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ str = yaffs_clone_str(alias_str);
+ if (!str)
+ return NULL;
+ }
+
+ in = yaffs_new_obj(dev, -1, type);
+
+ if (!in) {
+ kfree(str);
+ return NULL;
+ }
+
+ in->hdr_chunk = 0;
+ in->valid = 1;
+ in->variant_type = type;
+
+ in->yst_mode = mode;
+
+ yaffs_attribs_init(in, gid, uid, rdev);
+
+ in->n_data_chunks = 0;
+
+ yaffs_set_obj_name(in, name);
+ in->dirty = 1;
+
+ yaffs_add_obj_to_dir(parent, in);
+
+ in->my_dev = parent->my_dev;
+
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symlink_variant.alias = str;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardlink_variant.equiv_obj = equiv_obj;
+ in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
+ list_add(&in->hard_links, &equiv_obj->hard_links);
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* do nothing */
+ break;
+ }
+
+ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
+ /* Could not create the object header, fail */
+ yaffs_del_obj(in);
+ in = NULL;
+ }
+
+ if (in)
+ yaffs_update_parent(parent);
+
+ return in;
+}
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid)
+{
+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+ uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+ u32 mode, u32 uid, u32 gid)
+{
+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+ mode, uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, u32 rdev)
+{
+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+ uid, gid, NULL, NULL, rdev);
+}
+
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, const YCHAR *alias)
+{
+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+ uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_link_obj returns the object id of the equivalent object.*/
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
+ struct yaffs_obj *equiv_obj)
+{
+ /* Get the real object in case we were fed a hard link obj */
+ equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
+
+ if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
+ parent, name, 0, 0, 0,
+ equiv_obj, NULL, 0))
+ return equiv_obj;
+
+ return NULL;
+
+}
+
+
+
+/*---------------------- Block Management and Page Allocation -------------*/
+
+static void yaffs_deinit_blocks(struct yaffs_dev *dev)
+{
+ if (dev->block_info_alt && dev->block_info)
+ vfree(dev->block_info);
+ else
+ kfree(dev->block_info);
+
+ dev->block_info_alt = 0;
+
+ dev->block_info = NULL;
+
+ if (dev->chunk_bits_alt && dev->chunk_bits)
+ vfree(dev->chunk_bits);
+ else
+ kfree(dev->chunk_bits);
+ dev->chunk_bits_alt = 0;
+ dev->chunk_bits = NULL;
+}
+
+static int yaffs_init_blocks(struct yaffs_dev *dev)
+{
+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+ dev->block_info = NULL;
+ dev->chunk_bits = NULL;
+ dev->alloc_block = -1; /* force it to get a new one */
+
+ /* If the first allocation strategy fails, thry the alternate one */
+ dev->block_info =
+ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
+ if (!dev->block_info) {
+ dev->block_info =
+ vmalloc(n_blocks * sizeof(struct yaffs_block_info));
+ dev->block_info_alt = 1;
+ } else {
+ dev->block_info_alt = 0;
+ }
+
+ if (!dev->block_info)
+ goto alloc_error;
+
+ /* Set up dynamic blockinfo stuff. Round up bytes. */
+ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
+ dev->chunk_bits =
+ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
+ if (!dev->chunk_bits) {
+ dev->chunk_bits =
+ vmalloc(dev->chunk_bit_stride * n_blocks);
+ dev->chunk_bits_alt = 1;
+ } else {
+ dev->chunk_bits_alt = 0;
+ }
+ if (!dev->chunk_bits)
+ goto alloc_error;
+
+
+ memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
+ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
+ return YAFFS_OK;
+
+alloc_error:
+ yaffs_deinit_blocks(dev);
+ return YAFFS_FAIL;
+}
+
+
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
+{
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
+ int erased_ok = 0;
+ int i;
+
+ /* If the block is still healthy erase it and mark as clean.
+ * If the block has had a data failure, then retire it.
+ */
+
+ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+ "yaffs_block_became_dirty block %d state %d %s",
+ block_no, bi->block_state,
+ (bi->needs_retiring) ? "needs retiring" : "");
+
+ yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+ bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
+
+ /* If this is the block being garbage collected then stop gc'ing */
+ if (block_no == dev->gc_block)
+ dev->gc_block = 0;
+
+ /* If this block is currently the best candidate for gc
+ * then drop as a candidate */
+ if (block_no == dev->gc_dirtiest) {
+ dev->gc_dirtiest = 0;
+ dev->gc_pages_in_use = 0;
+ }
+
+ if (!bi->needs_retiring) {
+ yaffs2_checkpt_invalidate(dev);
+ erased_ok = yaffs_erase_block(dev, block_no);
+ if (!erased_ok) {
+ dev->n_erase_failures++;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Erasure failed %d", block_no);
+ }
+ }
+
+ /* Verify erasure if needed */
+ if (erased_ok &&
+ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
+ !yaffs_skip_verification(dev))) {
+ for (i = 0; i < dev->param.chunks_per_block; i++) {
+ if (!yaffs_check_chunk_erased(dev,
+ block_no * dev->param.chunks_per_block + i)) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ ">>Block %d erasure supposedly OK, but chunk %d not erased",
+ block_no, i);
+ }
+ }
+ }
+
+ if (!erased_ok) {
+ /* We lost a block of free space */
+ dev->n_free_chunks -= dev->param.chunks_per_block;
+ yaffs_retire_block(dev, block_no);
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>> Block %d retired", block_no);
+ return;
+ }
+
+ /* Clean it up... */
+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+ bi->seq_number = 0;
+ dev->n_erased_blocks++;
+ bi->pages_in_use = 0;
+ bi->soft_del_pages = 0;
+ bi->has_shrink_hdr = 0;
+ bi->skip_erased_check = 1; /* Clean, so no need to check */
+ bi->gc_prioritise = 0;
+ bi->has_summary=0;
+
+ yaffs_clear_chunk_bits(dev, block_no);
+
+ yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
+}
+
+static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi,
+ int old_chunk, u8 *buffer)
+{
+ int new_chunk;
+ int mark_flash = 1;
+ struct yaffs_ext_tags tags;
+ struct yaffs_obj *object;
+ int matching_chunk;
+ int ret_val = YAFFS_OK;
+
+ memset(&tags, 0, sizeof(tags));
+ yaffs_rd_chunk_tags_nand(dev, old_chunk,
+ buffer, &tags);
+ object = yaffs_find_by_number(dev, tags.obj_id);
+
+ yaffs_trace(YAFFS_TRACE_GC_DETAIL,
+ "Collecting chunk in block %d, %d %d %d ",
+ dev->gc_chunk, tags.obj_id,
+ tags.chunk_id, tags.n_bytes);
+
+ if (object && !yaffs_skip_verification(dev)) {
+ if (tags.chunk_id == 0)
+ matching_chunk =
+ object->hdr_chunk;
+ else if (object->soft_del)
+ /* Defeat the test */
+ matching_chunk = old_chunk;
+ else
+ matching_chunk =
+ yaffs_find_chunk_in_file
+ (object, tags.chunk_id,
+ NULL);
+
+ if (old_chunk != matching_chunk)
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "gc: page in gc mismatch: %d %d %d %d",
+ old_chunk,
+ matching_chunk,
+ tags.obj_id,
+ tags.chunk_id);
+ }
+
+ if (!object) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "page %d in gc has no object: %d %d %d ",
+ old_chunk,
+ tags.obj_id, tags.chunk_id,
+ tags.n_bytes);
+ }
+
+ if (object &&
+ object->deleted &&
+ object->soft_del && tags.chunk_id != 0) {
+ /* Data chunk in a soft deleted file,
+ * throw it away.
+ * It's a soft deleted data chunk,
+ * No need to copy this, just forget
+ * about it and fix up the object.
+ */
+
+ /* Free chunks already includes
+ * softdeleted chunks, how ever this
+ * chunk is going to soon be really
+ * deleted which will increment free
+ * chunks. We have to decrement free
+ * chunks so this works out properly.
+ */
+ dev->n_free_chunks--;
+ bi->soft_del_pages--;
+
+ object->n_data_chunks--;
+ if (object->n_data_chunks <= 0) {
+ /* remeber to clean up obj */
+ dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
+ dev->n_clean_ups++;
+ }
+ mark_flash = 0;
+ } else if (object) {
+ /* It's either a data chunk in a live
+ * file or an ObjectHeader, so we're
+ * interested in it.
+ * NB Need to keep the ObjectHeaders of
+ * deleted files until the whole file
+ * has been deleted off
+ */
+ tags.serial_number++;
+ dev->n_gc_copies++;
+
+ if (tags.chunk_id == 0) {
+ /* It is an object Id,
+ * We need to nuke the
+ * shrinkheader flags since its
+ * work is done.
+ * Also need to clean up
+ * shadowing.
+ */
+ struct yaffs_obj_hdr *oh;
+ oh = (struct yaffs_obj_hdr *) buffer;
+
+ oh->is_shrink = 0;
+ tags.extra_is_shrink = 0;
+ oh->shadows_obj = 0;
+ oh->inband_shadowed_obj_id = 0;
+ tags.extra_shadows = 0;
+
+ /* Update file size */
+ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
+ oh->file_size =
+ object->variant.file_variant.file_size;
+ tags.extra_length = oh->file_size;
+ }
+
+ yaffs_verify_oh(object, oh, &tags, 1);
+ new_chunk =
+ yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
+ } else {
+ new_chunk =
+ yaffs_write_new_chunk(dev, buffer, &tags, 1);
+ }
+
+ if (new_chunk < 0) {
+ ret_val = YAFFS_FAIL;
+ } else {
+
+ /* Now fix up the Tnodes etc. */
+
+ if (tags.chunk_id == 0) {
+ /* It's a header */
+ object->hdr_chunk = new_chunk;
+ object->serial = tags.serial_number;
+ } else {
+ /* It's a data chunk */
+ yaffs_put_chunk_in_file(object, tags.chunk_id,
+ new_chunk, 0);
+ }
+ }
+ }
+ if (ret_val == YAFFS_OK)
+ yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
+ return ret_val;
+}
+
+static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
+{
+ int old_chunk;
+ int ret_val = YAFFS_OK;
+ int i;
+ int is_checkpt_block;
+ int max_copies;
+ int chunks_before = yaffs_get_erased_chunks(dev);
+ int chunks_after;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
+
+ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
+
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "Collecting block %d, in use %d, shrink %d, whole_block %d",
+ block, bi->pages_in_use, bi->has_shrink_hdr,
+ whole_block);
+
+ /*yaffs_verify_free_chunks(dev); */
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
+ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
+
+ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
+
+ dev->gc_disable = 1;
+
+ yaffs_summary_gc(dev, block);
+
+ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "Collecting block %d that has no chunks in use",
+ block);
+ yaffs_block_became_dirty(dev, block);
+ } else {
+
+ u8 *buffer = yaffs_get_temp_buffer(dev);
+
+ yaffs_verify_blk(dev, bi, block);
+
+ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
+ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
+
+ for (/* init already done */ ;
+ ret_val == YAFFS_OK &&
+ dev->gc_chunk < dev->param.chunks_per_block &&
+ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
+ max_copies > 0;
+ dev->gc_chunk++, old_chunk++) {
+ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
+ /* Page is in use and might need to be copied */
+ max_copies--;
+ ret_val = yaffs_gc_process_chunk(dev, bi,
+ old_chunk, buffer);
+ }
+ }
+ yaffs_release_temp_buffer(dev, buffer);
+ }
+
+ yaffs_verify_collected_blk(dev, bi, block);
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+ /*
+ * The gc did not complete. Set block state back to FULL
+ * because checkpointing does not restore gc.
+ */
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ } else {
+ /* The gc completed. */
+ /* Do any required cleanups */
+ for (i = 0; i < dev->n_clean_ups; i++) {
+ /* Time to delete the file too */
+ struct yaffs_obj *object =
+ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
+ if (object) {
+ yaffs_free_tnode(dev,
+ object->variant.file_variant.top);
+ object->variant.file_variant.top = NULL;
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: About to finally delete object %d",
+ object->obj_id);
+ yaffs_generic_obj_del(object);
+ object->my_dev->n_deleted_files--;
+ }
+
+ }
+ chunks_after = yaffs_get_erased_chunks(dev);
+ if (chunks_before >= chunks_after)
+ yaffs_trace(YAFFS_TRACE_GC,
+ "gc did not increase free chunks before %d after %d",
+ chunks_before, chunks_after);
+ dev->gc_block = 0;
+ dev->gc_chunk = 0;
+ dev->n_clean_ups = 0;
+ }
+
+ dev->gc_disable = 0;
+
+ return ret_val;
+}
+
+/*
+ * find_gc_block() selects the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
+ int aggressive, int background)
+{
+ int i;
+ int iterations;
+ unsigned selected = 0;
+ int prioritised = 0;
+ int prioritised_exist = 0;
+ struct yaffs_block_info *bi;
+ int threshold;
+
+ /* First let's see if we need to grab a prioritised block */
+ if (dev->has_pending_prioritised_gc && !aggressive) {
+ dev->gc_dirtiest = 0;
+ bi = dev->block_info;
+ for (i = dev->internal_start_block;
+ i <= dev->internal_end_block && !selected; i++) {
+
+ if (bi->gc_prioritise) {
+ prioritised_exist = 1;
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+ yaffs_block_ok_for_gc(dev, bi)) {
+ selected = i;
+ prioritised = 1;
+ }
+ }
+ bi++;
+ }
+
+ /*
+ * If there is a prioritised block and none was selected then
+ * this happened because there is at least one old dirty block
+ * gumming up the works. Let's gc the oldest dirty block.
+ */
+
+ if (prioritised_exist &&
+ !selected && dev->oldest_dirty_block > 0)
+ selected = dev->oldest_dirty_block;
+
+ if (!prioritised_exist) /* None found, so we can clear this */
+ dev->has_pending_prioritised_gc = 0;
+ }
+
+ /* If we're doing aggressive GC then we are happy to take a less-dirty
+ * block, and search harder.
+ * else (leasurely gc), then we only bother to do this if the
+ * block has only a few pages in use.
+ */
+
+ if (!selected) {
+ int pages_used;
+ int n_blocks =
+ dev->internal_end_block - dev->internal_start_block + 1;
+ if (aggressive) {
+ threshold = dev->param.chunks_per_block;
+ iterations = n_blocks;
+ } else {
+ int max_threshold;
+
+ if (background)
+ max_threshold = dev->param.chunks_per_block / 2;
+ else
+ max_threshold = dev->param.chunks_per_block / 8;
+
+ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
+ threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
+ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+ if (threshold > max_threshold)
+ threshold = max_threshold;
+
+ iterations = n_blocks / 16 + 1;
+ if (iterations > 100)
+ iterations = 100;
+ }
+
+ for (i = 0;
+ i < iterations &&
+ (dev->gc_dirtiest < 1 ||
+ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
+ i++) {
+ dev->gc_block_finder++;
+ if (dev->gc_block_finder < dev->internal_start_block ||
+ dev->gc_block_finder > dev->internal_end_block)
+ dev->gc_block_finder =
+ dev->internal_start_block;
+
+ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
+
+ pages_used = bi->pages_in_use - bi->soft_del_pages;
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+ pages_used < dev->param.chunks_per_block &&
+ (dev->gc_dirtiest < 1 ||
+ pages_used < dev->gc_pages_in_use) &&
+ yaffs_block_ok_for_gc(dev, bi)) {
+ dev->gc_dirtiest = dev->gc_block_finder;
+ dev->gc_pages_in_use = pages_used;
+ }
+ }
+
+ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
+ selected = dev->gc_dirtiest;
+ }
+
+ /*
+ * If nothing has been selected for a while, try the oldest dirty
+ * because that's gumming up the works.
+ */
+
+ if (!selected && dev->param.is_yaffs2 &&
+ dev->gc_not_done >= (background ? 10 : 20)) {
+ yaffs2_find_oldest_dirty_seq(dev);
+ if (dev->oldest_dirty_block > 0) {
+ selected = dev->oldest_dirty_block;
+ dev->gc_dirtiest = selected;
+ dev->oldest_dirty_gc_count++;
+ bi = yaffs_get_block_info(dev, selected);
+ dev->gc_pages_in_use =
+ bi->pages_in_use - bi->soft_del_pages;
+ } else {
+ dev->gc_not_done = 0;
+ }
+ }
+
+ if (selected) {
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC Selected block %d with %d free, prioritised:%d",
+ selected,
+ dev->param.chunks_per_block - dev->gc_pages_in_use,
+ prioritised);
+
+ dev->n_gc_blocks++;
+ if (background)
+ dev->bg_gcs++;
+
+ dev->gc_dirtiest = 0;
+ dev->gc_pages_in_use = 0;
+ dev->gc_not_done = 0;
+ if (dev->refresh_skip > 0)
+ dev->refresh_skip--;
+ } else {
+ dev->gc_not_done++;
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
+ dev->gc_block_finder, dev->gc_not_done, threshold,
+ dev->gc_dirtiest, dev->gc_pages_in_use,
+ dev->oldest_dirty_block, background ? " bg" : "");
+ }
+
+ return selected;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_check_gc(struct yaffs_dev *dev, int background)
+{
+ int aggressive = 0;
+ int gc_ok = YAFFS_OK;
+ int max_tries = 0;
+ int min_erased;
+ int erased_chunks;
+ int checkpt_block_adjust;
+
+ if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
+ return YAFFS_OK;
+
+ if (dev->gc_disable)
+ /* Bail out so we don't get recursive gc */
+ return YAFFS_OK;
+
+ /* This loop should pass the first time.
+ * Only loops here if the collection does not increase space.
+ */
+
+ do {
+ max_tries++;
+
+ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
+
+ min_erased =
+ dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
+ erased_chunks =
+ dev->n_erased_blocks * dev->param.chunks_per_block;
+
+ /* If we need a block soon then do aggressive gc. */
+ if (dev->n_erased_blocks < min_erased)
+ aggressive = 1;
+ else {
+ if (!background
+ && erased_chunks > (dev->n_free_chunks / 4))
+ break;
+
+ if (dev->gc_skip > 20)
+ dev->gc_skip = 20;
+ if (erased_chunks < dev->n_free_chunks / 2 ||
+ dev->gc_skip < 1 || background)
+ aggressive = 0;
+ else {
+ dev->gc_skip--;
+ break;
+ }
+ }
+
+ dev->gc_skip = 5;
+
+ /* If we don't already have a block being gc'd then see if we
+ * should start another */
+
+ if (dev->gc_block < 1 && !aggressive) {
+ dev->gc_block = yaffs2_find_refresh_block(dev);
+ dev->gc_chunk = 0;
+ dev->n_clean_ups = 0;
+ }
+ if (dev->gc_block < 1) {
+ dev->gc_block =
+ yaffs_find_gc_block(dev, aggressive, background);
+ dev->gc_chunk = 0;
+ dev->n_clean_ups = 0;
+ }
+
+ if (dev->gc_block > 0) {
+ dev->all_gcs++;
+ if (!aggressive)
+ dev->passive_gc_count++;
+
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: GC n_erased_blocks %d aggressive %d",
+ dev->n_erased_blocks, aggressive);
+
+ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
+ }
+
+ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
+ dev->gc_block > 0) {
+ yaffs_trace(YAFFS_TRACE_GC,
+ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
+ dev->n_erased_blocks, max_tries,
+ dev->gc_block);
+ }
+ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
+ (dev->gc_block > 0) && (max_tries < 2));
+
+ return aggressive ? gc_ok : YAFFS_OK;
+}
+
+/*
+ * yaffs_bg_gc()
+ * Garbage collects. Intended to be called from a background thread.
+ * Returns non-zero if at least half the free chunks are erased.
+ */
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
+{
+ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
+
+ yaffs_check_gc(dev, 1);
+ return erased_chunks > dev->n_free_chunks / 2;
+}
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
+{
+ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
+
+ if (nand_chunk >= 0)
+ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
+ buffer, NULL);
+ else {
+ yaffs_trace(YAFFS_TRACE_NANDACCESS,
+ "Chunk %d not found zero instead",
+ nand_chunk);
+ /* get sane (zero) data if you read a hole */
+ memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
+ return 0;
+ }
+
+}
+
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+ int lyn)
+{
+ int block;
+ int page;
+ struct yaffs_ext_tags tags;
+ struct yaffs_block_info *bi;
+
+ if (chunk_id <= 0)
+ return;
+
+ dev->n_deletions++;
+ block = chunk_id / dev->param.chunks_per_block;
+ page = chunk_id % dev->param.chunks_per_block;
+
+ if (!yaffs_check_chunk_bit(dev, block, page))
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Deleting invalid chunk %d", chunk_id);
+
+ bi = yaffs_get_block_info(dev, block);
+
+ yaffs2_update_oldest_dirty_seq(dev, block, bi);
+
+ yaffs_trace(YAFFS_TRACE_DELETION,
+ "line %d delete of chunk %d",
+ lyn, chunk_id);
+
+ if (!dev->param.is_yaffs2 && mark_flash &&
+ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
+
+ memset(&tags, 0, sizeof(tags));
+ tags.is_deleted = 1;
+ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
+ yaffs_handle_chunk_update(dev, chunk_id, &tags);
+ } else {
+ dev->n_unmarked_deletions++;
+ }
+
+ /* Pull out of the management area.
+ * If the whole block became dirty, this will kick off an erasure.
+ */
+ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
+ bi->block_state == YAFFS_BLOCK_STATE_FULL ||
+ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+ dev->n_free_chunks++;
+ yaffs_clear_chunk_bit(dev, block, page);
+ bi->pages_in_use--;
+
+ if (bi->pages_in_use == 0 &&
+ !bi->has_shrink_hdr &&
+ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
+ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ yaffs_block_became_dirty(dev, block);
+ }
+ }
+}
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+ const u8 *buffer, int n_bytes, int use_reserve)
+{
+ /* Find old chunk Need to do this to get serial number
+ * Write new one and patch into tree.
+ * Invalidate old tags.
+ */
+
+ int prev_chunk_id;
+ struct yaffs_ext_tags prev_tags;
+ int new_chunk_id;
+ struct yaffs_ext_tags new_tags;
+ struct yaffs_dev *dev = in->my_dev;
+
+ yaffs_check_gc(dev, 0);
+
+ /* Get the previous chunk at this location in the file if it exists.
+ * If it does not exist then put a zero into the tree. This creates
+ * the tnode now, rather than later when it is harder to clean up.
+ */
+ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
+ if (prev_chunk_id < 1 &&
+ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
+ return 0;
+
+ /* Set up new tags */
+ memset(&new_tags, 0, sizeof(new_tags));
+
+ new_tags.chunk_id = inode_chunk;
+ new_tags.obj_id = in->obj_id;
+ new_tags.serial_number =
+ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
+ new_tags.n_bytes = n_bytes;
+
+ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Writing %d bytes to chunk!!!!!!!!!",
+ n_bytes);
+ BUG();
+ }
+
+ new_chunk_id =
+ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
+
+ if (new_chunk_id > 0) {
+ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
+
+ if (prev_chunk_id > 0)
+ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+ yaffs_verify_file_sane(in);
+ }
+ return new_chunk_id;
+
+}
+
+
+
+static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
+ const YCHAR *name, const void *value, int size,
+ int flags)
+{
+ struct yaffs_xattr_mod xmod;
+ int result;
+
+ xmod.set = set;
+ xmod.name = name;
+ xmod.data = value;
+ xmod.size = size;
+ xmod.flags = flags;
+ xmod.result = -ENOSPC;
+
+ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
+
+ if (result > 0)
+ return xmod.result;
+ else
+ return -ENOSPC;
+}
+
+static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
+ struct yaffs_xattr_mod *xmod)
+{
+ int retval = 0;
+ int x_offs = sizeof(struct yaffs_obj_hdr);
+ struct yaffs_dev *dev = obj->my_dev;
+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+ char *x_buffer = buffer + x_offs;
+
+ if (xmod->set)
+ retval =
+ nval_set(x_buffer, x_size, xmod->name, xmod->data,
+ xmod->size, xmod->flags);
+ else
+ retval = nval_del(x_buffer, x_size, xmod->name);
+
+ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattr_known = 1;
+ xmod->result = retval;
+
+ return retval;
+}
+
+static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
+ void *value, int size)
+{
+ char *buffer = NULL;
+ int result;
+ struct yaffs_ext_tags tags;
+ struct yaffs_dev *dev = obj->my_dev;
+ int x_offs = sizeof(struct yaffs_obj_hdr);
+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+ char *x_buffer;
+ int retval = 0;
+
+ if (obj->hdr_chunk < 1)
+ return -ENODATA;
+
+ /* If we know that the object has no xattribs then don't do all the
+ * reading and parsing.
+ */
+ if (obj->xattr_known && !obj->has_xattr) {
+ if (name)
+ return -ENODATA;
+ else
+ return 0;
+ }
+
+ buffer = (char *)yaffs_get_temp_buffer(dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ result =
+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
+
+ if (result != YAFFS_OK)
+ retval = -ENOENT;
+ else {
+ x_buffer = buffer + x_offs;
+
+ if (!obj->xattr_known) {
+ obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattr_known = 1;
+ }
+
+ if (name)
+ retval = nval_get(x_buffer, x_size, name, value, size);
+ else
+ retval = nval_list(x_buffer, x_size, value, size);
+ }
+ yaffs_release_temp_buffer(dev, (u8 *) buffer);
+ return retval;
+}
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
+ const void *value, int size, int flags)
+{
+ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
+}
+
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
+{
+ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
+}
+
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
+ int size)
+{
+ return yaffs_do_xattrib_fetch(obj, name, value, size);
+}
+
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
+{
+ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
+}
+
+static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
+{
+ u8 *buf;
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_dev *dev;
+ struct yaffs_ext_tags tags;
+ int result;
+ int alloc_failed = 0;
+
+ if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
+ return;
+
+ dev = in->my_dev;
+ in->lazy_loaded = 0;
+ buf = yaffs_get_temp_buffer(dev);
+
+ result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
+ oh = (struct yaffs_obj_hdr *)buf;
+
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ yaffs_set_obj_name_from_oh(in, oh);
+
+ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ in->variant.symlink_variant.alias =
+ yaffs_clone_str(oh->alias);
+ if (!in->variant.symlink_variant.alias)
+ alloc_failed = 1; /* Not returned */
+ }
+ yaffs_release_temp_buffer(dev, buf);
+}
+
+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
+ const YCHAR *oh_name, int buff_size)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ if (dev->param.auto_unicode) {
+ if (*oh_name) {
+ /* It is an ASCII name, do an ASCII to
+ * unicode conversion */
+ const char *ascii_oh_name = (const char *)oh_name;
+ int n = buff_size - 1;
+ while (n > 0 && *ascii_oh_name) {
+ *name = *ascii_oh_name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ strncpy(name, oh_name + 1, buff_size - 1);
+ }
+ } else {
+#else
+ {
+#endif
+ strncpy(name, oh_name, buff_size - 1);
+ }
+}
+
+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
+ const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+ int is_ascii;
+ YCHAR *w;
+
+ if (dev->param.auto_unicode) {
+
+ is_ascii = 1;
+ w = name;
+
+ /* Figure out if the name will fit in ascii character set */
+ while (is_ascii && *w) {
+ if ((*w) & 0xff00)
+ is_ascii = 0;
+ w++;
+ }
+
+ if (is_ascii) {
+ /* It is an ASCII name, so convert unicode to ascii */
+ char *ascii_oh_name = (char *)oh_name;
+ int n = YAFFS_MAX_NAME_LENGTH - 1;
+ while (n > 0 && *name) {
+ *ascii_oh_name = *name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ /* Unicode name, so save starting at the second YCHAR */
+ *oh_name = 0;
+ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
+ }
+ } else {
+#else
+ {
+#endif
+ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
+ }
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
+ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
+{
+
+ struct yaffs_block_info *bi;
+ struct yaffs_dev *dev = in->my_dev;
+ int prev_chunk_id;
+ int ret_val = 0;
+ int result = 0;
+ int new_chunk_id;
+ struct yaffs_ext_tags new_tags;
+ struct yaffs_ext_tags old_tags;
+ const YCHAR *alias = NULL;
+ u8 *buffer = NULL;
+ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
+ struct yaffs_obj_hdr *oh = NULL;
+
+ strcpy(old_name, _Y("silly old name"));
+
+ if (in->fake && in != dev->root_dir && !force && !xmod)
+ return ret_val;
+
+ yaffs_check_gc(dev, 0);
+ yaffs_check_obj_details_loaded(in);
+
+ buffer = yaffs_get_temp_buffer(in->my_dev);
+ oh = (struct yaffs_obj_hdr *)buffer;
+
+ prev_chunk_id = in->hdr_chunk;
+
+ if (prev_chunk_id > 0) {
+ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
+ buffer, &old_tags);
+
+ yaffs_verify_oh(in, oh, &old_tags, 0);
+ memcpy(old_name, oh->name, sizeof(oh->name));
+ memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+ } else {
+ memset(buffer, 0xff, dev->data_bytes_per_chunk);
+ }
+
+ oh->type = in->variant_type;
+ oh->yst_mode = in->yst_mode;
+ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
+
+ yaffs_load_attribs_oh(oh, in);
+
+ if (in->parent)
+ oh->parent_obj_id = in->parent->obj_id;
+ else
+ oh->parent_obj_id = 0;
+
+ if (name && *name) {
+ memset(oh->name, 0, sizeof(oh->name));
+ yaffs_load_oh_from_name(dev, oh->name, name);
+ } else if (prev_chunk_id > 0) {
+ memcpy(oh->name, old_name, sizeof(oh->name));
+ } else {
+ memset(oh->name, 0, sizeof(oh->name));
+ }
+
+ oh->is_shrink = is_shrink;
+
+ switch (in->variant_type) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Should not happen */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ oh->file_size =
+ (oh->parent_obj_id == YAFFS_OBJECTID_DELETED ||
+ oh->parent_obj_id == YAFFS_OBJECTID_UNLINKED) ?
+ 0 : in->variant.file_variant.file_size;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ oh->equiv_id = in->variant.hardlink_variant.equiv_id;
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ alias = in->variant.symlink_variant.alias;
+ if (!alias)
+ alias = _Y("no alias");
+ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
+ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+ break;
+ }
+
+ /* process any xattrib modifications */
+ if (xmod)
+ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
+
+ /* Tags */
+ memset(&new_tags, 0, sizeof(new_tags));
+ in->serial++;
+ new_tags.chunk_id = 0;
+ new_tags.obj_id = in->obj_id;
+ new_tags.serial_number = in->serial;
+
+ /* Add extra info for file header */
+ new_tags.extra_available = 1;
+ new_tags.extra_parent_id = oh->parent_obj_id;
+ new_tags.extra_length = oh->file_size;
+ new_tags.extra_is_shrink = oh->is_shrink;
+ new_tags.extra_equiv_id = oh->equiv_id;
+ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
+ new_tags.extra_obj_type = in->variant_type;
+ yaffs_verify_oh(in, oh, &new_tags, 1);
+
+ /* Create new chunk in NAND */
+ new_chunk_id =
+ yaffs_write_new_chunk(dev, buffer, &new_tags,
+ (prev_chunk_id > 0) ? 1 : 0);
+
+ if (buffer)
+ yaffs_release_temp_buffer(dev, buffer);
+
+ if (new_chunk_id < 0)
+ return new_chunk_id;
+
+ in->hdr_chunk = new_chunk_id;
+
+ if (prev_chunk_id > 0)
+ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+ if (!yaffs_obj_cache_dirty(in))
+ in->dirty = 0;
+
+ /* If this was a shrink, then mark the block
+ * that the chunk lives on */
+ if (is_shrink) {
+ bi = yaffs_get_block_info(in->my_dev,
+ new_chunk_id /
+ in->my_dev->param.chunks_per_block);
+ bi->has_shrink_hdr = 1;
+ }
+
+
+ return new_chunk_id;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
+{
+ int chunk;
+ u32 start;
+ int n_copy;
+ int n = n_bytes;
+ int n_done = 0;
+ struct yaffs_cache *cache;
+ struct yaffs_dev *dev;
+
+ dev = in->my_dev;
+
+ while (n > 0) {
+ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+ chunk++;
+
+ /* OK now check for the curveball where the start and end are in
+ * the same chunk.
+ */
+ if ((start + n) < dev->data_bytes_per_chunk)
+ n_copy = n;
+ else
+ n_copy = dev->data_bytes_per_chunk - start;
+
+ cache = yaffs_find_chunk_cache(in, chunk);
+
+ /* If the chunk is already in the cache or it is less than
+ * a whole chunk or we're using inband tags then use the cache
+ * (if there is caching) else bypass the cache.
+ */
+ if (cache || n_copy != dev->data_bytes_per_chunk ||
+ dev->param.inband_tags) {
+ if (dev->param.n_caches > 0) {
+
+ /* If we can't find the data in the cache,
+ * then load it up. */
+
+ if (!cache) {
+ cache =
+ yaffs_grab_chunk_cache(in->my_dev);
+ cache->object = in;
+ cache->chunk_id = chunk;
+ cache->dirty = 0;
+ cache->locked = 0;
+ yaffs_rd_data_obj(in, chunk,
+ cache->data);
+ cache->n_bytes = 0;
+ }
+
+ yaffs_use_cache(dev, cache, 0);
+
+ cache->locked = 1;
+
+ memcpy(buffer, &cache->data[start], n_copy);
+
+ cache->locked = 0;
+ } else {
+ /* Read into the local buffer then copy.. */
+
+ u8 *local_buffer =
+ yaffs_get_temp_buffer(dev);
+ yaffs_rd_data_obj(in, chunk, local_buffer);
+
+ memcpy(buffer, &local_buffer[start], n_copy);
+
+ yaffs_release_temp_buffer(dev, local_buffer);
+ }
+ } else {
+ /* A full chunk. Read directly into the buffer. */
+ yaffs_rd_data_obj(in, chunk, buffer);
+ }
+ n -= n_copy;
+ offset += n_copy;
+ buffer += n_copy;
+ n_done += n_copy;
+ }
+ return n_done;
+}
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_trhrough)
+{
+
+ int chunk;
+ u32 start;
+ int n_copy;
+ int n = n_bytes;
+ int n_done = 0;
+ int n_writeback;
+ int start_write = offset;
+ int chunk_written = 0;
+ u32 n_bytes_read;
+ u32 chunk_start;
+ struct yaffs_dev *dev;
+
+ dev = in->my_dev;
+
+ while (n > 0 && chunk_written >= 0) {
+ yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+
+ if (chunk * dev->data_bytes_per_chunk + start != offset ||
+ start >= dev->data_bytes_per_chunk) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "AddrToChunk of offset %d gives chunk %d start %d",
+ (int)offset, chunk, start);
+ }
+ chunk++; /* File pos to chunk in file offset */
+
+ /* OK now check for the curveball where the start and end are in
+ * the same chunk.
+ */
+
+ if ((start + n) < dev->data_bytes_per_chunk) {
+ n_copy = n;
+
+ /* Now calculate how many bytes to write back....
+ * If we're overwriting and not writing to then end of
+ * file then we need to write back as much as was there
+ * before.
+ */
+
+ chunk_start = ((chunk - 1) * dev->data_bytes_per_chunk);
+
+ if (chunk_start > in->variant.file_variant.file_size)
+ n_bytes_read = 0; /* Past end of file */
+ else
+ n_bytes_read =
+ in->variant.file_variant.file_size -
+ chunk_start;
+
+ if (n_bytes_read > dev->data_bytes_per_chunk)
+ n_bytes_read = dev->data_bytes_per_chunk;
+
+ n_writeback =
+ (n_bytes_read >
+ (start + n)) ? n_bytes_read : (start + n);
+
+ if (n_writeback < 0 ||
+ n_writeback > dev->data_bytes_per_chunk)
+ BUG();
+
+ } else {
+ n_copy = dev->data_bytes_per_chunk - start;
+ n_writeback = dev->data_bytes_per_chunk;
+ }
+
+ if (n_copy != dev->data_bytes_per_chunk ||
+ dev->param.inband_tags) {
+ /* An incomplete start or end chunk (or maybe both
+ * start and end chunk), or we're using inband tags,
+ * so we want to use the cache buffers.
+ */
+ if (dev->param.n_caches > 0) {
+ struct yaffs_cache *cache;
+
+ /* If we can't find the data in the cache, then
+ * load the cache */
+ cache = yaffs_find_chunk_cache(in, chunk);
+
+ if (!cache &&
+ yaffs_check_alloc_available(dev, 1)) {
+ cache = yaffs_grab_chunk_cache(dev);
+ cache->object = in;
+ cache->chunk_id = chunk;
+ cache->dirty = 0;
+ cache->locked = 0;
+ yaffs_rd_data_obj(in, chunk,
+ cache->data);
+ } else if (cache &&
+ !cache->dirty &&
+ !yaffs_check_alloc_available(dev,
+ 1)) {
+ /* Drop the cache if it was a read cache
+ * item and no space check has been made
+ * for it.
+ */
+ cache = NULL;
+ }
+
+ if (cache) {
+ yaffs_use_cache(dev, cache, 1);
+ cache->locked = 1;
+
+ memcpy(&cache->data[start], buffer,
+ n_copy);
+
+ cache->locked = 0;
+ cache->n_bytes = n_writeback;
+
+ if (write_trhrough) {
+ chunk_written =
+ yaffs_wr_data_obj
+ (cache->object,
+ cache->chunk_id,
+ cache->data,
+ cache->n_bytes, 1);
+ cache->dirty = 0;
+ }
+ } else {
+ chunk_written = -1; /* fail write */
+ }
+ } else {
+ /* An incomplete start or end chunk (or maybe
+ * both start and end chunk). Read into the
+ * local buffer then copy over and write back.
+ */
+
+ u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+ yaffs_rd_data_obj(in, chunk, local_buffer);
+ memcpy(&local_buffer[start], buffer, n_copy);
+
+ chunk_written =
+ yaffs_wr_data_obj(in, chunk,
+ local_buffer,
+ n_writeback, 0);
+
+ yaffs_release_temp_buffer(dev, local_buffer);
+ }
+ } else {
+ /* A full chunk. Write directly from the buffer. */
+
+ chunk_written =
+ yaffs_wr_data_obj(in, chunk, buffer,
+ dev->data_bytes_per_chunk, 0);
+
+ /* Since we've overwritten the cached data,
+ * we better invalidate it. */
+ yaffs_invalidate_chunk_cache(in, chunk);
+ }
+
+ if (chunk_written >= 0) {
+ n -= n_copy;
+ offset += n_copy;
+ buffer += n_copy;
+ n_done += n_copy;
+ }
+ }
+
+ /* Update file object */
+
+ if ((start_write + n_done) > in->variant.file_variant.file_size)
+ in->variant.file_variant.file_size = (start_write + n_done);
+
+ in->dirty = 1;
+ return n_done;
+}
+
+int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_trhrough)
+{
+ yaffs2_handle_hole(in, offset);
+ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_trhrough);
+}
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_prune_chunks(struct yaffs_obj *in, int new_size)
+{
+
+ struct yaffs_dev *dev = in->my_dev;
+ int old_size = in->variant.file_variant.file_size;
+ int i;
+ int chunk_id;
+ int last_del = 1 + (old_size - 1) / dev->data_bytes_per_chunk;
+ int start_del = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
+ dev->data_bytes_per_chunk;
+
+
+ /* Delete backwards so that we don't end up with holes if
+ * power is lost part-way through the operation.
+ */
+ for (i = last_del; i >= start_del; i--) {
+ /* NB this could be optimised somewhat,
+ * eg. could retrieve the tags and write them without
+ * using yaffs_chunk_del
+ */
+
+ chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
+
+ if (chunk_id < 1)
+ continue;
+
+ if (chunk_id <
+ (dev->internal_start_block * dev->param.chunks_per_block) ||
+ chunk_id >=
+ ((dev->internal_end_block + 1) *
+ dev->param.chunks_per_block)) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Found daft chunk_id %d for %d",
+ chunk_id, i);
+ } else {
+ in->n_data_chunks--;
+ yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
+ }
+ }
+}
+
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
+{
+ int new_full;
+ u32 new_partial;
+ struct yaffs_dev *dev = obj->my_dev;
+
+ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
+
+ yaffs_prune_chunks(obj, new_size);
+
+ if (new_partial != 0) {
+ int last_chunk = 1 + new_full;
+ u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+ /* Rewrite the last chunk with its new size and zero pad */
+ yaffs_rd_data_obj(obj, last_chunk, local_buffer);
+ memset(local_buffer + new_partial, 0,
+ dev->data_bytes_per_chunk - new_partial);
+
+ yaffs_wr_data_obj(obj, last_chunk, local_buffer,
+ new_partial, 1);
+
+ yaffs_release_temp_buffer(dev, local_buffer);
+ }
+
+ obj->variant.file_variant.file_size = new_size;
+
+ yaffs_prune_tree(dev, &obj->variant.file_variant);
+}
+
+int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
+{
+ struct yaffs_dev *dev = in->my_dev;
+ int old_size = in->variant.file_variant.file_size;
+
+ yaffs_flush_file_cache(in);
+ yaffs_invalidate_whole_cache(in);
+
+ yaffs_check_gc(dev, 0);
+
+ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ if (new_size == old_size)
+ return YAFFS_OK;
+
+ if (new_size > old_size) {
+ yaffs2_handle_hole(in, new_size);
+ in->variant.file_variant.file_size = new_size;
+ } else {
+ /* new_size < old_size */
+ yaffs_resize_file_down(in, new_size);
+ }
+
+ /* Write a new object header to reflect the resize.
+ * show we've shrunk the file, if need be
+ * Do this only if the file is not in the deleted directories
+ * and is not shadowed.
+ */
+ if (in->parent &&
+ !in->is_shadowed &&
+ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+ in->parent->obj_id != YAFFS_OBJECTID_DELETED)
+ yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
+
+ return YAFFS_OK;
+}
+
+int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
+{
+ if (!in->dirty)
+ return YAFFS_OK;
+
+ yaffs_flush_file_cache(in);
+
+ if (data_sync)
+ return YAFFS_OK;
+
+ if (update_time)
+ yaffs_load_current_time(in, 0, 0);
+
+ return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
+ YAFFS_OK : YAFFS_FAIL;
+}
+
+
+/* yaffs_del_file deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
+{
+ int ret_val;
+ int del_now = 0;
+ struct yaffs_dev *dev = in->my_dev;
+
+ if (!in->my_inode)
+ del_now = 1;
+
+ if (del_now) {
+ ret_val =
+ yaffs_change_obj_name(in, in->my_dev->del_dir,
+ _Y("deleted"), 0, 0);
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: immediate deletion of file %d",
+ in->obj_id);
+ in->deleted = 1;
+ in->my_dev->n_deleted_files++;
+ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+ yaffs_resize_file(in, 0);
+ yaffs_soft_del_file(in);
+ } else {
+ ret_val =
+ yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
+ _Y("unlinked"), 0, 0);
+ }
+ return ret_val;
+}
+
+int yaffs_del_file(struct yaffs_obj *in)
+{
+ int ret_val = YAFFS_OK;
+ int deleted; /* Need to cache value on stack if in is freed */
+ struct yaffs_dev *dev = in->my_dev;
+
+ if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+ yaffs_resize_file(in, 0);
+
+ if (in->n_data_chunks > 0) {
+ /* Use soft deletion if there is data in the file.
+ * That won't be the case if it has been resized to zero.
+ */
+ if (!in->unlinked)
+ ret_val = yaffs_unlink_file_if_needed(in);
+
+ deleted = in->deleted;
+
+ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
+ in->deleted = 1;
+ deleted = 1;
+ in->my_dev->n_deleted_files++;
+ yaffs_soft_del_file(in);
+ }
+ return deleted ? YAFFS_OK : YAFFS_FAIL;
+ } else {
+ /* The file has no data chunks so we toss it immediately */
+ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
+ in->variant.file_variant.top = NULL;
+ yaffs_generic_obj_del(in);
+
+ return YAFFS_OK;
+ }
+}
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
+{
+ return (obj &&
+ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+ !(list_empty(&obj->variant.dir_variant.children));
+}
+
+static int yaffs_del_dir(struct yaffs_obj *obj)
+{
+ /* First check that the directory is empty. */
+ if (yaffs_is_non_empty_dir(obj))
+ return YAFFS_FAIL;
+
+ return yaffs_generic_obj_del(obj);
+}
+
+static int yaffs_del_symlink(struct yaffs_obj *in)
+{
+ kfree(in->variant.symlink_variant.alias);
+ in->variant.symlink_variant.alias = NULL;
+
+ return yaffs_generic_obj_del(in);
+}
+
+static int yaffs_del_link(struct yaffs_obj *in)
+{
+ /* remove this hardlink from the list associated with the equivalent
+ * object
+ */
+ list_del_init(&in->hard_links);
+ return yaffs_generic_obj_del(in);
+}
+
+int yaffs_del_obj(struct yaffs_obj *obj)
+{
+ int ret_val = -1;
+
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ ret_val = yaffs_del_file(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ if (!list_empty(&obj->variant.dir_variant.dirty)) {
+ yaffs_trace(YAFFS_TRACE_BACKGROUND,
+ "Remove object %d from dirty directories",
+ obj->obj_id);
+ list_del_init(&obj->variant.dir_variant.dirty);
+ }
+ return yaffs_del_dir(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ ret_val = yaffs_del_symlink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ ret_val = yaffs_del_link(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ ret_val = yaffs_generic_obj_del(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ ret_val = 0;
+ break; /* should not happen. */
+ }
+ return ret_val;
+}
+
+static int yaffs_unlink_worker(struct yaffs_obj *obj)
+{
+ int del_now = 0;
+
+ if (!obj)
+ return YAFFS_FAIL;
+
+ if (!obj->my_inode)
+ del_now = 1;
+
+ yaffs_update_parent(obj->parent);
+
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+ return yaffs_del_link(obj);
+ } else if (!list_empty(&obj->hard_links)) {
+ /* Curve ball: We're unlinking an object that has a hardlink.
+ *
+ * This problem arises because we are not strictly following
+ * The Linux link/inode model.
+ *
+ * We can't really delete the object.
+ * Instead, we do the following:
+ * - Select a hardlink.
+ * - Unhook it from the hard links
+ * - Move it from its parent directory so that the rename works.
+ * - Rename the object to the hardlink's name.
+ * - Delete the hardlink
+ */
+
+ struct yaffs_obj *hl;
+ struct yaffs_obj *parent;
+ int ret_val;
+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ hl = list_entry(obj->hard_links.next, struct yaffs_obj,
+ hard_links);
+
+ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+ parent = hl->parent;
+
+ list_del_init(&hl->hard_links);
+
+ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
+
+ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
+
+ if (ret_val == YAFFS_OK)
+ ret_val = yaffs_generic_obj_del(hl);
+
+ return ret_val;
+
+ } else if (del_now) {
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return yaffs_del_file(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ list_del_init(&obj->variant.dir_variant.dirty);
+ return yaffs_del_dir(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ return yaffs_del_symlink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ return yaffs_generic_obj_del(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ default:
+ return YAFFS_FAIL;
+ }
+ } else if (yaffs_is_non_empty_dir(obj)) {
+ return YAFFS_FAIL;
+ } else {
+ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
+ _Y("unlinked"), 0, 0);
+ }
+}
+
+static int yaffs_unlink_obj(struct yaffs_obj *obj)
+{
+ if (obj && obj->unlink_allowed)
+ return yaffs_unlink_worker(obj);
+
+ return YAFFS_FAIL;
+}
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
+{
+ struct yaffs_obj *obj;
+
+ obj = yaffs_find_by_name(dir, name);
+ return yaffs_unlink_obj(obj);
+}
+
+/* Note:
+ * If old_name is NULL then we take old_dir as the object to be renamed.
+ */
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
+ struct yaffs_obj *new_dir, const YCHAR *new_name)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *existing_target = NULL;
+ int force = 0;
+ int result;
+ struct yaffs_dev *dev;
+
+ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ BUG();
+ return YAFFS_FAIL;
+ }
+
+ dev = old_dir->my_dev;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+ /* Special case for case insemsitive systems.
+ * While look-up is case insensitive, the name isn't.
+ * Therefore we might want to change x.txt to X.txt
+ */
+ if (old_dir == new_dir &&
+ old_name && new_name &&
+ strcmp(old_name, new_name) == 0)
+ force = 1;
+#endif
+
+ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
+ YAFFS_MAX_NAME_LENGTH)
+ /* ENAMETOOLONG */
+ return YAFFS_FAIL;
+
+ if (old_name)
+ obj = yaffs_find_by_name(old_dir, old_name);
+ else{
+ obj = old_dir;
+ old_dir = obj->parent;
+ }
+
+ if (obj && obj->rename_allowed) {
+ /* Now handle an existing target, if there is one */
+ existing_target = yaffs_find_by_name(new_dir, new_name);
+ if (yaffs_is_non_empty_dir(existing_target)) {
+ return YAFFS_FAIL; /* ENOTEMPTY */
+ } else if (existing_target && existing_target != obj) {
+ /* Nuke the target first, using shadowing,
+ * but only if it isn't the same object.
+ *
+ * Note we must disable gc here otherwise it can mess
+ * up the shadowing.
+ *
+ */
+ dev->gc_disable = 1;
+ yaffs_change_obj_name(obj, new_dir, new_name, force,
+ existing_target->obj_id);
+ existing_target->is_shadowed = 1;
+ yaffs_unlink_obj(existing_target);
+ dev->gc_disable = 0;
+ }
+
+ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
+
+ yaffs_update_parent(old_dir);
+ if (new_dir != old_dir)
+ yaffs_update_parent(new_dir);
+
+ return result;
+ }
+ return YAFFS_FAIL;
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+ int backward_scanning)
+{
+ struct yaffs_obj *obj;
+
+ if (backward_scanning) {
+ /* Handle YAFFS2 case (backward scanning)
+ * If the shadowed object exists then ignore.
+ */
+ obj = yaffs_find_by_number(dev, obj_id);
+ if (obj)
+ return;
+ }
+
+ /* Let's create it (if it does not exist) assuming it is a file so that
+ * it can do shrinking etc.
+ * We put it in unlinked dir to be cleaned up after the scanning
+ */
+ obj =
+ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
+ if (!obj)
+ return;
+ obj->is_shadowed = 1;
+ yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
+ obj->variant.file_variant.shrink_size = 0;
+ obj->valid = 1; /* So that we don't read any other info. */
+}
+
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
+{
+ struct list_head *lh;
+ struct list_head *save;
+ struct yaffs_obj *hl;
+ struct yaffs_obj *in;
+
+ list_for_each_safe(lh, save, hard_list) {
+ hl = list_entry(lh, struct yaffs_obj, hard_links);
+ in = yaffs_find_by_number(dev,
+ hl->variant.hardlink_variant.equiv_id);
+
+ if (in) {
+ /* Add the hardlink pointers */
+ hl->variant.hardlink_variant.equiv_obj = in;
+ list_add(&hl->hard_links, &in->hard_links);
+ } else {
+ /* Todo Need to report/handle this better.
+ * Got a problem... hardlink to a non-existant object
+ */
+ hl->variant.hardlink_variant.equiv_obj = NULL;
+ INIT_LIST_HEAD(&hl->hard_links);
+ }
+ }
+}
+
+static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
+{
+ /*
+ * Sort out state of unlinked and deleted objects after scanning.
+ */
+ struct list_head *i;
+ struct list_head *n;
+ struct yaffs_obj *l;
+
+ if (dev->read_only)
+ return;
+
+ /* Soft delete all the unlinked files */
+ list_for_each_safe(i, n,
+ &dev->unlinked_dir->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
+ yaffs_del_obj(l);
+ }
+
+ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
+ yaffs_del_obj(l);
+ }
+}
+
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ * This code assumes that we don't ever change the current relationships
+ * between directories:
+ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
+ * lost-n-found->parent == root_dir
+ *
+ * This fixes the problem where directories might have inadvertently been
+ * deleted leaving the object "hanging" without being rooted in the
+ * directory tree.
+ */
+
+static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+ return (obj == dev->del_dir ||
+ obj == dev->unlinked_dir || obj == dev->root_dir);
+}
+
+static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_obj *parent;
+ int i;
+ struct list_head *lh;
+ struct list_head *n;
+ int depth_limit;
+ int hanging;
+
+ if (dev->read_only)
+ return;
+
+ /* Iterate through the objects in each hash entry,
+ * looking at each object.
+ * Make sure it is rooted.
+ */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ parent = obj->parent;
+
+ if (yaffs_has_null_parent(dev, obj)) {
+ /* These directories are not hanging */
+ hanging = 0;
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ hanging = 1;
+ } else if (yaffs_has_null_parent(dev, parent)) {
+ hanging = 0;
+ } else {
+ /*
+ * Need to follow the parent chain to
+ * see if it is hanging.
+ */
+ hanging = 0;
+ depth_limit = 100;
+
+ while (parent != dev->root_dir &&
+ parent->parent &&
+ parent->parent->variant_type ==
+ YAFFS_OBJECT_TYPE_DIRECTORY &&
+ depth_limit > 0) {
+ parent = parent->parent;
+ depth_limit--;
+ }
+ if (parent != dev->root_dir)
+ hanging = 1;
+ }
+ if (hanging) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Hanging object %d moved to lost and found",
+ obj->obj_id);
+ yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+ }
+ }
+ }
+}
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_del_dir_contents(struct yaffs_obj *dir)
+{
+ struct yaffs_obj *obj;
+ struct list_head *lh;
+ struct list_head *n;
+
+ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ BUG();
+
+ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
+ obj = list_entry(lh, struct yaffs_obj, siblings);
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffs_del_dir_contents(obj);
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Deleting lost_found object %d",
+ obj->obj_id);
+ yaffs_unlink_obj(obj);
+ }
+}
+
+static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
+{
+ yaffs_del_dir_contents(dev->lost_n_found);
+}
+
+
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
+ const YCHAR *name)
+{
+ int sum;
+ struct list_head *i;
+ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+ struct yaffs_obj *l;
+
+ if (!name)
+ return NULL;
+
+ if (!directory) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_find_by_name: null pointer directory"
+ );
+ BUG();
+ return NULL;
+ }
+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "tragedy: yaffs_find_by_name: non-directory"
+ );
+ BUG();
+ }
+
+ sum = yaffs_calc_name_sum(name);
+
+ list_for_each(i, &directory->variant.dir_variant.children) {
+ l = list_entry(i, struct yaffs_obj, siblings);
+
+ if (l->parent != directory)
+ BUG();
+
+ yaffs_check_obj_details_loaded(l);
+
+ /* Special case for lost-n-found */
+ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
+ return l;
+ } else if (l->sum == sum || l->hdr_chunk <= 0) {
+ /* LostnFound chunk called Objxxx
+ * Do a real check
+ */
+ yaffs_get_obj_name(l, buffer,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ if (strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
+ return l;
+ }
+ }
+ return NULL;
+}
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
+{
+ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+ obj = obj->variant.hardlink_variant.equiv_obj;
+ yaffs_check_obj_details_loaded(obj);
+ }
+ return obj;
+}
+
+/*
+ * A note or two on object names.
+ * * If the object name is missing, we then make one up in the form objnnn
+ *
+ * * ASCII names are stored in the object header's name field from byte zero
+ * * Unicode names are historically stored starting from byte zero.
+ *
+ * Then there are automatic Unicode names...
+ * The purpose of these is to save names in a way that can be read as
+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
+ * system to share files.
+ *
+ * These automatic unicode are stored slightly differently...
+ * - If the name can fit in the ASCII character space then they are saved as
+ * ascii names as per above.
+ * - If the name needs Unicode then the name is saved in Unicode
+ * starting at oh->name[1].
+
+ */
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+ int buffer_size)
+{
+ /* Create an object name if we could not find one. */
+ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
+ YCHAR local_name[20];
+ YCHAR num_string[20];
+ YCHAR *x = &num_string[19];
+ unsigned v = obj->obj_id;
+ num_string[19] = 0;
+ while (v > 0) {
+ x--;
+ *x = '0' + (v % 10);
+ v /= 10;
+ }
+ /* make up a name */
+ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
+ strcat(local_name, x);
+ strncpy(name, local_name, buffer_size - 1);
+ }
+}
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
+{
+ memset(name, 0, buffer_size * sizeof(YCHAR));
+ yaffs_check_obj_details_loaded(obj);
+ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
+ } else if (obj->short_name[0]) {
+ strcpy(name, obj->short_name);
+ } else if (obj->hdr_chunk > 0) {
+ int result;
+ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
+
+ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
+
+ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
+
+ if (obj->hdr_chunk > 0) {
+ result = yaffs_rd_chunk_tags_nand(obj->my_dev,
+ obj->hdr_chunk,
+ buffer, NULL);
+ }
+ yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
+ buffer_size);
+
+ yaffs_release_temp_buffer(obj->my_dev, buffer);
+ }
+
+ yaffs_fix_null_name(obj, name, buffer_size);
+
+ return strnlen(name, YAFFS_MAX_NAME_LENGTH);
+}
+
+int yaffs_get_obj_length(struct yaffs_obj *obj)
+{
+ /* Dereference any hard linking */
+ obj = yaffs_get_equivalent_obj(obj);
+
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+ return obj->variant.file_variant.file_size;
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ if (!obj->variant.symlink_variant.alias)
+ return 0;
+ return strnlen(obj->variant.symlink_variant.alias,
+ YAFFS_MAX_ALIAS_LENGTH);
+ } else {
+ /* Only a directory should drop through to here */
+ return obj->my_dev->data_bytes_per_chunk;
+ }
+}
+
+int yaffs_get_obj_link_count(struct yaffs_obj *obj)
+{
+ int count = 0;
+ struct list_head *i;
+
+ if (!obj->unlinked)
+ count++; /* the object itself */
+
+ list_for_each(i, &obj->hard_links)
+ count++; /* add the hard links; */
+
+ return count;
+}
+
+int yaffs_get_obj_inode(struct yaffs_obj *obj)
+{
+ obj = yaffs_get_equivalent_obj(obj);
+
+ return obj->obj_id;
+}
+
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
+{
+ obj = yaffs_get_equivalent_obj(obj);
+
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return DT_REG;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ return DT_DIR;
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ return DT_LNK;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ return DT_REG;
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ if (S_ISFIFO(obj->yst_mode))
+ return DT_FIFO;
+ if (S_ISCHR(obj->yst_mode))
+ return DT_CHR;
+ if (S_ISBLK(obj->yst_mode))
+ return DT_BLK;
+ if (S_ISSOCK(obj->yst_mode))
+ return DT_SOCK;
+ return DT_REG;
+ break;
+ default:
+ return DT_REG;
+ break;
+ }
+}
+
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
+{
+ obj = yaffs_get_equivalent_obj(obj);
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+ return yaffs_clone_str(obj->variant.symlink_variant.alias);
+ else
+ return yaffs_clone_str(_Y(""));
+}
+
+/*--------------------------- Initialisation code -------------------------- */
+
+static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
+{
+ /* Common functions, gotta have */
+ if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+ return 0;
+
+ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
+ if (dev->param.write_chunk_tags_fn &&
+ dev->param.read_chunk_tags_fn &&
+ !dev->param.write_chunk_fn &&
+ !dev->param.read_chunk_fn &&
+ dev->param.bad_block_fn && dev->param.query_block_fn)
+ return 1;
+
+ /* Can use the "spare" style interface for yaffs1 */
+ if (!dev->param.is_yaffs2 &&
+ !dev->param.write_chunk_tags_fn &&
+ !dev->param.read_chunk_tags_fn &&
+ dev->param.write_chunk_fn &&
+ dev->param.read_chunk_fn &&
+ !dev->param.bad_block_fn && !dev->param.query_block_fn)
+ return 1;
+
+ return 0; /* bad */
+}
+
+static int yaffs_create_initial_dir(struct yaffs_dev *dev)
+{
+ /* Initialise the unlinked, deleted, root and lost+found directories */
+ dev->lost_n_found = dev->root_dir = NULL;
+ dev->unlinked_dir = dev->del_dir = NULL;
+ dev->unlinked_dir =
+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+ dev->del_dir =
+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+ dev->root_dir =
+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
+ YAFFS_ROOT_MODE | S_IFDIR);
+ dev->lost_n_found =
+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
+ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+
+ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
+ && dev->del_dir) {
+ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
+ return YAFFS_OK;
+ }
+ return YAFFS_FAIL;
+}
+
+int yaffs_guts_initialise(struct yaffs_dev *dev)
+{
+ int init_failed = 0;
+ unsigned x;
+ int bits;
+
+ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()");
+
+ /* Check stuff that must be set */
+
+ if (!dev) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs: Need a device"
+ );
+ return YAFFS_FAIL;
+ }
+
+ if (dev->is_mounted) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
+ return YAFFS_FAIL;
+ }
+
+ dev->internal_start_block = dev->param.start_block;
+ dev->internal_end_block = dev->param.end_block;
+ dev->block_offset = 0;
+ dev->chunk_offset = 0;
+ dev->n_free_chunks = 0;
+
+ dev->gc_block = 0;
+
+ if (dev->param.start_block == 0) {
+ dev->internal_start_block = dev->param.start_block + 1;
+ dev->internal_end_block = dev->param.end_block + 1;
+ dev->block_offset = 1;
+ dev->chunk_offset = dev->param.chunks_per_block;
+ }
+
+ /* Check geometry parameters. */
+
+ if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
+ dev->param.total_bytes_per_chunk < 1024) ||
+ (!dev->param.is_yaffs2 &&
+ dev->param.total_bytes_per_chunk < 512) ||
+ (dev->param.inband_tags && !dev->param.is_yaffs2) ||
+ dev->param.chunks_per_block < 2 ||
+ dev->param.n_reserved_blocks < 2 ||
+ dev->internal_start_block <= 0 ||
+ dev->internal_end_block <= 0 ||
+ dev->internal_end_block <=
+ (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
+ ) {
+ /* otherwise it is too small */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
+ dev->param.total_bytes_per_chunk,
+ dev->param.is_yaffs2 ? "2" : "",
+ dev->param.inband_tags);
+ return YAFFS_FAIL;
+ }
+
+ if (yaffs_init_nand(dev) != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+ return YAFFS_FAIL;
+ }
+
+ /* Sort out space for inband tags, if required */
+ if (dev->param.inband_tags)
+ dev->data_bytes_per_chunk =
+ dev->param.total_bytes_per_chunk -
+ sizeof(struct yaffs_packed_tags2_tags_only);
+ else
+ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
+
+ /* Got the right mix of functions? */
+ if (!yaffs_check_dev_fns(dev)) {
+ /* Function missing */
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "device function(s) missing or wrong");
+
+ return YAFFS_FAIL;
+ }
+
+ /* Finished with most checks. Further checks happen later on too. */
+
+ dev->is_mounted = 1;
+
+ /* OK now calculate a few things for the device */
+
+ /*
+ * Calculate all the chunk size manipulation numbers:
+ */
+ x = dev->data_bytes_per_chunk;
+ /* We always use dev->chunk_shift and dev->chunk_div */
+ dev->chunk_shift = calc_shifts(x);
+ x >>= dev->chunk_shift;
+ dev->chunk_div = x;
+ /* We only use chunk mask if chunk_div is 1 */
+ dev->chunk_mask = (1 << dev->chunk_shift) - 1;
+
+ /*
+ * Calculate chunk_grp_bits.
+ * We need to find the next power of 2 > than internal_end_block
+ */
+
+ x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
+
+ bits = calc_shifts_ceiling(x);
+
+ /* Set up tnode width if wide tnodes are enabled. */
+ if (!dev->param.wide_tnodes_disabled) {
+ /* bits must be even so that we end up with 32-bit words */
+ if (bits & 1)
+ bits++;
+ if (bits < 16)
+ dev->tnode_width = 16;
+ else
+ dev->tnode_width = bits;
+ } else {
+ dev->tnode_width = 16;
+ }
+
+ dev->tnode_mask = (1 << dev->tnode_width) - 1;
+
+ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
+ * so if the bitwidth of the
+ * chunk range we're using is greater than 16 we need
+ * to figure out chunk shift and chunk_grp_size
+ */
+
+ if (bits <= dev->tnode_width)
+ dev->chunk_grp_bits = 0;
+ else
+ dev->chunk_grp_bits = bits - dev->tnode_width;
+
+ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
+ if (dev->tnode_size < sizeof(struct yaffs_tnode))
+ dev->tnode_size = sizeof(struct yaffs_tnode);
+
+ dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
+
+ if (dev->param.chunks_per_block < dev->chunk_grp_size) {
+ /* We have a problem because the soft delete won't work if
+ * the chunk group size > chunks per block.
+ * This can be remedied by using larger "virtual blocks".
+ */
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
+
+ return YAFFS_FAIL;
+ }
+
+ /* Finished verifying the device, continue with initialisation */
+
+ /* More device initialisation */
+ dev->all_gcs = 0;
+ dev->passive_gc_count = 0;
+ dev->oldest_dirty_gc_count = 0;
+ dev->bg_gcs = 0;
+ dev->gc_block_finder = 0;
+ dev->buffered_block = -1;
+ dev->doing_buffered_block_rewrite = 0;
+ dev->n_deleted_files = 0;
+ dev->n_bg_deletions = 0;
+ dev->n_unlinked_files = 0;
+ dev->n_ecc_fixed = 0;
+ dev->n_ecc_unfixed = 0;
+ dev->n_tags_ecc_fixed = 0;
+ dev->n_tags_ecc_unfixed = 0;
+ dev->n_erase_failures = 0;
+ dev->n_erased_blocks = 0;
+ dev->gc_disable = 0;
+ dev->has_pending_prioritised_gc = 1;
+ /* Assume the worst for now, will get fixed on first GC */
+ INIT_LIST_HEAD(&dev->dirty_dirs);
+ dev->oldest_dirty_seq = 0;
+ dev->oldest_dirty_block = 0;
+
+ /* Initialise temporary buffers and caches. */
+ if (!yaffs_init_tmp_buffers(dev))
+ init_failed = 1;
+
+ dev->cache = NULL;
+ dev->gc_cleanup_list = NULL;
+
+ if (!init_failed && dev->param.n_caches > 0) {
+ int i;
+ void *buf;
+ int cache_bytes =
+ dev->param.n_caches * sizeof(struct yaffs_cache);
+
+ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
+ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
+
+ dev->cache = kmalloc(cache_bytes, GFP_NOFS);
+
+ buf = (u8 *) dev->cache;
+
+ if (dev->cache)
+ memset(dev->cache, 0, cache_bytes);
+
+ for (i = 0; i < dev->param.n_caches && buf; i++) {
+ dev->cache[i].object = NULL;
+ dev->cache[i].last_use = 0;
+ dev->cache[i].dirty = 0;
+ dev->cache[i].data = buf =
+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+ }
+ if (!buf)
+ init_failed = 1;
+
+ dev->cache_last_use = 0;
+ }
+
+ dev->cache_hits = 0;
+
+ if (!init_failed) {
+ dev->gc_cleanup_list =
+ kmalloc(dev->param.chunks_per_block * sizeof(u32),
+ GFP_NOFS);
+ if (!dev->gc_cleanup_list)
+ init_failed = 1;
+ }
+
+ if (dev->param.is_yaffs2)
+ dev->param.use_header_file_size = 1;
+
+ if (!init_failed && !yaffs_init_blocks(dev))
+ init_failed = 1;
+
+ yaffs_init_tnodes_and_objs(dev);
+
+ if (!init_failed && !yaffs_create_initial_dir(dev))
+ init_failed = 1;
+
+ if(!init_failed && dev->param.is_yaffs2 &&
+ !dev->param.disable_summary &&
+ !yaffs_summary_init(dev))
+ init_failed = 1;
+
+ if (!init_failed) {
+ /* Now scan the flash. */
+ if (dev->param.is_yaffs2) {
+ if (yaffs2_checkpt_restore(dev)) {
+ yaffs_check_obj_details_loaded(dev->root_dir);
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT |
+ YAFFS_TRACE_MOUNT,
+ "yaffs: restored from checkpoint"
+ );
+ } else {
+
+ /* Clean up the mess caused by an aborted
+ * checkpoint load then scan backwards.
+ */
+ yaffs_deinit_blocks(dev);
+
+ yaffs_deinit_tnodes_and_objs(dev);
+
+ dev->n_erased_blocks = 0;
+ dev->n_free_chunks = 0;
+ dev->alloc_block = -1;
+ dev->alloc_page = -1;
+ dev->n_deleted_files = 0;
+ dev->n_unlinked_files = 0;
+ dev->n_bg_deletions = 0;
+
+ if (!init_failed && !yaffs_init_blocks(dev))
+ init_failed = 1;
+
+ yaffs_init_tnodes_and_objs(dev);
+
+ if (!init_failed
+ && !yaffs_create_initial_dir(dev))
+ init_failed = 1;
+
+ if (!init_failed && !yaffs2_scan_backwards(dev))
+ init_failed = 1;
+ }
+ } else if (!yaffs1_scan(dev)) {
+ init_failed = 1;
+ }
+
+ yaffs_strip_deleted_objs(dev);
+ yaffs_fix_hanging_objs(dev);
+ if (dev->param.empty_lost_n_found)
+ yaffs_empty_l_n_f(dev);
+ }
+
+ if (init_failed) {
+ /* Clean up the mess */
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: yaffs_guts_initialise() aborted.");
+
+ yaffs_deinitialise(dev);
+ return YAFFS_FAIL;
+ }
+
+ /* Zero out stats */
+ dev->n_page_reads = 0;
+ dev->n_page_writes = 0;
+ dev->n_erasures = 0;
+ dev->n_gc_copies = 0;
+ dev->n_retried_writes = 0;
+
+ dev->n_retired_blocks = 0;
+
+ yaffs_verify_free_chunks(dev);
+ yaffs_verify_blocks(dev);
+
+ /* Clean up any aborted checkpoint data */
+ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
+ yaffs2_checkpt_invalidate(dev);
+
+ yaffs_trace(YAFFS_TRACE_TRACING,
+ "yaffs: yaffs_guts_initialise() done.");
+ return YAFFS_OK;
+}
+
+void yaffs_deinitialise(struct yaffs_dev *dev)
+{
+ if (dev->is_mounted) {
+ int i;
+
+ yaffs_deinit_blocks(dev);
+ yaffs_deinit_tnodes_and_objs(dev);
+ yaffs_summary_deinit(dev);
+
+ if (dev->param.n_caches > 0 && dev->cache) {
+
+ for (i = 0; i < dev->param.n_caches; i++) {
+ kfree(dev->cache[i].data);
+ dev->cache[i].data = NULL;
+ }
+
+ kfree(dev->cache);
+ dev->cache = NULL;
+ }
+
+ kfree(dev->gc_cleanup_list);
+
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
+ kfree(dev->temp_buffer[i].buffer);
+
+ dev->is_mounted = 0;
+
+ if (dev->param.deinitialise_flash_fn)
+ dev->param.deinitialise_flash_fn(dev);
+ }
+}
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev)
+{
+ int n_free = 0;
+ int b;
+ struct yaffs_block_info *blk;
+
+ blk = dev->block_info;
+ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+ switch (blk->block_state) {
+ case YAFFS_BLOCK_STATE_EMPTY:
+ case YAFFS_BLOCK_STATE_ALLOCATING:
+ case YAFFS_BLOCK_STATE_COLLECTING:
+ case YAFFS_BLOCK_STATE_FULL:
+ n_free +=
+ (dev->param.chunks_per_block - blk->pages_in_use +
+ blk->soft_del_pages);
+ break;
+ default:
+ break;
+ }
+ blk++;
+ }
+ return n_free;
+}
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
+{
+ /* This is what we report to the outside world */
+ int n_free;
+ int n_dirty_caches;
+ int blocks_for_checkpt;
+ int i;
+
+ n_free = dev->n_free_chunks;
+ n_free += dev->n_deleted_files;
+
+ /* Now count and subtract the number of dirty chunks in the cache. */
+
+ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
+ if (dev->cache[i].dirty)
+ n_dirty_caches++;
+ }
+
+ n_free -= n_dirty_caches;
+
+ n_free -=
+ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
+
+ /* Now figure checkpoint space and report that... */
+ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
+
+ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
+
+ if (n_free < 0)
+ n_free = 0;
+
+ return n_free;
+}
diff --git a/fs/yaffs2-new/yaffs_guts.h b/fs/yaffs2-new/yaffs_guts.h
new file mode 100644
index 0000000000..490122aa16
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_guts.h
@@ -0,0 +1,938 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "yportenv.h"
+
+#define YAFFS_OK 1
+#define YAFFS_FAIL 0
+
+/* Give us a Y=0x59,
+ * Give us an A=0x41,
+ * Give us an FF=0xff
+ * Give us an S=0x53
+ * And what have we got...
+ */
+#define YAFFS_MAGIC 0x5941ff53
+
+#define YAFFS_NTNODES_LEVEL0 16
+#define YAFFS_TNODES_LEVEL0_BITS 4
+#define YAFFS_TNODES_LEVEL0_MASK 0xf
+
+#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK 0x7
+#define YAFFS_TNODES_MAX_LEVEL 6
+
+
+/* Constants for YAFFS1 mode */
+#define YAFFS_BYTES_PER_SPARE 16
+#define YAFFS_BYTES_PER_CHUNK 512
+#define YAFFS_CHUNK_SIZE_SHIFT 9
+#define YAFFS_CHUNKS_PER_BLOCK 32
+#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
+
+#define YAFFS_MAX_CHUNK_ID 0x000fffff
+
+#define YAFFS_ALLOCATION_NOBJECTS 100
+#define YAFFS_ALLOCATION_NTNODES 100
+#define YAFFS_ALLOCATION_NLINKS 100
+
+#define YAFFS_NOBJECT_BUCKETS 256
+
+#define YAFFS_OBJECT_SPACE 0x40000
+#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
+
+#define YAFFS_CHECKPOINT_VERSION 4
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH 127
+#define YAFFS_MAX_ALIAS_LENGTH 79
+#else
+#define YAFFS_MAX_NAME_LENGTH 255
+#define YAFFS_MAX_ALIAS_LENGTH 159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH 15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT 1
+#define YAFFS_OBJECTID_LOSTNFOUND 2
+#define YAFFS_OBJECTID_UNLINKED 3
+#define YAFFS_OBJECTID_DELETED 4
+
+/* Fake object Id for summary data */
+#define YAFFS_OBJECTID_SUMMARY 0x10
+
+/* Pseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
+
+#define YAFFS_MAX_SHORT_OP_CACHES 20
+
+#define YAFFS_N_TEMP_BUFFERS 6
+
+/* We limit the number attempts at sucessfully saving a chunk of data.
+ * Small-page devices have 32 pages per block; large-page devices have 64.
+ * Default to something in the order of 5 to 10 blocks worth of chunks.
+ */
+#define YAFFS_WR_ATTEMPTS (5*64)
+
+/* Sequence numbers are used in YAFFS2 to determine block allocation order.
+ * The range is limited slightly to help distinguish bad numbers from good.
+ * This also allows us to perhaps in the future use special numbers for
+ * special purposes.
+ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
+
+/* Special sequence number for bad block that failed to be marked bad */
+#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
+
+/* ChunkCache is used for short read/write operations.*/
+struct yaffs_cache {
+ struct yaffs_obj *object;
+ int chunk_id;
+ int last_use;
+ int dirty;
+ int n_bytes; /* Only valid if the cache is dirty */
+ int locked; /* Can't push out or flush while locked. */
+ u8 *data;
+};
+
+/* yaffs1 tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
+ * otherwise the structure size will get blown out.
+ */
+
+struct yaffs_tags {
+ unsigned chunk_id:20;
+ unsigned serial_number:2;
+ unsigned n_bytes_lsb:10;
+ unsigned obj_id:18;
+ unsigned ecc:12;
+ unsigned n_bytes_msb:2;
+};
+
+union yaffs_tags_union {
+ struct yaffs_tags as_tags;
+ u8 as_bytes[8];
+};
+
+
+/* Stuff used for extended tags in YAFFS2 */
+
+enum yaffs_ecc_result {
+ YAFFS_ECC_RESULT_UNKNOWN,
+ YAFFS_ECC_RESULT_NO_ERROR,
+ YAFFS_ECC_RESULT_FIXED,
+ YAFFS_ECC_RESULT_UNFIXED
+};
+
+enum yaffs_obj_type {
+ YAFFS_OBJECT_TYPE_UNKNOWN,
+ YAFFS_OBJECT_TYPE_FILE,
+ YAFFS_OBJECT_TYPE_SYMLINK,
+ YAFFS_OBJECT_TYPE_DIRECTORY,
+ YAFFS_OBJECT_TYPE_HARDLINK,
+ YAFFS_OBJECT_TYPE_SPECIAL
+};
+
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
+struct yaffs_ext_tags {
+ unsigned chunk_used; /* Status of the chunk: used or unused */
+ unsigned obj_id; /* If 0 this is not used */
+ unsigned chunk_id; /* If 0 this is a header, else a data chunk */
+ unsigned n_bytes; /* Only valid for data chunks */
+
+ /* The following stuff only has meaning when we read */
+ enum yaffs_ecc_result ecc_result;
+ unsigned block_bad;
+
+ /* YAFFS 1 stuff */
+ unsigned is_deleted; /* The chunk is marked deleted */
+ unsigned serial_number; /* Yaffs1 2-bit serial number */
+
+ /* YAFFS2 stuff */
+ unsigned seq_number; /* The sequence number of this block */
+
+ /* Extra info if this is an object header (YAFFS2 only) */
+
+ unsigned extra_available; /* Extra info available if not zero */
+ unsigned extra_parent_id; /* The parent object */
+ unsigned extra_is_shrink; /* Is it a shrink header? */
+ unsigned extra_shadows; /* Does this shadow another object? */
+
+ enum yaffs_obj_type extra_obj_type; /* What object type? */
+
+ unsigned extra_length; /* Length if it is a file */
+ unsigned extra_equiv_id; /* Equivalent object for a hard link */
+};
+
+/* Spare structure for YAFFS1 */
+struct yaffs_spare {
+ u8 tb0;
+ u8 tb1;
+ u8 tb2;
+ u8 tb3;
+ u8 page_status; /* set to 0 to delete the chunk */
+ u8 block_status;
+ u8 tb4;
+ u8 tb5;
+ u8 ecc1[3];
+ u8 tb6;
+ u8 tb7;
+ u8 ecc2[3];
+};
+
+/*Special structure for passing through to mtd */
+struct yaffs_nand_spare {
+ struct yaffs_spare spare;
+ int eccres1;
+ int eccres2;
+};
+
+/* Block data in RAM */
+
+enum yaffs_block_state {
+ YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+ YAFFS_BLOCK_STATE_SCANNING,
+ /* Being scanned */
+
+ YAFFS_BLOCK_STATE_NEEDS_SCAN,
+ /* The block might have something on it (ie it is allocating or full,
+ * perhaps empty) but it needs to be scanned to determine its true
+ * state.
+ * This state is only valid during scanning.
+ * NB We tolerate empty because the pre-scanner might be incapable of
+ * deciding
+ * However, if this state is returned on a YAFFS2 device,
+ * then we expect a sequence number
+ */
+
+ YAFFS_BLOCK_STATE_EMPTY,
+ /* This block is empty */
+
+ YAFFS_BLOCK_STATE_ALLOCATING,
+ /* This block is partially allocated.
+ * At least one page holds valid data.
+ * This is the one currently being used for page
+ * allocation. Should never be more than one of these.
+ * If a block is only partially allocated at mount it is treated as
+ * full.
+ */
+
+ YAFFS_BLOCK_STATE_FULL,
+ /* All the pages in this block have been allocated.
+ * If a block was only partially allocated when mounted we treat
+ * it as fully allocated.
+ */
+
+ YAFFS_BLOCK_STATE_DIRTY,
+ /* The block was full and now all chunks have been deleted.
+ * Erase me, reuse me.
+ */
+
+ YAFFS_BLOCK_STATE_CHECKPOINT,
+ /* This block is assigned to holding checkpoint data. */
+
+ YAFFS_BLOCK_STATE_COLLECTING,
+ /* This block is being garbage collected */
+
+ YAFFS_BLOCK_STATE_DEAD
+ /* This block has failed and is not in use */
+};
+
+#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+struct yaffs_block_info {
+
+ int soft_del_pages:10; /* number of soft deleted pages */
+ int pages_in_use:10; /* number of pages in use */
+ unsigned block_state:4; /* One of the above block states. */
+ /* NB use unsigned because enum is sometimes
+ * an int */
+ u32 needs_retiring:1; /* Data has failed on this block, */
+ /*need to get valid data off and retire*/
+ u32 skip_erased_check:1;/* Skip the erased check on this block */
+ u32 gc_prioritise:1; /* An ECC check or blank check has failed.
+ Block should be prioritised for GC */
+ u32 chunk_error_strikes:3; /* How many times we've had ecc etc
+ failures on this block and tried to reuse it */
+ u32 has_summary:1; /* The block has a summary */
+
+ u32 has_shrink_hdr:1; /* This block has at least one shrink header */
+ u32 seq_number; /* block sequence number for yaffs2 */
+
+};
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+struct yaffs_obj_hdr {
+ enum yaffs_obj_type type;
+
+ /* Apply to everything */
+ int parent_obj_id;
+ u16 sum_no_longer_used; /* checksum of name. No longer used */
+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ /* The following apply to all object types except for hard links */
+ u32 yst_mode; /* protection */
+
+ u32 yst_uid;
+ u32 yst_gid;
+ u32 yst_atime;
+ u32 yst_mtime;
+ u32 yst_ctime;
+
+ /* File size applies to files only */
+ int file_size;
+
+ /* Equivalent object id applies to hard links only. */
+ int equiv_id;
+
+ /* Alias is for symlinks only. */
+ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+ u32 yst_rdev; /* stuff for block and char devices (major/min) */
+
+ u32 win_ctime[2];
+ u32 win_atime[2];
+ u32 win_mtime[2];
+
+ u32 inband_shadowed_obj_id;
+ u32 inband_is_shrink;
+
+ u32 reserved[2];
+ int shadows_obj; /* This object header shadows the
+ specified object if > 0 */
+
+ /* is_shrink applies to object headers written when wemake a hole. */
+ u32 is_shrink;
+
+};
+
+/*--------------------------- Tnode -------------------------- */
+
+struct yaffs_tnode {
+ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
+};
+
+/*------------------------ Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+struct yaffs_file_var {
+ u32 file_size;
+ u32 scanned_size;
+ u32 shrink_size;
+ int top_level;
+ struct yaffs_tnode *top;
+};
+
+struct yaffs_dir_var {
+ struct list_head children; /* list of child links */
+ struct list_head dirty; /* Entry for list of dirty directories */
+};
+
+struct yaffs_symlink_var {
+ YCHAR *alias;
+};
+
+struct yaffs_hardlink_var {
+ struct yaffs_obj *equiv_obj;
+ u32 equiv_id;
+};
+
+union yaffs_obj_var {
+ struct yaffs_file_var file_variant;
+ struct yaffs_dir_var dir_variant;
+ struct yaffs_symlink_var symlink_variant;
+ struct yaffs_hardlink_var hardlink_variant;
+};
+
+struct yaffs_obj {
+ u8 deleted:1; /* This should only apply to unlinked files. */
+ u8 soft_del:1; /* it has also been soft deleted */
+ u8 unlinked:1; /* An unlinked file.*/
+ u8 fake:1; /* A fake object has no presence on NAND. */
+ u8 rename_allowed:1; /* Some objects cannot be renamed. */
+ u8 unlink_allowed:1;
+ u8 dirty:1; /* the object needs to be written to flash */
+ u8 valid:1; /* When the file system is being loaded up, this
+ * object might be created before the data
+ * is available
+ * ie. file data chunks encountered before
+ * the header.
+ */
+ u8 lazy_loaded:1; /* This object has been lazy loaded and
+ * is missing some detail */
+
+ u8 defered_free:1; /* Object is removed from NAND, but is
+ * still in the inode cache.
+ * Free of object is defered.
+ * until the inode is released.
+ */
+ u8 being_created:1; /* This object is still being created
+ * so skip some verification checks. */
+ u8 is_shadowed:1; /* This object is shadowed on the way
+ * to being renamed. */
+
+ u8 xattr_known:1; /* We know if this has object has xattribs
+ * or not. */
+ u8 has_xattr:1; /* This object has xattribs.
+ * Only valid if xattr_known. */
+
+ u8 serial; /* serial number of chunk in NAND.*/
+ u16 sum; /* sum of the name to speed searching */
+
+ struct yaffs_dev *my_dev; /* The device I'm on */
+
+ struct list_head hash_link; /* list of objects in hash bucket */
+
+ struct list_head hard_links; /* hard linked object chain*/
+
+ /* directory structure stuff */
+ /* also used for linking up the free list */
+ struct yaffs_obj *parent;
+ struct list_head siblings;
+
+ /* Where's my object header in NAND? */
+ int hdr_chunk;
+
+ int n_data_chunks; /* Number of data chunks for this file. */
+
+ u32 obj_id; /* the object id value */
+
+ u32 yst_mode;
+
+ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
+
+#ifdef CONFIG_YAFFS_WINCE
+ u32 win_ctime[2];
+ u32 win_mtime[2];
+ u32 win_atime[2];
+#else
+ u32 yst_uid;
+ u32 yst_gid;
+ u32 yst_atime;
+ u32 yst_mtime;
+ u32 yst_ctime;
+#endif
+
+ u32 yst_rdev;
+
+ void *my_inode;
+
+ enum yaffs_obj_type variant_type;
+
+ union yaffs_obj_var variant;
+
+};
+
+struct yaffs_obj_bucket {
+ struct list_head list;
+ int count;
+};
+
+/* yaffs_checkpt_obj holds the definition of an object as dumped
+ * by checkpointing.
+ */
+
+struct yaffs_checkpt_obj {
+ int struct_type;
+ u32 obj_id;
+ u32 parent_id;
+ int hdr_chunk;
+ enum yaffs_obj_type variant_type:3;
+ u8 deleted:1;
+ u8 soft_del:1;
+ u8 unlinked:1;
+ u8 fake:1;
+ u8 rename_allowed:1;
+ u8 unlink_allowed:1;
+ u8 serial;
+ int n_data_chunks;
+ u32 size_or_equiv_obj;
+};
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few.
+ */
+
+struct yaffs_buffer {
+ u8 *buffer;
+ int in_use;
+};
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_param {
+ const YCHAR *name;
+
+ /*
+ * Entry parameters set up way early. Yaffs sets up the rest.
+ * The structure should be zeroed out before use so that unused
+ * and defualt values are zero.
+ */
+
+ int inband_tags; /* Use unband tags */
+ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
+ be a power of 2 */
+ int chunks_per_block; /* does not need to be a power of 2 */
+ int spare_bytes_per_chunk; /* spare area size */
+ int start_block; /* Start block we're allowed to use */
+ int end_block; /* End block we're allowed to use */
+ int n_reserved_blocks; /* Tuneable so that we can reduce
+ * reserved blocks on NOR and RAM. */
+
+ int n_caches; /* If <= 0, then short op caching is disabled,
+ * else the number of short op caches.
+ */
+ int use_nand_ecc; /* Flag to decide whether or not to use
+ * NAND driver ECC on data (yaffs1) */
+ int tags_9bytes; /* Use 9 byte tags */
+ int no_tags_ecc; /* Flag to decide whether or not to do ECC
+ * on packed tags (yaffs2) */
+
+ int is_yaffs2; /* Use yaffs2 mode on this device */
+
+ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
+
+ int refresh_period; /* How often to check for a block refresh */
+
+ /* Checkpoint control. Can be set before or after initialisation */
+ u8 skip_checkpt_rd;
+ u8 skip_checkpt_wr;
+
+ int enable_xattr; /* Enable xattribs */
+
+ /* NAND access functions (Must be set before calling YAFFS) */
+
+ int (*write_chunk_fn) (struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ const struct yaffs_spare *spare);
+ int (*read_chunk_fn) (struct yaffs_dev *dev,
+ int nand_chunk, u8 *data,
+ struct yaffs_spare *spare);
+ int (*erase_fn) (struct yaffs_dev *dev, int flash_block);
+ int (*initialise_flash_fn) (struct yaffs_dev *dev);
+ int (*deinitialise_flash_fn) (struct yaffs_dev *dev);
+
+ /* yaffs2 mode functions */
+ int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ const struct yaffs_ext_tags *tags);
+ int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
+ int nand_chunk, u8 *data,
+ struct yaffs_ext_tags *tags);
+ int (*bad_block_fn) (struct yaffs_dev *dev, int block_no);
+ int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number);
+
+ /* The remove_obj_fn function must be supplied by OS flavours that
+ * need it.
+ * yaffs direct uses it to implement the faster readdir.
+ * Linux uses it to protect the directory during unlocking.
+ */
+ void (*remove_obj_fn) (struct yaffs_obj *obj);
+
+ /* Callback to mark the superblock dirty */
+ void (*sb_dirty_fn) (struct yaffs_dev *dev);
+
+ /* Callback to control garbage collection. */
+ unsigned (*gc_control) (struct yaffs_dev *dev);
+
+ /* Debug control flags. Don't use unless you know what you're doing */
+ int use_header_file_size; /* Flag to determine if we should use
+ * file sizes from the header */
+ int disable_lazy_load; /* Disable lazy loading on this device */
+ int wide_tnodes_disabled; /* Set to disable wide tnodes */
+ int disable_soft_del; /* yaffs 1 only: Set to disable the use of
+ * softdeletion. */
+
+ int defered_dir_update; /* Set to defer directory updates */
+
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ int auto_unicode;
+#endif
+ int always_check_erased; /* Force chunk erased check always on */
+
+ int disable_summary;
+};
+
+struct yaffs_dev {
+ struct yaffs_param param;
+
+ /* Context storage. Holds extra OS specific data for this device */
+
+ void *os_context;
+ void *driver_context;
+
+ struct list_head dev_list;
+
+ /* Runtime parameters. Set up by YAFFS. */
+ int data_bytes_per_chunk;
+
+ /* Non-wide tnode stuff */
+ u16 chunk_grp_bits; /* Number of bits that need to be resolved if
+ * the tnodes are not wide enough.
+ */
+ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
+
+ /* Stuff to support wide tnodes */
+ u32 tnode_width;
+ u32 tnode_mask;
+ u32 tnode_size;
+
+ /* Stuff for figuring out file offset to chunk conversions */
+ u32 chunk_shift; /* Shift value */
+ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
+ u32 chunk_mask; /* Mask to use for power-of-2 case */
+
+ int is_mounted;
+ int read_only;
+ int is_checkpointed;
+
+ /* Stuff to support block offsetting to support start block zero */
+ int internal_start_block;
+ int internal_end_block;
+ int block_offset;
+ int chunk_offset;
+
+ /* Runtime checkpointing stuff */
+ int checkpt_page_seq; /* running sequence number of checkpt pages */
+ int checkpt_byte_count;
+ int checkpt_byte_offs;
+ u8 *checkpt_buffer;
+ int checkpt_open_write;
+ int blocks_in_checkpt;
+ int checkpt_cur_chunk;
+ int checkpt_cur_block;
+ int checkpt_next_block;
+ int *checkpt_block_list;
+ int checkpt_max_blocks;
+ u32 checkpt_sum;
+ u32 checkpt_xor;
+
+ int checkpoint_blocks_required; /* Number of blocks needed to store
+ * current checkpoint set */
+
+ /* Block Info */
+ struct yaffs_block_info *block_info;
+ u8 *chunk_bits; /* bitmap of chunks in use */
+ unsigned block_info_alt:1; /* allocated using alternative alloc */
+ unsigned chunk_bits_alt:1; /* allocated using alternative alloc */
+ int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
+ * Must be consistent with chunks_per_block.
+ */
+
+ int n_erased_blocks;
+ int alloc_block; /* Current block being allocated off */
+ u32 alloc_page;
+ int alloc_block_finder; /* Used to search for next allocation block */
+
+ /* Object and Tnode memory management */
+ void *allocator;
+ int n_obj;
+ int n_tnodes;
+
+ int n_hardlinks;
+
+ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
+ u32 bucket_finder;
+
+ int n_free_chunks;
+
+ /* Garbage collection control */
+ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
+ u32 n_clean_ups;
+
+ unsigned has_pending_prioritised_gc; /* We think this device might
+ have pending prioritised gcs */
+ unsigned gc_disable;
+ unsigned gc_block_finder;
+ unsigned gc_dirtiest;
+ unsigned gc_pages_in_use;
+ unsigned gc_not_done;
+ unsigned gc_block;
+ unsigned gc_chunk;
+ unsigned gc_skip;
+ struct yaffs_summary_tags *gc_sum_tags;
+
+ /* Special directories */
+ struct yaffs_obj *root_dir;
+ struct yaffs_obj *lost_n_found;
+
+ int buffered_block; /* Which block is buffered here? */
+ int doing_buffered_block_rewrite;
+
+ struct yaffs_cache *cache;
+ int cache_last_use;
+
+ /* Stuff for background deletion and unlinked files. */
+ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
+ files live. */
+ struct yaffs_obj *del_dir; /* Directory where deleted objects are
+ sent to disappear. */
+ struct yaffs_obj *unlinked_deletion; /* Current file being
+ background deleted. */
+ int n_deleted_files; /* Count of files awaiting deletion; */
+ int n_unlinked_files; /* Count of unlinked files. */
+ int n_bg_deletions; /* Count of background deletions. */
+
+ /* Temporary buffer management */
+ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
+ int max_temp;
+ int temp_in_use;
+ int unmanaged_buffer_allocs;
+ int unmanaged_buffer_deallocs;
+
+ /* yaffs2 runtime stuff */
+ unsigned seq_number; /* Sequence number of currently
+ allocating block */
+ unsigned oldest_dirty_seq;
+ unsigned oldest_dirty_block;
+
+ /* Block refreshing */
+ int refresh_skip; /* A skip down counter.
+ * Refresh happens when this gets to zero. */
+
+ /* Dirty directory handling */
+ struct list_head dirty_dirs; /* List of dirty directories */
+
+ /* Summary */
+ int chunks_per_summary;
+ struct yaffs_summary_tags *sum_tags;
+
+ /* Statistics */
+ u32 n_page_writes;
+ u32 n_page_reads;
+ u32 n_erasures;
+ u32 n_erase_failures;
+ u32 n_gc_copies;
+ u32 all_gcs;
+ u32 passive_gc_count;
+ u32 oldest_dirty_gc_count;
+ u32 n_gc_blocks;
+ u32 bg_gcs;
+ u32 n_retried_writes;
+ u32 n_retired_blocks;
+ u32 n_ecc_fixed;
+ u32 n_ecc_unfixed;
+ u32 n_tags_ecc_fixed;
+ u32 n_tags_ecc_unfixed;
+ u32 n_deletions;
+ u32 n_unmarked_deletions;
+ u32 refresh_count;
+ u32 cache_hits;
+ u32 tags_used;
+ u32 summary_used;
+
+};
+
+/* The CheckpointDevice structure holds the device information that changes
+ *at runtime and must be preserved over unmount/mount cycles.
+ */
+struct yaffs_checkpt_dev {
+ int struct_type;
+ int n_erased_blocks;
+ int alloc_block; /* Current block being allocated off */
+ u32 alloc_page;
+ int n_free_chunks;
+
+ int n_deleted_files; /* Count of files awaiting deletion; */
+ int n_unlinked_files; /* Count of unlinked files. */
+ int n_bg_deletions; /* Count of background deletions. */
+
+ /* yaffs2 runtime stuff */
+ unsigned seq_number; /* Sequence number of currently
+ * allocating block */
+
+};
+
+struct yaffs_checkpt_validity {
+ int struct_type;
+ u32 magic;
+ u32 version;
+ u32 head;
+};
+
+struct yaffs_shadow_fixer {
+ int obj_id;
+ int shadowed_id;
+ struct yaffs_shadow_fixer *next;
+};
+
+/* Structure for doing xattr modifications */
+struct yaffs_xattr_mod {
+ int set; /* If 0 then this is a deletion */
+ const YCHAR *name;
+ const void *data;
+ int size;
+ int flags;
+ int result;
+};
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_guts_initialise(struct yaffs_dev *dev);
+void yaffs_deinitialise(struct yaffs_dev *dev);
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
+ struct yaffs_obj *new_dir, const YCHAR * new_name);
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
+int yaffs_del_obj(struct yaffs_obj *obj);
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
+int yaffs_get_obj_length(struct yaffs_obj *obj);
+int yaffs_get_obj_inode(struct yaffs_obj *obj);
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
+int yaffs_get_obj_link_count(struct yaffs_obj *obj);
+
+/* File operations */
+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
+ int n_bytes);
+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
+ int n_bytes, int write_trhrough);
+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid);
+
+int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
+
+/* Flushing and checkpointing */
+void yaffs_flush_whole_cache(struct yaffs_dev *dev);
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev);
+int yaffs_checkpoint_restore(struct yaffs_dev *dev);
+
+/* Directory operations */
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+ u32 mode, u32 uid, u32 gid);
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
+ const YCHAR *name);
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
+
+/* Link operations */
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
+ struct yaffs_obj *equiv_obj);
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
+
+/* Symlink operations */
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, const YCHAR *alias);
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
+
+/* Special inodes (fifos, sockets and devices) */
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+ const YCHAR *name, u32 mode, u32 uid,
+ u32 gid, u32 rdev);
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
+ const void *value, int size, int flags);
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
+ int size);
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
+
+/* Special directories */
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj);
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
+
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
+
+/* Debug dump */
+int yaffs_dump_obj(struct yaffs_obj *obj);
+
+void yaffs_guts_test(struct yaffs_dev *dev);
+
+/* A few useful functions to be used within the core files*/
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+ int lyn);
+int yaffs_check_ff(u8 *buffer, int n_bytes);
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi);
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+ int number,
+ enum yaffs_obj_type type);
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+ int nand_chunk, int in_scan);
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+ const struct yaffs_obj_hdr *oh);
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
+YCHAR *yaffs_clone_str(const YCHAR *str);
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
+ int force, int is_shrink, int shadows,
+ struct yaffs_xattr_mod *xop);
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+ int backward_scanning);
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id,
+ struct yaffs_tnode *passed_tn);
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+ int n_bytes, int write_trhrough);
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+ struct yaffs_file_var *file_struct,
+ u32 chunk_id);
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+ unsigned pos);
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
+#endif
diff --git a/fs/yaffs2-new/yaffs_malloc.h b/fs/yaffs2-new/yaffs_malloc.h
new file mode 100644
index 0000000000..3a2ea50b66
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_malloc.h
@@ -0,0 +1,39 @@
+#ifndef __YAFFS_MALLOC_H__
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* XXX U-BOOT XXX */
+
+extern void *yaffs_malloc(size_t size);
+void yaffs_free(void *ptr);
+
+
+#ifndef kmalloc
+#define kmalloc(x, flags) yaffs_malloc(x)
+#endif
+
+#ifndef vmalloc
+#define vmalloc(x) yaffs_malloc(x)
+#endif
+
+#ifndef kfree
+#define kfree(x) yaffs_free(x)
+#endif
+
+#ifndef vfree
+#define vfree(x) yaffs_free(x)
+#endif
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_mtdif.c b/fs/yaffs2-new/yaffs_mtdif.c
new file mode 100644
index 0000000000..2d77699663
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_mtdif.c
@@ -0,0 +1,53 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+
+#include "yaffs_direct.h"
+
+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ u32 addr =
+ ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
+ dev->param.chunks_per_block;
+ struct erase_info ei;
+ int retval = 0;
+
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
+ ei.time = 1000;
+ ei.retries = 2;
+ ei.callback = NULL;
+ ei.priv = (u_long) dev;
+
+ retval = mtd->erase(mtd, &ei);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+int nandmtd_initialise(struct yaffs_dev *dev)
+{
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_mtdif.h b/fs/yaffs2-new/yaffs_mtdif.h
new file mode 100644
index 0000000000..3ef5581fdb
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_mtdif.h
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF_H__
+#define __YAFFS_MTDIF_H__
+
+#include "yaffs_guts.h"
+
+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
+int nandmtd_initialise(struct yaffs_dev *dev);
+#endif
diff --git a/fs/yaffs2-new/yaffs_mtdif2.h b/fs/yaffs2-new/yaffs_mtdif2.h
new file mode 100644
index 0000000000..d4d18585b2
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_mtdif2.h
@@ -0,0 +1,29 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF2_H__
+#define __YAFFS_MTDIF2_H__
+
+#include "yaffs_guts.h"
+int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data,
+ const struct yaffs_ext_tags *tags);
+int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, struct yaffs_ext_tags *tags);
+int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
+int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state, u32 *seq_number);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_mtdif2_single.c b/fs/yaffs2-new/yaffs_mtdif2_single.c
new file mode 100644
index 0000000000..31aebb1082
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_mtdif2_single.c
@@ -0,0 +1,209 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* mtd interface for YAFFS2 */
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_mtdif2.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_direct.h"
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+
+
+/* NB For use with inband tags....
+ * We assume that the data buffer is of size total_bytes_per_chunk so that
+ * we can also use it to load the tags.
+ */
+int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
+ const u8 *data,
+ const struct yaffs_ext_tags *tags)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ struct mtd_oob_ops ops;
+ int retval = 0;
+ loff_t addr;
+ struct yaffs_packed_tags2 pt;
+ int packed_tags_size =
+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+ void *packed_tags_ptr =
+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
+ nand_chunk, data, tags);
+
+ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+
+ /* For yaffs2 writing there must be both data and tags.
+ * If we're using inband tags, then the tags are stuffed into
+ * the end of the data buffer.
+ */
+ if (!data || !tags)
+ BUG();
+ else if (dev->param.inband_tags) {
+ struct yaffs_packed_tags2_tags_only *pt2tp;
+
+ pt2tp =
+ (struct yaffs_packed_tags2_tags_only *)
+ (data + dev->data_bytes_per_chunk);
+ yaffs_pack_tags2_tags_only(pt2tp, tags);
+ } else {
+ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
+ }
+
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
+ ops.len = dev->param.total_bytes_per_chunk;
+ ops.ooboffs = 0;
+ ops.datbuf = (u8 *) data;
+ ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
+ retval = mtd->write_oob(mtd, addr, &ops);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
+ u8 *data, struct yaffs_ext_tags *tags)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ struct mtd_oob_ops ops;
+ size_t dummy;
+ int retval = 0;
+ int local_data = 0;
+ loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
+ struct yaffs_packed_tags2 pt;
+ int packed_tags_size =
+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
+ void *packed_tags_ptr =
+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
+ nand_chunk, data, tags);
+
+ if (dev->param.inband_tags && !data) {
+ local_data = 1;
+ data = yaffs_get_temp_buffer(dev);
+ }
+
+ if (dev->param.inband_tags || (data && !tags)) {
+ retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
+ &dummy, data);
+ } else if (tags) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = packed_tags_size;
+ ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
+ ops.ooboffs = 0;
+ ops.datbuf = data;
+ ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
+ retval = mtd->read_oob(mtd, addr, &ops);
+ }
+
+ if (dev->param.inband_tags && tags) {
+ struct yaffs_packed_tags2_tags_only *pt2tp;
+
+ pt2tp =
+ (struct yaffs_packed_tags2_tags_only *)
+ &data[dev->data_bytes_per_chunk];
+ yaffs_unpack_tags2_tags_only(tags, pt2tp);
+ } else if (tags) {
+ memcpy(packed_tags_ptr,
+ yaffs_dev_to_lc(dev)->spare_buffer,
+ packed_tags_size);
+ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
+ }
+
+ if (local_data)
+ yaffs_release_temp_buffer(dev, data);
+
+ if (tags && retval == -EBADMSG &&
+ tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
+ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ dev->n_ecc_unfixed++;
+ }
+ if (tags && retval == -EUCLEAN &&
+ tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
+ tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+ dev->n_ecc_fixed++;
+ }
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "nandmtd2_mark_block_bad %d", block_no);
+
+ retval =
+ mtd->block_markbad(mtd,
+ block_no * dev->param.chunks_per_block *
+ dev->param.total_bytes_per_chunk);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
+
+int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
+ enum yaffs_block_state *state, u32 * seq_number)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
+ retval =
+ mtd->block_isbad(mtd,
+ block_no * dev->param.chunks_per_block *
+ dev->param.total_bytes_per_chunk);
+
+ if (retval) {
+ yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
+
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ *seq_number = 0;
+ } else {
+ struct yaffs_ext_tags t;
+
+ nandmtd2_read_chunk_tags(dev, block_no *
+ dev->param.chunks_per_block, NULL, &t);
+
+ if (t.chunk_used) {
+ *seq_number = t.seq_number;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+ } else {
+ *seq_number = 0;
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ }
+ }
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "block is bad seq %d state %d", *seq_number, *state);
+
+ if (retval == 0)
+ return YAFFS_OK;
+
+ return YAFFS_FAIL;
+}
diff --git a/fs/yaffs2-new/yaffs_nameval.c b/fs/yaffs2-new/yaffs_nameval.c
new file mode 100644
index 0000000000..487b03e19f
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_nameval.c
@@ -0,0 +1,207 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 simple implementation of a name-value store assumes a small number of
+* values and fits into a small finite buffer.
+ *
+ * Each attribute is stored as a record:
+ * sizeof(int) bytes record size.
+ * strnlen+1 bytes name null terminated.
+ * nbytes value.
+ * ----------
+ * total size stored in record size
+ *
+ * This code has not been tested with unicode yet.
+ */
+
+#include "yaffs_nameval.h"
+
+#include "yportenv.h"
+
+static int nval_find(const char *xb, int xb_size, const YCHAR *name,
+ int *exist_size)
+{
+ int pos = 0;
+ int size;
+
+ memcpy(&size, xb, sizeof(int));
+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+ if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), name, size)) {
+ if (exist_size)
+ *exist_size = size;
+ return pos;
+ }
+ pos += size;
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
+ else
+ size = 0;
+ }
+ if (exist_size)
+ *exist_size = 0;
+ return -ENODATA;
+}
+
+static int nval_used(const char *xb, int xb_size)
+{
+ int pos = 0;
+ int size;
+
+ memcpy(&size, xb + pos, sizeof(int));
+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+ pos += size;
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
+ else
+ size = 0;
+ }
+ return pos;
+}
+
+int nval_del(char *xb, int xb_size, const YCHAR *name)
+{
+ int pos = nval_find(xb, xb_size, name, NULL);
+ int size;
+
+ if (pos < 0 || pos >= xb_size)
+ return -ENODATA;
+
+ /* Find size, shift rest over this record,
+ * then zero out the rest of buffer */
+ memcpy(&size, xb + pos, sizeof(int));
+ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
+ memset(xb + (xb_size - size), 0, size);
+ return 0;
+}
+
+int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
+ int bsize, int flags)
+{
+ int pos;
+ int namelen = strnlen(name, xb_size);
+ int reclen;
+ int size_exist = 0;
+ int space;
+ int start;
+
+ pos = nval_find(xb, xb_size, name, &size_exist);
+
+ if (flags & XATTR_CREATE && pos >= 0)
+ return -EEXIST;
+ if (flags & XATTR_REPLACE && pos < 0)
+ return -ENODATA;
+
+ start = nval_used(xb, xb_size);
+ space = xb_size - start + size_exist;
+
+ reclen = (sizeof(int) + namelen + 1 + bsize);
+
+ if (reclen > space)
+ return -ENOSPC;
+
+ if (pos >= 0) {
+ nval_del(xb, xb_size, name);
+ start = nval_used(xb, xb_size);
+ }
+
+ pos = start;
+
+ memcpy(xb + pos, &reclen, sizeof(int));
+ pos += sizeof(int);
+ strncpy((YCHAR *) (xb + pos), name, reclen);
+ pos += (namelen + 1);
+ memcpy(xb + pos, buf, bsize);
+ return 0;
+}
+
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+ int bsize)
+{
+ int pos = nval_find(xb, xb_size, name, NULL);
+ int size;
+
+ if (pos >= 0 && pos < xb_size) {
+
+ memcpy(&size, xb + pos, sizeof(int));
+ pos += sizeof(int); /* advance past record length */
+ size -= sizeof(int);
+
+ /* Advance over name string */
+ while (xb[pos] && size > 0 && pos < xb_size) {
+ pos++;
+ size--;
+ }
+ /*Advance over NUL */
+ pos++;
+ size--;
+
+ /* If bsize is zero then this is a size query.
+ * Return the size, but don't copy.
+ */
+ if (!bsize)
+ return size;
+
+ if (size <= bsize) {
+ memcpy(buf, xb + pos, size);
+ return size;
+ }
+ }
+ if (pos >= 0)
+ return -ERANGE;
+
+ return -ENODATA;
+}
+
+int nval_list(const char *xb, int xb_size, char *buf, int bsize)
+{
+ int pos = 0;
+ int size;
+ int name_len;
+ int ncopied = 0;
+ int filled = 0;
+
+ memcpy(&size, xb + pos, sizeof(int));
+ while (size > sizeof(int) &&
+ size <= xb_size &&
+ (pos + size) < xb_size &&
+ !filled) {
+ pos += sizeof(int);
+ size -= sizeof(int);
+ name_len = strnlen((YCHAR *) (xb + pos), size);
+ if (ncopied + name_len + 1 < bsize) {
+ memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
+ buf += name_len;
+ *buf = '\0';
+ buf++;
+ if (sizeof(YCHAR) > 1) {
+ *buf = '\0';
+ buf++;
+ }
+ ncopied += (name_len + 1);
+ } else {
+ filled = 1;
+ }
+ pos += size;
+ if (pos < xb_size - sizeof(int))
+ memcpy(&size, xb + pos, sizeof(int));
+ else
+ size = 0;
+ }
+ return ncopied;
+}
+
+int nval_hasvalues(const char *xb, int xb_size)
+{
+ return nval_used(xb, xb_size) > 0;
+}
diff --git a/fs/yaffs2-new/yaffs_nameval.h b/fs/yaffs2-new/yaffs_nameval.h
new file mode 100644
index 0000000000..951e64f872
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_nameval.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAMEVAL_H__
+#define __NAMEVAL_H__
+
+#include "yportenv.h"
+
+int nval_del(char *xb, int xb_size, const YCHAR * name);
+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
+ int bsize, int flags);
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+ int bsize);
+int nval_list(const char *xb, int xb_size, char *buf, int bsize);
+int nval_hasvalues(const char *xb, int xb_size);
+#endif
diff --git a/fs/yaffs2-new/yaffs_nand.c b/fs/yaffs2-new/yaffs_nand.c
new file mode 100644
index 0000000000..165d01004d
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_nand.c
@@ -0,0 +1,120 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+
+#include "yaffs_getblockinfo.h"
+#include "yaffs_summary.h"
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+ u8 *buffer, struct yaffs_ext_tags *tags)
+{
+ int result;
+ struct yaffs_ext_tags local_tags;
+ int flash_chunk = nand_chunk - dev->chunk_offset;
+
+ dev->n_page_reads++;
+
+ /* If there are no tags provided use local tags. */
+ if (!tags)
+ tags = &local_tags;
+
+ if (dev->param.read_chunk_tags_fn)
+ result =
+ dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
+ tags);
+ else
+ result = yaffs_tags_compat_rd(dev,
+ flash_chunk, buffer, tags);
+ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
+
+ struct yaffs_block_info *bi;
+ bi = yaffs_get_block_info(dev,
+ nand_chunk /
+ dev->param.chunks_per_block);
+ yaffs_handle_chunk_error(dev, bi);
+ }
+ return result;
+}
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *buffer, struct yaffs_ext_tags *tags)
+{
+ int result;
+ int flash_chunk = nand_chunk - dev->chunk_offset;
+
+ dev->n_page_writes++;
+
+ if (tags) {
+ tags->seq_number = dev->seq_number;
+ tags->chunk_used = 1;
+ yaffs_trace(YAFFS_TRACE_WRITE,
+ "Writing chunk %d tags %d %d",
+ nand_chunk, tags->obj_id, tags->chunk_id);
+ } else {
+ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
+ BUG();
+ return YAFFS_FAIL;
+ }
+
+ if (dev->param.write_chunk_tags_fn)
+ result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
+ buffer, tags);
+ else
+ result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags);
+
+ yaffs_summary_add(dev, tags, nand_chunk);
+
+ return result;
+}
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+ block_no -= dev->block_offset;
+ if (dev->param.bad_block_fn)
+ return dev->param.bad_block_fn(dev, block_no);
+
+ return yaffs_tags_compat_mark_bad(dev, block_no);
+}
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number)
+{
+ block_no -= dev->block_offset;
+ if (dev->param.query_block_fn)
+ return dev->param.query_block_fn(dev, block_no, state,
+ seq_number);
+
+ return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
+}
+
+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
+{
+ int result;
+
+ flash_block -= dev->block_offset;
+ dev->n_erasures++;
+ result = dev->param.erase_fn(dev, flash_block);
+ return result;
+}
+
+int yaffs_init_nand(struct yaffs_dev *dev)
+{
+ if (dev->param.initialise_flash_fn)
+ return dev->param.initialise_flash_fn(dev);
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_nand.h b/fs/yaffs2-new/yaffs_nand.h
new file mode 100644
index 0000000000..71346627fc
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_nand.h
@@ -0,0 +1,38 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+ u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ unsigned *seq_number);
+
+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
+
+int yaffs_init_nand(struct yaffs_dev *dev);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_packedtags2.c b/fs/yaffs2-new/yaffs_packedtags2.c
new file mode 100644
index 0000000000..820bc41023
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_packedtags2.c
@@ -0,0 +1,181 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunk_id */
+
+#define EXTRA_HEADER_INFO_FLAG 0x80000000
+#define EXTRA_SHRINK_FLAG 0x40000000
+#define EXTRA_SHADOWS_FLAG 0x20000000
+#define EXTRA_SPARE_FLAGS 0x10000000
+
+#define ALL_EXTRA_FLAGS 0xf0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
+
+static void yaffs_dump_packed_tags2_tags_only(
+ const struct yaffs_packed_tags2_tags_only *ptt)
+{
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "packed tags obj %d chunk %d byte %d seq %d",
+ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
+}
+
+static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
+{
+ yaffs_dump_packed_tags2_tags_only(&pt->t);
+}
+
+static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
+{
+ yaffs_trace(YAFFS_TRACE_MTD,
+ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
+ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
+ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
+ t->seq_number);
+
+}
+
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
+ const struct yaffs_ext_tags *t)
+{
+ ptt->chunk_id = t->chunk_id;
+ ptt->seq_number = t->seq_number;
+ ptt->n_bytes = t->n_bytes;
+ ptt->obj_id = t->obj_id;
+
+ if (t->chunk_id == 0 && t->extra_available) {
+ /* Store the extra header info instead */
+ /* We save the parent object in the chunk_id */
+ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
+ if (t->extra_is_shrink)
+ ptt->chunk_id |= EXTRA_SHRINK_FLAG;
+ if (t->extra_shadows)
+ ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
+
+ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
+
+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+ ptt->n_bytes = t->extra_equiv_id;
+ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+ ptt->n_bytes = t->extra_length;
+ else
+ ptt->n_bytes = 0;
+ }
+
+ yaffs_dump_packed_tags2_tags_only(ptt);
+ yaffs_dump_tags2(t);
+}
+
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+ const struct yaffs_ext_tags *t, int tags_ecc)
+{
+ yaffs_pack_tags2_tags_only(&pt->t, t);
+
+ if (tags_ecc)
+ yaffs_ecc_calc_other((unsigned char *)&pt->t,
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &pt->ecc);
+}
+
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+ struct yaffs_packed_tags2_tags_only *ptt)
+{
+ memset(t, 0, sizeof(struct yaffs_ext_tags));
+
+ if (ptt->seq_number == 0xffffffff)
+ return;
+
+ t->block_bad = 0;
+ t->chunk_used = 1;
+ t->obj_id = ptt->obj_id;
+ t->chunk_id = ptt->chunk_id;
+ t->n_bytes = ptt->n_bytes;
+ t->is_deleted = 0;
+ t->serial_number = 0;
+ t->seq_number = ptt->seq_number;
+
+ /* Do extra header info stuff */
+ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
+ t->chunk_id = 0;
+ t->n_bytes = 0;
+
+ t->extra_available = 1;
+ t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
+ t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
+ t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
+ t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
+ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+
+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+ t->extra_equiv_id = ptt->n_bytes;
+ else
+ t->extra_length = ptt->n_bytes;
+ }
+ yaffs_dump_packed_tags2_tags_only(ptt);
+ yaffs_dump_tags2(t);
+}
+
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+ int tags_ecc)
+{
+ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+ if (pt->t.seq_number != 0xffffffff && tags_ecc) {
+ /* Chunk is in use and we need to do ECC */
+
+ struct yaffs_ecc_other ecc;
+ int result;
+ yaffs_ecc_calc_other((unsigned char *)&pt->t,
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &ecc);
+ result =
+ yaffs_ecc_correct_other((unsigned char *)&pt->t,
+ sizeof(struct yaffs_packed_tags2_tags_only),
+ &pt->ecc, &ecc);
+ switch (result) {
+ case 0:
+ ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+ break;
+ case 1:
+ ecc_result = YAFFS_ECC_RESULT_FIXED;
+ break;
+ case -1:
+ ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ break;
+ default:
+ ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+ }
+ }
+ yaffs_unpack_tags2_tags_only(t, &pt->t);
+
+ t->ecc_result = ecc_result;
+
+ yaffs_dump_packed_tags2(pt);
+ yaffs_dump_tags2(t);
+}
diff --git a/fs/yaffs2-new/yaffs_packedtags2.h b/fs/yaffs2-new/yaffs_packedtags2.h
new file mode 100644
index 0000000000..675e719460
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_packedtags2.h
@@ -0,0 +1,47 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+struct yaffs_packed_tags2_tags_only {
+ unsigned seq_number;
+ unsigned obj_id;
+ unsigned chunk_id;
+ unsigned n_bytes;
+};
+
+struct yaffs_packed_tags2 {
+ struct yaffs_packed_tags2_tags_only t;
+ struct yaffs_ecc_other ecc;
+};
+
+/* Full packed tags with ECC, used for oob tags */
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+ const struct yaffs_ext_tags *t, int tags_ecc);
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+ int tags_ecc);
+
+/* Only the tags part (no ECC for use with inband tags */
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
+ const struct yaffs_ext_tags *t);
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+ struct yaffs_packed_tags2_tags_only *pt);
+#endif
diff --git a/fs/yaffs2-new/yaffs_qsort.c b/fs/yaffs2-new/yaffs_qsort.c
new file mode 100644
index 0000000000..187519fbdb
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_qsort.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "yportenv.h"
+/* #include <linux/string.h> */
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) do { \
+ long i = (n) / sizeof (TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+} while (0)
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+ if (swaptype <= 1)
+ swapcode(long, a, b, n);
+ else
+ swapcode(char, a, b, n);
+}
+
+#define yswap(a, b) do { \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype); \
+} while (0)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
+ : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
+}
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+yaffs_qsort(void *aa, size_t n, size_t es,
+ int (*cmp)(const void *, const void *))
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+ register char *a = aa;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ yswap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp);
+ pm = med3(pm - d, pm, pm + d, cmp);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp);
+ }
+ pm = med3(pl, pm, pn, cmp);
+ }
+ yswap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ yswap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ yswap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ yswap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ yswap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min((long)(pd - pc), (long)(pn - pd - es));
+ vecswap(pb, pn - r, r);
+ r = pb - pa;
+ if (r > es)
+ yaffs_qsort(a, r / es, es, cmp);
+ r = pd - pc;
+ if (r > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* yaffs_qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/fs/yaffs2-new/yaffs_summary.c b/fs/yaffs2-new/yaffs_summary.c
new file mode 100644
index 0000000000..4cf1711177
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_summary.c
@@ -0,0 +1,252 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* Summaries write the useful part of the tags for the chunks in a block into an
+ * an array which is written to the last n chunks of the block.
+ * Reading the summaries gives all the tags for the block in one read. Much
+ * faster.
+ *
+ * Chunks holding summaries are marked with tags making it look like
+ * they are part of a fake file.
+ *
+ * The summary could also be used during gc.
+ *
+ */
+
+#include "yaffs_summary.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_bitmap.h"
+
+/* Summary tags don't need the sequence number because that is redundant. */
+struct yaffs_summary_tags {
+ unsigned obj_id;
+ unsigned chunk_id;
+ unsigned n_bytes;
+};
+
+static void yaffs_summary_clear(struct yaffs_dev *dev)
+{
+ if(!dev->sum_tags)
+ return;
+ memset(dev->sum_tags, 0, dev->chunks_per_summary *
+ sizeof(struct yaffs_summary_tags));
+}
+
+int yaffs_summary_init(struct yaffs_dev *dev)
+{
+ int sum_bytes;
+ int chunks_used; /* Number of chunks used by summary */
+
+ sum_bytes = dev->param.chunks_per_block *
+ sizeof(struct yaffs_summary_tags);
+
+ chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
+ dev->data_bytes_per_chunk;
+ dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
+ dev->sum_tags = kmalloc(sizeof(struct yaffs_summary_tags) *
+ dev->chunks_per_summary, GFP_NOFS);
+ dev->gc_sum_tags = kmalloc(sizeof(struct yaffs_summary_tags) *
+ dev->chunks_per_summary, GFP_NOFS);
+ if(!dev->sum_tags || !dev->gc_sum_tags) {
+ kfree(dev->sum_tags);
+ kfree(dev->gc_sum_tags);
+ return YAFFS_FAIL;
+ }
+
+ yaffs_summary_clear(dev);
+
+ return YAFFS_OK;
+}
+
+void yaffs_summary_deinit(struct yaffs_dev *dev)
+{
+ kfree(dev->sum_tags);
+ dev->sum_tags = NULL;
+ kfree(dev->gc_sum_tags);
+ dev->gc_sum_tags = NULL;
+ dev->chunks_per_summary = 0;
+}
+
+static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
+{
+ struct yaffs_ext_tags tags;
+ u8 *buffer;
+ u8 *sum_buffer = (u8 *)dev->sum_tags;
+ int n_bytes;
+ int chunk_in_nand;
+ int chunk_in_block;
+ int result;
+ int this_tx;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+
+ buffer = yaffs_get_temp_buffer(dev);
+ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
+ memset(&tags, 0, sizeof(struct yaffs_ext_tags));
+ tags.obj_id = YAFFS_OBJECTID_SUMMARY;
+ tags.chunk_id = 1;
+ chunk_in_block = dev->chunks_per_summary;
+ chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
+ dev-> chunks_per_summary;
+ do {
+ this_tx = n_bytes;
+ if (this_tx > dev->data_bytes_per_chunk)
+ this_tx = dev->data_bytes_per_chunk;
+ memcpy(buffer, sum_buffer, this_tx);
+ tags.n_bytes = this_tx;
+ result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
+ buffer, &tags);
+
+ if (result != YAFFS_OK)
+ break;
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+ dev->n_free_chunks--;
+
+ n_bytes -= this_tx;
+ sum_buffer += this_tx;
+ chunk_in_nand++;
+ chunk_in_block++;
+ tags.chunk_id++;
+ } while (result == YAFFS_OK && n_bytes > 0);
+ yaffs_release_temp_buffer(dev, buffer);
+
+
+ if (result == YAFFS_OK)
+ bi->has_summary = 1;
+
+
+ return result;
+}
+
+int yaffs_summary_read(struct yaffs_dev *dev,
+ struct yaffs_summary_tags *st,
+ int blk)
+{
+ struct yaffs_ext_tags tags;
+ u8 *buffer;
+ u8 *sum_buffer = (u8 *)st;
+ int n_bytes;
+ int chunk_id;
+ int chunk_in_nand;
+ int chunk_in_block;
+ int result;
+ int this_tx;
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+
+ buffer = yaffs_get_temp_buffer(dev);
+ n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
+ chunk_in_block = dev->chunks_per_summary;
+ chunk_in_nand = blk * dev->param.chunks_per_block +
+ dev->chunks_per_summary;
+ chunk_id = 1;
+ do {
+ this_tx = n_bytes;
+ if(this_tx > dev->data_bytes_per_chunk)
+ this_tx = dev->data_bytes_per_chunk;
+ result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
+ buffer, &tags);
+
+ if (tags.chunk_id != chunk_id ||
+ tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
+ tags.chunk_used == 0 ||
+ tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+ this_tx != tags.n_bytes)
+ result = YAFFS_FAIL;
+ if (result != YAFFS_OK)
+ break;
+
+ if (st == dev->sum_tags) {
+ /* If we're scanning then update the block info */
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+ }
+
+ memcpy(sum_buffer, buffer, this_tx);
+ n_bytes -= this_tx;
+ sum_buffer += this_tx;
+ chunk_in_nand++;
+ chunk_in_block++;
+ chunk_id++;
+ } while (result == YAFFS_OK && n_bytes > 0);
+ yaffs_release_temp_buffer(dev, buffer);
+
+ if (st == dev->sum_tags && result == YAFFS_OK)
+ bi->has_summary = 1;
+
+ return result;
+}
+int yaffs_summary_add(struct yaffs_dev *dev,
+ struct yaffs_ext_tags *tags,
+ int chunk_in_nand)
+{
+ struct yaffs_packed_tags2_tags_only tags_only;
+ struct yaffs_summary_tags *sum_tags;
+ int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
+ int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
+
+ if(!dev->sum_tags)
+ return YAFFS_OK;
+
+ if(chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+ yaffs_pack_tags2_tags_only(&tags_only, tags);
+ sum_tags = &dev->sum_tags[chunk_in_block];
+ sum_tags->chunk_id = tags_only.chunk_id;
+ sum_tags->n_bytes = tags_only.n_bytes;
+ sum_tags->obj_id = tags_only.obj_id;
+
+ if(chunk_in_block == dev->chunks_per_summary - 1) {
+ /* Time to write out the summary */
+ yaffs_summary_write(dev, block_in_nand);
+ yaffs_summary_clear(dev);
+ yaffs_skip_rest_of_block(dev);
+ }
+ }
+ return YAFFS_OK;
+}
+
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+ struct yaffs_ext_tags *tags,
+ int chunk_in_block)
+{
+ struct yaffs_packed_tags2_tags_only tags_only;
+ struct yaffs_summary_tags *sum_tags;
+ if(chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+ sum_tags = &dev->sum_tags[chunk_in_block];
+ tags_only.chunk_id = sum_tags->chunk_id;
+ tags_only.n_bytes = sum_tags->n_bytes;
+ tags_only.obj_id = sum_tags->obj_id;
+ yaffs_unpack_tags2_tags_only(tags, &tags_only);
+ return YAFFS_OK;
+ }
+ return YAFFS_FAIL;
+}
+
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
+{
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+ int i;
+
+ if (!bi->has_summary)
+ return;
+
+ for (i = dev->chunks_per_summary; i < dev->param.chunks_per_block; i++) {
+ if( yaffs_check_chunk_bit(dev, blk, i)) {
+ yaffs_clear_chunk_bit(dev, blk, i);
+ bi->pages_in_use--;
+ dev->n_free_chunks++;
+ }
+ }
+
+}
diff --git a/fs/yaffs2-new/yaffs_summary.h b/fs/yaffs2-new/yaffs_summary.h
new file mode 100644
index 0000000000..be141d0733
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_summary.h
@@ -0,0 +1,37 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_SUMMARY_H__
+#define __YAFFS_SUMMARY_H__
+
+#include "yaffs_packedtags2.h"
+
+
+int yaffs_summary_init(struct yaffs_dev *dev);
+void yaffs_summary_deinit(struct yaffs_dev *dev);
+
+int yaffs_summary_add(struct yaffs_dev *dev,
+ struct yaffs_ext_tags *tags,
+ int chunk_in_block);
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+ struct yaffs_ext_tags *tags,
+ int chunk_in_block);
+int yaffs_summary_read(struct yaffs_dev *dev,
+ struct yaffs_summary_tags *st,
+ int blk);
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
+
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_tagscompat.c b/fs/yaffs2-new/yaffs_tagscompat.c
new file mode 100644
index 0000000000..9ac5896da3
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_tagscompat.c
@@ -0,0 +1,407 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_trace.h"
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+
+
+/********** Tags ECC calculations *********/
+
+void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare)
+{
+ yaffs_ecc_calc(data, spare->ecc1);
+ yaffs_ecc_calc(&data[256], spare->ecc2);
+}
+
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
+{
+ /* Calculate an ecc */
+ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+ unsigned i, j;
+ unsigned ecc = 0;
+ unsigned bit = 0;
+
+ tags->ecc = 0;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 1; j & 0xff; j <<= 1) {
+ bit++;
+ if (b[i] & j)
+ ecc ^= bit;
+ }
+ }
+ tags->ecc = ecc;
+}
+
+int yaffs_check_tags_ecc(struct yaffs_tags *tags)
+{
+ unsigned ecc = tags->ecc;
+
+ yaffs_calc_tags_ecc(tags);
+
+ ecc ^= tags->ecc;
+
+ if (ecc && ecc <= 64) {
+ /* TODO: Handle the failure better. Retire? */
+ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+
+ ecc--;
+
+ b[ecc / 8] ^= (1 << (ecc & 7));
+
+ /* Now recvalc the ecc */
+ yaffs_calc_tags_ecc(tags);
+
+ return 1; /* recovered error */
+ } else if (ecc) {
+ /* Wierd ecc failure value */
+ /* TODO Need to do somethiong here */
+ return -1; /* unrecovered error */
+ }
+ return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+ struct yaffs_tags *tags_ptr)
+{
+ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+
+ yaffs_calc_tags_ecc(tags_ptr);
+
+ spare_ptr->tb0 = tu->as_bytes[0];
+ spare_ptr->tb1 = tu->as_bytes[1];
+ spare_ptr->tb2 = tu->as_bytes[2];
+ spare_ptr->tb3 = tu->as_bytes[3];
+ spare_ptr->tb4 = tu->as_bytes[4];
+ spare_ptr->tb5 = tu->as_bytes[5];
+ spare_ptr->tb6 = tu->as_bytes[6];
+ spare_ptr->tb7 = tu->as_bytes[7];
+}
+
+static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
+ struct yaffs_spare *spare_ptr,
+ struct yaffs_tags *tags_ptr)
+{
+ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+ int result;
+
+ tu->as_bytes[0] = spare_ptr->tb0;
+ tu->as_bytes[1] = spare_ptr->tb1;
+ tu->as_bytes[2] = spare_ptr->tb2;
+ tu->as_bytes[3] = spare_ptr->tb3;
+ tu->as_bytes[4] = spare_ptr->tb4;
+ tu->as_bytes[5] = spare_ptr->tb5;
+ tu->as_bytes[6] = spare_ptr->tb6;
+ tu->as_bytes[7] = spare_ptr->tb7;
+
+ result = yaffs_check_tags_ecc(tags_ptr);
+ if (result > 0)
+ dev->n_tags_ecc_fixed++;
+ else if (result < 0)
+ dev->n_tags_ecc_unfixed++;
+}
+
+static void yaffs_spare_init(struct yaffs_spare *spare)
+{
+ memset(spare, 0xff, sizeof(struct yaffs_spare));
+}
+
+static int yaffs_wr_nand(struct yaffs_dev *dev,
+ int nand_chunk, const u8 *data,
+ struct yaffs_spare *spare)
+{
+ if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>> yaffs chunk %d is not valid",
+ nand_chunk);
+ return YAFFS_FAIL;
+ }
+
+ return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
+}
+
+static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data,
+ struct yaffs_spare *spare,
+ enum yaffs_ecc_result *ecc_result,
+ int correct_errors)
+{
+ int ret_val;
+ struct yaffs_spare local_spare;
+
+ if (!spare) {
+ /* If we don't have a real spare, then we use a local one. */
+ /* Need this for the calculation of the ecc */
+ spare = &local_spare;
+ }
+
+ if (!dev->param.use_nand_ecc) {
+ ret_val =
+ dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
+ if (data && correct_errors) {
+ /* Do ECC correction */
+ /* Todo handle any errors */
+ int ecc_result1, ecc_result2;
+ u8 calc_ecc[3];
+
+ yaffs_ecc_calc(data, calc_ecc);
+ ecc_result1 =
+ yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
+ yaffs_ecc_calc(&data[256], calc_ecc);
+ ecc_result2 =
+ yaffs_ecc_correct(&data[256], spare->ecc2,
+ calc_ecc);
+
+ if (ecc_result1 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error fix performed on chunk %d:0",
+ nand_chunk);
+ dev->n_ecc_fixed++;
+ } else if (ecc_result1 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error unfixed on chunk %d:0",
+ nand_chunk);
+ dev->n_ecc_unfixed++;
+ }
+
+ if (ecc_result2 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error fix performed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_fixed++;
+ } else if (ecc_result2 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>yaffs ecc error unfixed on chunk %d:1",
+ nand_chunk);
+ dev->n_ecc_unfixed++;
+ }
+
+ if (ecc_result1 || ecc_result2) {
+ /* We had a data problem on this page */
+ yaffs_handle_rd_data_error(dev, nand_chunk);
+ }
+
+ if (ecc_result1 < 0 || ecc_result2 < 0)
+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ else if (ecc_result1 > 0 || ecc_result2 > 0)
+ *ecc_result = YAFFS_ECC_RESULT_FIXED;
+ else
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+ }
+ } else {
+ /* Must allocate enough memory for spare+2*sizeof(int) */
+ /* for ecc results from device. */
+ struct yaffs_nand_spare nspare;
+
+ memset(&nspare, 0, sizeof(nspare));
+
+ ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
+ (struct yaffs_spare *)
+ &nspare);
+ memcpy(spare, &nspare, sizeof(struct yaffs_spare));
+ if (data && correct_errors) {
+ if (nspare.eccres1 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>mtd ecc error fix performed on chunk %d:0",
+ nand_chunk);
+ } else if (nspare.eccres1 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>mtd ecc error unfixed on chunk %d:0",
+ nand_chunk);
+ }
+
+ if (nspare.eccres2 > 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>mtd ecc error fix performed on chunk %d:1",
+ nand_chunk);
+ } else if (nspare.eccres2 < 0) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "**>>mtd ecc error unfixed on chunk %d:1",
+ nand_chunk);
+ }
+
+ if (nspare.eccres1 || nspare.eccres2) {
+ /* We had a data problem on this page */
+ yaffs_handle_rd_data_error(dev, nand_chunk);
+ }
+
+ if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
+ *ecc_result = YAFFS_ECC_RESULT_FIXED;
+ else
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+ }
+ }
+ return ret_val;
+}
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
+{
+ int flash_block = nand_chunk / dev->param.chunks_per_block;
+
+ /* Mark the block for retirement */
+ yaffs_get_block_info(dev, flash_block + dev->block_offset)->
+ needs_retiring = 1;
+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ "**>>Block %d marked for retirement",
+ flash_block);
+
+ /* TODO:
+ * Just do a garbage collection on the affected block
+ * then retire the block
+ * NB recursion
+ */
+}
+
+int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data, const struct yaffs_ext_tags *ext_tags)
+{
+ struct yaffs_spare spare;
+ struct yaffs_tags tags;
+
+ yaffs_spare_init(&spare);
+
+ if (ext_tags->is_deleted)
+ spare.page_status = 0;
+ else {
+ tags.obj_id = ext_tags->obj_id;
+ tags.chunk_id = ext_tags->chunk_id;
+
+ tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
+
+ if (dev->data_bytes_per_chunk >= 1024)
+ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
+ else
+ tags.n_bytes_msb = 3;
+
+ tags.serial_number = ext_tags->serial_number;
+
+ if (!dev->param.use_nand_ecc && data)
+ yaffs_calc_ecc(data, &spare);
+
+ yaffs_load_tags_to_spare(&spare, &tags);
+ }
+ return yaffs_wr_nand(dev, nand_chunk, data, &spare);
+}
+
+int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data, struct yaffs_ext_tags *ext_tags)
+{
+ struct yaffs_spare spare;
+ struct yaffs_tags tags;
+ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+ static struct yaffs_spare spare_ff;
+ static int init;
+ int deleted;
+
+ if (!init) {
+ memset(&spare_ff, 0xff, sizeof(spare_ff));
+ init = 1;
+ }
+
+ if (!yaffs_rd_chunk_nand(dev, nand_chunk,
+ data, &spare, &ecc_result, 1))
+ return YAFFS_FAIL;
+
+ /* ext_tags may be NULL */
+ if (!ext_tags)
+ return YAFFS_OK;
+
+ deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
+
+ ext_tags->is_deleted = deleted;
+ ext_tags->ecc_result = ecc_result;
+ ext_tags->block_bad = 0; /* We're reading it */
+ /* therefore it is not a bad block */
+ ext_tags->chunk_used =
+ memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
+
+ if (ext_tags->chunk_used) {
+ yaffs_get_tags_from_spare(dev, &spare, &tags);
+ ext_tags->obj_id = tags.obj_id;
+ ext_tags->chunk_id = tags.chunk_id;
+ ext_tags->n_bytes = tags.n_bytes_lsb;
+
+ if (dev->data_bytes_per_chunk >= 1024)
+ ext_tags->n_bytes |=
+ (((unsigned)tags.n_bytes_msb) << 10);
+
+ ext_tags->serial_number = tags.serial_number;
+ }
+
+ return YAFFS_OK;
+}
+
+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
+{
+ struct yaffs_spare spare;
+
+ memset(&spare, 0xff, sizeof(struct yaffs_spare));
+
+ spare.block_status = 'Y';
+
+ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
+ &spare);
+ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
+ NULL, &spare);
+
+ return YAFFS_OK;
+}
+
+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number)
+{
+ struct yaffs_spare spare0, spare1;
+ static struct yaffs_spare spare_ff;
+ static int init;
+ enum yaffs_ecc_result dummy;
+
+ if (!init) {
+ memset(&spare_ff, 0xff, sizeof(spare_ff));
+ init = 1;
+ }
+
+ *seq_number = 0;
+
+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
+ &spare0, &dummy, 1);
+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
+ NULL, &spare1, &dummy, 1);
+
+ if (hweight8(spare0.block_status & spare1.block_status) < 7)
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ else
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_tagscompat.h b/fs/yaffs2-new/yaffs_tagscompat.h
new file mode 100644
index 0000000000..b3c6655772
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_tagscompat.h
@@ -0,0 +1,36 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+#include "yaffs_guts.h"
+int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+ int nand_chunk,
+ const u8 *data, const struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+ int nand_chunk,
+ u8 *data, struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+ int block_no,
+ enum yaffs_block_state *state,
+ u32 *seq_number);
+
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
+int yaffs_check_tags_ecc(struct yaffs_tags *tags);
+int yaffs_count_bits(u8 byte);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_trace.h b/fs/yaffs2-new/yaffs_trace.h
new file mode 100644
index 0000000000..fd26054d39
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_trace.h
@@ -0,0 +1,57 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YTRACE_H__
+#define __YTRACE_H__
+
+extern unsigned int yaffs_trace_mask;
+extern unsigned int yaffs_wr_attempts;
+
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+
+#define YAFFS_TRACE_OS 0x00000002
+#define YAFFS_TRACE_ALLOCATE 0x00000004
+#define YAFFS_TRACE_SCAN 0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
+#define YAFFS_TRACE_ERASE 0x00000020
+#define YAFFS_TRACE_GC 0x00000040
+#define YAFFS_TRACE_WRITE 0x00000080
+#define YAFFS_TRACE_TRACING 0x00000100
+#define YAFFS_TRACE_DELETION 0x00000200
+#define YAFFS_TRACE_BUFFERS 0x00000400
+#define YAFFS_TRACE_NANDACCESS 0x00000800
+#define YAFFS_TRACE_GC_DETAIL 0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
+#define YAFFS_TRACE_MTD 0x00004000
+#define YAFFS_TRACE_CHECKPOINT 0x00008000
+
+#define YAFFS_TRACE_VERIFY 0x00010000
+#define YAFFS_TRACE_VERIFY_NAND 0x00020000
+#define YAFFS_TRACE_VERIFY_FULL 0x00040000
+#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
+
+#define YAFFS_TRACE_SYNC 0x00100000
+#define YAFFS_TRACE_BACKGROUND 0x00200000
+#define YAFFS_TRACE_LOCK 0x00400000
+#define YAFFS_TRACE_MOUNT 0x00800000
+
+#define YAFFS_TRACE_ERROR 0x40000000
+#define YAFFS_TRACE_BUG 0x80000000
+#define YAFFS_TRACE_ALWAYS 0xf0000000
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_uboot.c b/fs/yaffs2-new/yaffs_uboot.c
new file mode 100644
index 0000000000..171bb7bd86
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_uboot.c
@@ -0,0 +1,258 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * yaffscfg.c The configuration for the "direct" use of yaffs in U-boot.
+ *
+ */
+
+#include <common.h>
+#include "malloc.h"
+
+#include "yaffscfg.h"
+#include "yaffsfs_errno.h"
+
+#include "yportenv.h"
+#include "yaffsfs.h"
+#include "yaffs_trace.h"
+
+void yaffsfs_Lock(void)
+{
+}
+
+void yaffsfs_Unlock(void)
+{
+}
+
+void *yaffs_malloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ printf("%s failed to allocate %u bytes!\n", __FUNCTION__, (unsigned int)size);
+ return ptr;
+}
+
+void yaffs_free(void *ptr)
+{
+ free(ptr);
+}
+
+u32 yaffsfs_CurrentTime(void)
+{
+ return 0;
+}
+
+unsigned int yaffs_wr_attempts;
+unsigned int yaffs_trace_mask = 0;
+
+void yaffs_startup(void)
+{
+ yaffs_trace_mask = YAFFS_TRACE_ERROR | YAFFS_TRACE_BUG | YAFFS_TRACE_ALWAYS;
+ yaffsfs_initialise();
+}
+
+int cmd_yaffs_mount(const char *mp)
+{
+ int retval;
+ char *p;
+
+ yaffsfs_set_error(0);
+ yaffs_startup();
+ retval = yaffsfs_mount(mp);
+ if (retval == -1) {
+ retval = yaffsfs_get_error(&p);
+ printf("Failed: %s\n", p);
+ }
+ return yaffsfs_get_error(NULL);
+}
+
+int cmd_yaffs_umount(char *mp)
+{
+ char *p;
+ int retval;
+
+ yaffsfs_set_error(0);
+ if (yaffsfs_unmount(mp) == -1) {
+ retval = yaffsfs_get_error(&p);
+ printf("Failed: %s\n", p);
+ }
+ return yaffsfs_get_error(NULL);
+}
+
+int cmd_yaffs_ls(const char *mountpt, int longlist)
+{
+ int i, ret;
+ yaffs_DIR *d;
+ yaffs_dirent *de;
+ struct yaffs_stat stat;
+ char tempstr[255];
+ char *p;
+
+ yaffsfs_set_error(0);
+
+ d = yaffs_opendir(mountpt);
+
+ if(!d)
+ {
+ ret = yaffsfs_get_error(&p);
+ printf("%s: %s\n", mountpt, p);
+ return ret;
+ }
+ else
+ {
+ for(i = 0; (de = yaffs_readdir(d)) != NULL; i++)
+ {
+ if (longlist)
+ {
+ sprintf(tempstr, "%s/%s", mountpt, de->d_name);
+ yaffs_stat(tempstr, &stat);
+ printf("%-25s\t%7ld\n",de->d_name, stat.st_size);
+ }
+ else
+ {
+ printf("%s\n",de->d_name);
+ }
+ }
+ }
+ return 0;
+}
+
+int cmd_yaffs_df(const char *path, loff_t *size)
+{
+ loff_t free_space;
+ int ret = 0;
+ char *p;
+
+ yaffsfs_set_error(0);
+
+ free_space = yaffs_freespace(path);
+ if (free_space == -1) {
+ ret = yaffsfs_get_error(&p);
+ printf("Failed: %s\n", p);
+ } else
+ *size = free_space;
+
+ return ret;
+}
+
+int cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
+{
+ int h, ret;
+ char *p;
+
+ yaffsfs_set_error(0);
+ printf ("Copy 0x%p to %s ... ", addr, fn);
+ h = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
+ if (h >= 0) {
+
+ yaffs_write(h,addr,size);
+ yaffs_close(h);
+
+ }
+
+ ret = yaffsfs_get_error(&p);
+ if (ret)
+ printf("[Failed: %s]\n", p);
+ else
+ printf("[DONE]\n");
+
+ return ret;
+}
+
+int cmd_yaffs_mread_file(char *fn, char *addr, long *size)
+{
+ int h, ret;
+ struct yaffs_stat s;
+ char *p;
+
+ yaffsfs_set_error(0);
+ printf ("Copy %s to 0x%p... ", fn, addr);
+
+ yaffs_stat(fn,&s);
+ h = yaffs_open(fn, O_RDWR,0);
+ if (h<0) {
+ yaffsfs_set_error(-ENOENT);
+ } else {
+ yaffs_read(h,addr,(int)s.st_size);
+ yaffs_close(h);
+ }
+
+ ret = yaffsfs_get_error(&p);
+ if (ret)
+ printf("[Failed: %s]\n", p);
+ else {
+ printf("[DONE]\n");
+ *size = s.st_size;
+ }
+
+ return ret;
+}
+
+int cmd_yaffs_mkdir(const char *dir)
+{
+ int ret;
+ char *p;
+
+ yaffsfs_set_error(0);
+ ret = yaffs_mkdir(dir, 0);
+ if (ret < 0) {
+ ret = yaffsfs_get_error(&p);
+ printf("[Failed: %p]\n", p);
+ }
+ return ret;
+}
+
+int cmd_yaffs_rmdir(const char *dir)
+{
+ int ret;
+ char *p;
+
+ yaffsfs_set_error(0);
+ ret = yaffs_rmdir(dir);
+ if (ret < 0) {
+ ret = yaffsfs_get_error(&p);
+ printf("[Failed: %s]\n", p);
+ }
+ return ret;
+}
+
+int cmd_yaffs_rm(const char *path)
+{
+ int ret;
+ char *p;
+
+ yaffsfs_set_error(0);
+ ret = yaffs_unlink(path);
+ if (ret < 0) {
+ ret = yaffsfs_get_error(&p);
+ printf("[Failed: %s]\n", p);
+ }
+ return ret;
+}
+
+int cmd_yaffs_mv(const char *oldPath, const char *newPath)
+{
+ int ret;
+ char *p;
+
+ yaffsfs_set_error(0);
+ ret = yaffs_rename(newPath, oldPath);
+
+ if (ret < 0) {
+ ret = yaffsfs_get_error(&p);
+ printf("[Failed: %s]\n", p);
+ }
+ return ret;
+}
diff --git a/fs/yaffs2-new/yaffs_verify.c b/fs/yaffs2-new/yaffs_verify.c
new file mode 100644
index 0000000000..b3e540dd52
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_verify.c
@@ -0,0 +1,525 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_verify.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+
+int yaffs_skip_verification(struct yaffs_dev *dev)
+{
+ dev = dev;
+ return !(yaffs_trace_mask &
+ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_full_verification(struct yaffs_dev *dev)
+{
+ dev = dev;
+ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
+{
+ dev = dev;
+ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+static const char * const block_state_name[] = {
+ "Unknown",
+ "Needs scan",
+ "Scanning",
+ "Empty",
+ "Allocating",
+ "Full",
+ "Dirty",
+ "Checkpoint",
+ "Collecting",
+ "Dead"
+};
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
+{
+ int actually_used;
+ int in_use;
+
+ if (yaffs_skip_verification(dev))
+ return;
+
+ /* Report illegal runtime states */
+ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has undefined state %d",
+ n, bi->block_state);
+
+ switch (bi->block_state) {
+ case YAFFS_BLOCK_STATE_UNKNOWN:
+ case YAFFS_BLOCK_STATE_SCANNING:
+ case YAFFS_BLOCK_STATE_NEEDS_SCAN:
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has bad run-state %s",
+ n, block_state_name[bi->block_state]);
+ }
+
+ /* Check pages in use and soft deletions are legal */
+
+ actually_used = bi->pages_in_use - bi->soft_del_pages;
+
+ if (bi->pages_in_use < 0 ||
+ bi->pages_in_use > dev->param.chunks_per_block ||
+ bi->soft_del_pages < 0 ||
+ bi->soft_del_pages > dev->param.chunks_per_block ||
+ actually_used < 0 || actually_used > dev->param.chunks_per_block)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has illegal values pages_in_used %d soft_del_pages %d",
+ n, bi->pages_in_use, bi->soft_del_pages);
+
+ /* Check chunk bitmap legal */
+ in_use = yaffs_count_chunk_bits(dev, n);
+ if (in_use != bi->pages_in_use)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
+ n, bi->pages_in_use, in_use);
+}
+
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi, int n)
+{
+ yaffs_verify_blk(dev, bi, n);
+
+ /* After collection the block should be in the erased state */
+
+ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
+ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Block %d is in state %d after gc, should be erased",
+ n, bi->block_state);
+ }
+}
+
+void yaffs_verify_blocks(struct yaffs_dev *dev)
+{
+ int i;
+ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
+ int illegal_states = 0;
+
+ if (yaffs_skip_verification(dev))
+ return;
+
+ memset(state_count, 0, sizeof(state_count));
+
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+ yaffs_verify_blk(dev, bi, i);
+
+ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
+ state_count[bi->block_state]++;
+ else
+ illegal_states++;
+ }
+
+ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
+
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "%d blocks have illegal states",
+ illegal_states);
+ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Too many allocating blocks");
+
+ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "%s %d blocks",
+ block_state_name[i], state_count[i]);
+
+ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Checkpoint block count wrong dev %d count %d",
+ dev->blocks_in_checkpt,
+ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
+
+ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Erased block count wrong dev %d count %d",
+ dev->n_erased_blocks,
+ state_count[YAFFS_BLOCK_STATE_EMPTY]);
+
+ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Too many collecting blocks %d (max is 1)",
+ state_count[YAFFS_BLOCK_STATE_COLLECTING]);
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in
+ * which case those tests will not be performed.
+ */
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+ struct yaffs_ext_tags *tags, int parent_check)
+{
+ if (obj && yaffs_skip_verification(obj->my_dev))
+ return;
+
+ if (!(tags && obj && oh)) {
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Verifying object header tags %p obj %p oh %p",
+ tags, obj, oh);
+ return;
+ }
+
+ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+ oh->type > YAFFS_OBJECT_TYPE_MAX)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header type is illegal value 0x%x",
+ tags->obj_id, oh->type);
+
+ if (tags->obj_id != obj->obj_id)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch obj_id %d",
+ tags->obj_id, obj->obj_id);
+
+ /*
+ * Check that the object's parent ids match if parent_check requested.
+ *
+ * Tests do not apply to the root object.
+ */
+
+ if (parent_check && tags->obj_id > 1 && !obj->parent)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch parent_id %d obj->parent is NULL",
+ tags->obj_id, oh->parent_obj_id);
+
+ if (parent_check && obj->parent &&
+ oh->parent_obj_id != obj->parent->obj_id &&
+ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header mismatch parent_id %d parent_obj_id %d",
+ tags->obj_id, oh->parent_obj_id,
+ obj->parent->obj_id);
+
+ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header name is NULL",
+ obj->obj_id);
+
+ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d header name is 0xff",
+ obj->obj_id);
+}
+
+void yaffs_verify_file(struct yaffs_obj *obj)
+{
+ int required_depth;
+ int actual_depth;
+ u32 last_chunk;
+ u32 the_chunk;
+ u32 x;
+ u32 i;
+ struct yaffs_dev *dev;
+ struct yaffs_ext_tags tags;
+ struct yaffs_tnode *tn;
+ u32 obj_id;
+
+ if (!obj)
+ return;
+
+ if (yaffs_skip_verification(obj->my_dev))
+ return;
+
+ dev = obj->my_dev;
+ obj_id = obj->obj_id;
+
+ /* Check file size is consistent with tnode depth */
+ last_chunk =
+ obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
+ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
+ required_depth = 0;
+ while (x > 0) {
+ x >>= YAFFS_TNODES_INTERNAL_BITS;
+ required_depth++;
+ }
+
+ actual_depth = obj->variant.file_variant.top_level;
+
+ /* Check that the chunks in the tnode tree are all correct.
+ * We do this by scanning through the tnode tree and
+ * checking the tags for every chunk match.
+ */
+
+ if (yaffs_skip_nand_verification(dev))
+ return;
+
+ for (i = 1; i <= last_chunk; i++) {
+ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
+
+ if (!tn)
+ continue;
+
+ the_chunk = yaffs_get_group_base(dev, tn, i);
+ if (the_chunk > 0) {
+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+ &tags);
+ if (tags.obj_id != obj_id || tags.chunk_id != i)
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
+ obj_id, i, the_chunk,
+ tags.obj_id, tags.chunk_id);
+ }
+ }
+}
+
+void yaffs_verify_link(struct yaffs_obj *obj)
+{
+ if (obj && yaffs_skip_verification(obj->my_dev))
+ return;
+
+ /* Verify sane equivalent object */
+}
+
+void yaffs_verify_symlink(struct yaffs_obj *obj)
+{
+ if (obj && yaffs_skip_verification(obj->my_dev))
+ return;
+
+ /* Verify symlink string */
+}
+
+void yaffs_verify_special(struct yaffs_obj *obj)
+{
+ if (obj && yaffs_skip_verification(obj->my_dev))
+ return;
+}
+
+void yaffs_verify_obj(struct yaffs_obj *obj)
+{
+ struct yaffs_dev *dev;
+ u32 chunk_min;
+ u32 chunk_max;
+ u32 chunk_id_ok;
+ u32 chunk_in_range;
+ u32 chunk_wrongly_deleted;
+ u32 chunk_valid;
+
+ if (!obj)
+ return;
+
+ if (obj->being_created)
+ return;
+
+ dev = obj->my_dev;
+
+ if (yaffs_skip_verification(dev))
+ return;
+
+ /* Check sane object header chunk */
+
+ chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
+ chunk_max =
+ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
+
+ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
+ ((unsigned)(obj->hdr_chunk)) <= chunk_max);
+ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
+ chunk_valid = chunk_in_range &&
+ yaffs_check_chunk_bit(dev,
+ obj->hdr_chunk / dev->param.chunks_per_block,
+ obj->hdr_chunk % dev->param.chunks_per_block);
+ chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
+
+ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has chunk_id %d %s %s",
+ obj->obj_id, obj->hdr_chunk,
+ chunk_id_ok ? "" : ",out of range",
+ chunk_wrongly_deleted ? ",marked as deleted" : "");
+
+ if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
+ struct yaffs_ext_tags tags;
+ struct yaffs_obj_hdr *oh;
+ u8 *buffer = yaffs_get_temp_buffer(dev);
+
+ oh = (struct yaffs_obj_hdr *)buffer;
+
+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
+
+ yaffs_verify_oh(obj, oh, &tags, 1);
+
+ yaffs_release_temp_buffer(dev, buffer);
+ }
+
+ /* Verify it has a parent */
+ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has parent pointer %p which does not look like an object",
+ obj->obj_id, obj->parent);
+ }
+
+ /* Verify parent is a directory */
+ if (obj->parent &&
+ obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d's parent is not a directory (type %d)",
+ obj->obj_id, obj->parent->variant_type);
+ }
+
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ yaffs_verify_file(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ yaffs_verify_symlink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ yaffs_verify_dir(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ yaffs_verify_link(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ yaffs_verify_special(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ default:
+ yaffs_trace(YAFFS_TRACE_VERIFY,
+ "Obj %d has illegaltype %d",
+ obj->obj_id, obj->variant_type);
+ break;
+ }
+}
+
+void yaffs_verify_objects(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ int i;
+ struct list_head *lh;
+
+ if (yaffs_skip_verification(dev))
+ return;
+
+ /* Iterate through the objects in each hash entry */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each(lh, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ yaffs_verify_obj(obj);
+ }
+ }
+}
+
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
+{
+ struct list_head *lh;
+ struct yaffs_obj *list_obj;
+ int count = 0;
+
+ if (!obj) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
+ BUG();
+ return;
+ }
+
+ if (yaffs_skip_verification(obj->my_dev))
+ return;
+
+ if (!obj->parent) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
+ BUG();
+ return;
+ }
+
+ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
+ BUG();
+ }
+
+ /* Iterate through the objects in each hash entry */
+
+ list_for_each(lh, &obj->parent->variant.dir_variant.children) {
+ list_obj = list_entry(lh, struct yaffs_obj, siblings);
+ yaffs_verify_obj(list_obj);
+ if (obj == list_obj)
+ count++;
+ }
+
+ if (count != 1) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Object in directory %d times",
+ count);
+ BUG();
+ }
+}
+
+void yaffs_verify_dir(struct yaffs_obj *directory)
+{
+ struct list_head *lh;
+ struct yaffs_obj *list_obj;
+
+ if (!directory) {
+ BUG();
+ return;
+ }
+
+ if (yaffs_skip_full_verification(directory->my_dev))
+ return;
+
+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Directory has wrong type: %d",
+ directory->variant_type);
+ BUG();
+ }
+
+ /* Iterate through the objects in each hash entry */
+
+ list_for_each(lh, &directory->variant.dir_variant.children) {
+ list_obj = list_entry(lh, struct yaffs_obj, siblings);
+ if (list_obj->parent != directory) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Object in directory list has wrong parent %p",
+ list_obj->parent);
+ BUG();
+ }
+ yaffs_verify_obj_in_dir(list_obj);
+ }
+}
+
+static int yaffs_free_verification_failures;
+
+void yaffs_verify_free_chunks(struct yaffs_dev *dev)
+{
+ int counted;
+ int difference;
+
+ if (yaffs_skip_verification(dev))
+ return;
+
+ counted = yaffs_count_free_chunks(dev);
+
+ difference = dev->n_free_chunks - counted;
+
+ if (difference) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Freechunks verification failure %d %d %d",
+ dev->n_free_chunks, counted, difference);
+ yaffs_free_verification_failures++;
+ }
+}
+
+int yaffs_verify_file_sane(struct yaffs_obj *in)
+{
+ in = in;
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_verify.h b/fs/yaffs2-new/yaffs_verify.h
new file mode 100644
index 0000000000..4f4af8d29a
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_verify.h
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_VERIFY_H__
+#define __YAFFS_VERIFY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
+ int n);
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi, int n);
+void yaffs_verify_blocks(struct yaffs_dev *dev);
+
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+ struct yaffs_ext_tags *tags, int parent_check);
+void yaffs_verify_file(struct yaffs_obj *obj);
+void yaffs_verify_link(struct yaffs_obj *obj);
+void yaffs_verify_symlink(struct yaffs_obj *obj);
+void yaffs_verify_special(struct yaffs_obj *obj);
+void yaffs_verify_obj(struct yaffs_obj *obj);
+void yaffs_verify_objects(struct yaffs_dev *dev);
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
+void yaffs_verify_dir(struct yaffs_obj *directory);
+void yaffs_verify_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_verify_file_sane(struct yaffs_obj *obj);
+
+int yaffs_skip_verification(struct yaffs_dev *dev);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_yaffs1.c b/fs/yaffs2-new/yaffs_yaffs1.c
new file mode 100644
index 0000000000..da6a40ff96
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_yaffs1.c
@@ -0,0 +1,424 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_yaffs1.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+#include "yaffs_attribs.h"
+
+int yaffs1_scan(struct yaffs_dev *dev)
+{
+ struct yaffs_ext_tags tags;
+ int blk;
+ int result;
+ int chunk;
+ int c;
+ int deleted;
+ enum yaffs_block_state state;
+ LIST_HEAD(hard_list);
+ struct yaffs_block_info *bi;
+ u32 seq_number;
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_obj *in;
+ struct yaffs_obj *parent;
+ int alloc_failed = 0;
+ struct yaffs_shadow_fixer *shadow_fixers = NULL;
+ u8 *chunk_data;
+
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs1_scan starts intstartblk %d intendblk %d...",
+ dev->internal_start_block, dev->internal_end_block);
+
+ chunk_data = yaffs_get_temp_buffer(dev);
+
+ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ /* Scan all the blocks to determine their state */
+ bi = dev->block_info;
+ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+ blk++) {
+ yaffs_clear_chunk_bits(dev, blk);
+ bi->pages_in_use = 0;
+ bi->soft_del_pages = 0;
+
+ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+ bi->block_state = state;
+ bi->seq_number = seq_number;
+
+ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
+
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+ "Block scanning block %d state %d seq %d",
+ blk, state, seq_number);
+
+ if (state == YAFFS_BLOCK_STATE_DEAD) {
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+ "block %d is bad", blk);
+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+ dev->n_erased_blocks++;
+ dev->n_free_chunks += dev->param.chunks_per_block;
+ }
+ bi++;
+ }
+
+ /* For each block.... */
+ for (blk = dev->internal_start_block;
+ !alloc_failed && blk <= dev->internal_end_block; blk++) {
+
+ cond_resched();
+
+ bi = yaffs_get_block_info(dev, blk);
+ state = bi->block_state;
+
+ deleted = 0;
+
+ /* For each chunk in each block that needs scanning.... */
+ for (c = 0;
+ !alloc_failed && c < dev->param.chunks_per_block &&
+ state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
+ /* Read the tags and decide what to do */
+ chunk = blk * dev->param.chunks_per_block + c;
+
+ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
+ &tags);
+
+ /* Let's have a good look at this chunk... */
+
+ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
+ tags.is_deleted) {
+ /* YAFFS1 only...
+ * A deleted chunk
+ */
+ deleted++;
+ dev->n_free_chunks++;
+ } else if (!tags.chunk_used) {
+ /* An unassigned chunk in the block
+ * This means that either the block is empty or
+ * this is the one being allocated from
+ */
+
+ if (c == 0) {
+ /* We're looking at the first chunk in
+ *the block so the block is unused */
+ state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->n_erased_blocks++;
+ } else {
+ /* this is the block being allocated */
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Allocating from %d %d",
+ blk, c);
+ state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->alloc_block = blk;
+ dev->alloc_page = c;
+ dev->alloc_block_finder = blk;
+
+ }
+
+ dev->n_free_chunks +=
+ (dev->param.chunks_per_block - c);
+ } else if (tags.chunk_id > 0) {
+ /* chunk_id > 0 so it is a data chunk... */
+ unsigned int endpos;
+
+ yaffs_set_chunk_bit(dev, blk, c);
+ bi->pages_in_use++;
+
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ YAFFS_OBJECT_TYPE_FILE);
+ /* PutChunkIntoFile checks for a clash
+ * (two data chunks with the same chunk_id).
+ */
+
+ if (!in)
+ alloc_failed = 1;
+
+ if (in) {
+ if (!yaffs_put_chunk_in_file
+ (in, tags.chunk_id, chunk, 1))
+ alloc_failed = 1;
+ }
+
+ endpos =
+ (tags.chunk_id - 1) *
+ dev->data_bytes_per_chunk +
+ tags.n_bytes;
+ if (in &&
+ in->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE &&
+ in->variant.file_variant.scanned_size <
+ endpos) {
+ in->variant.file_variant.scanned_size =
+ endpos;
+ if (!dev->param.use_header_file_size) {
+ in->variant.
+ file_variant.file_size =
+ in->variant.
+ file_variant.scanned_size;
+ }
+
+ }
+ } else {
+ /* chunk_id == 0, so it is an ObjectHeader.
+ * Make the object
+ */
+ yaffs_set_chunk_bit(dev, blk, c);
+ bi->pages_in_use++;
+
+ result = yaffs_rd_chunk_tags_nand(dev, chunk,
+ chunk_data,
+ NULL);
+
+ oh = (struct yaffs_obj_hdr *)chunk_data;
+
+ in = yaffs_find_by_number(dev, tags.obj_id);
+ if (in && in->variant_type != oh->type) {
+ /* This should not happen, but somehow
+ * Wev'e ended up with an obj_id that
+ * has been reused but not yet deleted,
+ * and worse still it has changed type.
+ * Delete the old object.
+ */
+
+ yaffs_del_obj(in);
+ in = NULL;
+ }
+
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ oh->type);
+
+ if (!in)
+ alloc_failed = 1;
+
+ if (in && oh->shadows_obj > 0) {
+
+ struct yaffs_shadow_fixer *fixer;
+ fixer =
+ kmalloc(sizeof
+ (struct yaffs_shadow_fixer),
+ GFP_NOFS);
+ if (fixer) {
+ fixer->next = shadow_fixers;
+ shadow_fixers = fixer;
+ fixer->obj_id = tags.obj_id;
+ fixer->shadowed_id =
+ oh->shadows_obj;
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Shadow fixer: %d shadows %d",
+ fixer->obj_id,
+ fixer->shadowed_id);
+
+ }
+
+ }
+
+ if (in && in->valid) {
+ /* We have already filled this one.
+ * We have a duplicate and need to
+ * resolve it. */
+
+ unsigned existing_serial = in->serial;
+ unsigned new_serial =
+ tags.serial_number;
+
+ if (((existing_serial + 1) & 3) ==
+ new_serial) {
+ /* Use new one - destroy the
+ * exisiting one */
+ yaffs_chunk_del(dev,
+ in->hdr_chunk,
+ 1, __LINE__);
+ in->valid = 0;
+ } else {
+ /* Use existing - destroy
+ * this one. */
+ yaffs_chunk_del(dev, chunk, 1,
+ __LINE__);
+ }
+ }
+
+ if (in && !in->valid &&
+ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+ tags.obj_id ==
+ YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle
+ * with directory structure */
+ in->valid = 1;
+ in->variant_type = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ in->hdr_chunk = chunk;
+ in->serial = tags.serial_number;
+
+ } else if (in && !in->valid) {
+ /* we need to load this info */
+
+ in->valid = 1;
+ in->variant_type = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ in->hdr_chunk = chunk;
+ in->serial = tags.serial_number;
+
+ yaffs_set_obj_name_from_oh(in, oh);
+ in->dirty = 0;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ parent =
+ yaffs_find_or_create_by_number
+ (dev, oh->parent_obj_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ if (!parent)
+ alloc_failed = 1;
+ if (parent && parent->variant_type ==
+ YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variant_type =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->
+ variant.dir_variant.
+ children);
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, a problem....
+ * We're trying to use a
+ * non-directory as a directory
+ */
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ );
+ parent = dev->lost_n_found;
+ }
+
+ yaffs_add_obj_to_dir(parent, in);
+
+ switch (in->variant_type) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (dev->param.
+ use_header_file_size)
+
+ in->variant.
+ file_variant.file_size
+ = oh->file_size;
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.
+ hardlink_variant.equiv_id =
+ oh->equiv_id;
+ list_add(&in->hard_links,
+ &hard_list);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symlink_variant.
+ alias =
+ yaffs_clone_str(oh->alias);
+ if (!in->variant.
+ symlink_variant.alias)
+ alloc_failed = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ /* If we got this far while scanning,
+ * then the block is fully allocated. */
+ state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ /* If the block was partially allocated then
+ * treat it as fully allocated. */
+ state = YAFFS_BLOCK_STATE_FULL;
+ dev->alloc_block = -1;
+ }
+
+ bi->block_state = state;
+
+ /* Now let's see if it was dirty */
+ if (bi->pages_in_use == 0 &&
+ !bi->has_shrink_hdr &&
+ bi->block_state == YAFFS_BLOCK_STATE_FULL)
+ yaffs_block_became_dirty(dev, blk);
+ }
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We should now have scanned all the objects, now it's time to add
+ * these hardlinks.
+ */
+
+ yaffs_link_fixup(dev, &hard_list);
+
+ /*
+ * Fix up any shadowed objects.
+ * There should not be more than one of these.
+ */
+ {
+ struct yaffs_shadow_fixer *fixer;
+ struct yaffs_obj *obj;
+
+ while (shadow_fixers) {
+ fixer = shadow_fixers;
+ shadow_fixers = fixer->next;
+ /* Complete the rename transaction by deleting the
+ * shadowed object then setting the object header
+ to unshadowed.
+ */
+ obj = yaffs_find_by_number(dev, fixer->shadowed_id);
+ if (obj)
+ yaffs_del_obj(obj);
+
+ obj = yaffs_find_by_number(dev, fixer->obj_id);
+
+ if (obj)
+ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+ kfree(fixer);
+ }
+ }
+
+ yaffs_release_temp_buffer(dev, chunk_data);
+
+ if (alloc_failed)
+ return YAFFS_FAIL;
+
+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_yaffs1.h b/fs/yaffs2-new/yaffs_yaffs1.h
new file mode 100644
index 0000000000..97e2fdd08a
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_yaffs1.h
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS1_H__
+#define __YAFFS_YAFFS1_H__
+
+#include "yaffs_guts.h"
+int yaffs1_scan(struct yaffs_dev *dev);
+
+#endif
diff --git a/fs/yaffs2-new/yaffs_yaffs2.c b/fs/yaffs2-new/yaffs_yaffs2.c
new file mode 100644
index 0000000000..5761e960e6
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_yaffs2.c
@@ -0,0 +1,1532 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_checkptrw.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_verify.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/*
+ * Checkpoints are really no benefit on very small partitions.
+ *
+ * To save space on small partitions don't bother with checkpoints unless
+ * the partition is at least this big.
+ */
+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
+#define YAFFS_SMALL_HOLE_THRESHOLD 4
+
+/*
+ * Oldest Dirty Sequence Number handling.
+ */
+
+/* yaffs_calc_oldest_dirty_seq()
+ * yaffs2_find_oldest_dirty_seq()
+ * Calculate the oldest dirty sequence number if we don't know it.
+ */
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+ int i;
+ unsigned seq;
+ unsigned block_no = 0;
+ struct yaffs_block_info *b;
+
+ if (!dev->param.is_yaffs2)
+ return;
+
+ /* Find the oldest dirty sequence number. */
+ seq = dev->seq_number + 1;
+ b = dev->block_info;
+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+ if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
+ (b->pages_in_use - b->soft_del_pages) <
+ dev->param.chunks_per_block &&
+ b->seq_number < seq) {
+ seq = b->seq_number;
+ block_no = i;
+ }
+ b++;
+ }
+
+ if (block_no) {
+ dev->oldest_dirty_seq = seq;
+ dev->oldest_dirty_block = block_no;
+ }
+}
+
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+ if (!dev->param.is_yaffs2)
+ return;
+
+ if (!dev->oldest_dirty_seq)
+ yaffs_calc_oldest_dirty_seq(dev);
+}
+
+/*
+ * yaffs_clear_oldest_dirty_seq()
+ * Called when a block is erased or marked bad. (ie. when its seq_number
+ * becomes invalid). If the value matches the oldest then we clear
+ * dev->oldest_dirty_seq to force its recomputation.
+ */
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi)
+{
+
+ if (!dev->param.is_yaffs2)
+ return;
+
+ if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
+ dev->oldest_dirty_seq = 0;
+ dev->oldest_dirty_block = 0;
+ }
+}
+
+/*
+ * yaffs2_update_oldest_dirty_seq()
+ * Update the oldest dirty sequence number whenever we dirty a block.
+ * Only do this if the oldest_dirty_seq is actually being tracked.
+ */
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+ struct yaffs_block_info *bi)
+{
+ if (!dev->param.is_yaffs2)
+ return;
+
+ if (dev->oldest_dirty_seq) {
+ if (dev->oldest_dirty_seq > bi->seq_number) {
+ dev->oldest_dirty_seq = bi->seq_number;
+ dev->oldest_dirty_block = block_no;
+ }
+ }
+}
+
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
+{
+
+ if (!dev->param.is_yaffs2)
+ return 1; /* disqualification only applies to yaffs2. */
+
+ if (!bi->has_shrink_hdr)
+ return 1; /* can gc */
+
+ yaffs2_find_oldest_dirty_seq(dev);
+
+ /* Can't do gc of this block if there are any blocks older than this
+ * one that have discarded pages.
+ */
+ return (bi->seq_number <= dev->oldest_dirty_seq);
+}
+
+/*
+ * yaffs2_find_refresh_block()
+ * periodically finds the oldest full block by sequence number for refreshing.
+ * Only for yaffs2.
+ */
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
+{
+ u32 b;
+ u32 oldest = 0;
+ u32 oldest_seq = 0;
+ struct yaffs_block_info *bi;
+
+ if (!dev->param.is_yaffs2)
+ return oldest;
+
+ /*
+ * If refresh period < 10 then refreshing is disabled.
+ */
+ if (dev->param.refresh_period < 10)
+ return oldest;
+
+ /*
+ * Fix broken values.
+ */
+ if (dev->refresh_skip > dev->param.refresh_period)
+ dev->refresh_skip = dev->param.refresh_period;
+
+ if (dev->refresh_skip > 0)
+ return oldest;
+
+ /*
+ * Refresh skip is now zero.
+ * We'll do a refresh this time around....
+ * Update the refresh skip and find the oldest block.
+ */
+ dev->refresh_skip = dev->param.refresh_period;
+ dev->refresh_count++;
+ bi = dev->block_info;
+ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+
+ if (oldest < 1 || bi->seq_number < oldest_seq) {
+ oldest = b;
+ oldest_seq = bi->seq_number;
+ }
+ }
+ bi++;
+ }
+
+ if (oldest > 0) {
+ yaffs_trace(YAFFS_TRACE_GC,
+ "GC refresh count %d selected block %d with seq_number %d",
+ dev->refresh_count, oldest, oldest_seq);
+ }
+
+ return oldest;
+}
+
+int yaffs2_checkpt_required(struct yaffs_dev *dev)
+{
+ int nblocks;
+
+ if (!dev->param.is_yaffs2)
+ return 0;
+
+ nblocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+ return !dev->param.skip_checkpt_wr &&
+ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+}
+
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
+{
+ int retval;
+ int n_bytes = 0;
+ int n_blocks;
+ int dev_blocks;
+
+ if (!dev->param.is_yaffs2)
+ return 0;
+
+ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
+ /* Not a valid value so recalculate */
+ dev_blocks = dev->param.end_block - dev->param.start_block + 1;
+ n_bytes += sizeof(struct yaffs_checkpt_validity);
+ n_bytes += sizeof(struct yaffs_checkpt_dev);
+ n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
+ n_bytes += dev_blocks * dev->chunk_bit_stride;
+ n_bytes +=
+ (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
+ dev->n_obj;
+ n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
+ n_bytes += sizeof(struct yaffs_checkpt_validity);
+ n_bytes += sizeof(u32); /* checksum */
+
+ /* Round up and add 2 blocks to allow for some bad blocks,
+ * so add 3 */
+
+ n_blocks =
+ (n_bytes /
+ (dev->data_bytes_per_chunk *
+ dev->param.chunks_per_block)) + 3;
+
+ dev->checkpoint_blocks_required = n_blocks;
+ }
+
+ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
+ if (retval < 0)
+ retval = 0;
+ return retval;
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+ struct yaffs_checkpt_validity cp;
+
+ memset(&cp, 0, sizeof(cp));
+
+ cp.struct_type = sizeof(cp);
+ cp.magic = YAFFS_MAGIC;
+ cp.version = YAFFS_CHECKPOINT_VERSION;
+ cp.head = (head) ? 1 : 0;
+
+ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+ struct yaffs_checkpt_validity cp;
+ int ok;
+
+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ if (ok)
+ ok = (cp.struct_type == sizeof(cp)) &&
+ (cp.magic == YAFFS_MAGIC) &&
+ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+ (cp.head == ((head) ? 1 : 0));
+ return ok ? 1 : 0;
+}
+
+static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
+ struct yaffs_dev *dev)
+{
+ cp->n_erased_blocks = dev->n_erased_blocks;
+ cp->alloc_block = dev->alloc_block;
+ cp->alloc_page = dev->alloc_page;
+ cp->n_free_chunks = dev->n_free_chunks;
+
+ cp->n_deleted_files = dev->n_deleted_files;
+ cp->n_unlinked_files = dev->n_unlinked_files;
+ cp->n_bg_deletions = dev->n_bg_deletions;
+ cp->seq_number = dev->seq_number;
+
+}
+
+static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
+ struct yaffs_checkpt_dev *cp)
+{
+ dev->n_erased_blocks = cp->n_erased_blocks;
+ dev->alloc_block = cp->alloc_block;
+ dev->alloc_page = cp->alloc_page;
+ dev->n_free_chunks = cp->n_free_chunks;
+
+ dev->n_deleted_files = cp->n_deleted_files;
+ dev->n_unlinked_files = cp->n_unlinked_files;
+ dev->n_bg_deletions = cp->n_bg_deletions;
+ dev->seq_number = cp->seq_number;
+}
+
+static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
+{
+ struct yaffs_checkpt_dev cp;
+ u32 n_bytes;
+ u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+ int ok;
+
+ /* Write device runtime values */
+ yaffs2_dev_to_checkpt_dev(&cp, dev);
+ cp.struct_type = sizeof(cp);
+
+ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (!ok)
+ return 0;
+
+ /* Write block info */
+ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+ if (!ok)
+ return 0;
+
+ /* Write chunk bits */
+ n_bytes = n_blocks * dev->chunk_bit_stride;
+ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
+{
+ struct yaffs_checkpt_dev cp;
+ u32 n_bytes;
+ u32 n_blocks =
+ (dev->internal_end_block - dev->internal_start_block + 1);
+ int ok;
+
+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (!ok)
+ return 0;
+
+ if (cp.struct_type != sizeof(cp))
+ return 0;
+
+ yaffs_checkpt_dev_to_dev(dev, &cp);
+
+ n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+
+ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
+
+ if (!ok)
+ return 0;
+
+ n_bytes = n_blocks * dev->chunk_bit_stride;
+
+ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+ return ok ? 1 : 0;
+}
+
+static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
+ struct yaffs_obj *obj)
+{
+ cp->obj_id = obj->obj_id;
+ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
+ cp->hdr_chunk = obj->hdr_chunk;
+ cp->variant_type = obj->variant_type;
+ cp->deleted = obj->deleted;
+ cp->soft_del = obj->soft_del;
+ cp->unlinked = obj->unlinked;
+ cp->fake = obj->fake;
+ cp->rename_allowed = obj->rename_allowed;
+ cp->unlink_allowed = obj->unlink_allowed;
+ cp->serial = obj->serial;
+ cp->n_data_chunks = obj->n_data_chunks;
+
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+ cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
+ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
+}
+
+static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
+ struct yaffs_checkpt_obj *cp)
+{
+ struct yaffs_obj *parent;
+
+ if (obj->variant_type != cp->variant_type) {
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
+ cp->obj_id, cp->variant_type, cp->hdr_chunk,
+ obj->variant_type);
+ return 0;
+ }
+
+ obj->obj_id = cp->obj_id;
+
+ if (cp->parent_id)
+ parent = yaffs_find_or_create_by_number(obj->my_dev,
+ cp->parent_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ else
+ parent = NULL;
+
+ if (parent) {
+ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
+ cp->obj_id, cp->parent_id,
+ cp->variant_type, cp->hdr_chunk,
+ parent->variant_type);
+ return 0;
+ }
+ yaffs_add_obj_to_dir(parent, obj);
+ }
+
+ obj->hdr_chunk = cp->hdr_chunk;
+ obj->variant_type = cp->variant_type;
+ obj->deleted = cp->deleted;
+ obj->soft_del = cp->soft_del;
+ obj->unlinked = cp->unlinked;
+ obj->fake = cp->fake;
+ obj->rename_allowed = cp->rename_allowed;
+ obj->unlink_allowed = cp->unlink_allowed;
+ obj->serial = cp->serial;
+ obj->n_data_chunks = cp->n_data_chunks;
+
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+ obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
+ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
+
+ if (obj->hdr_chunk > 0)
+ obj->lazy_loaded = 1;
+ return 1;
+}
+
+static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
+ struct yaffs_tnode *tn, u32 level,
+ int chunk_offset)
+{
+ int i;
+ struct yaffs_dev *dev = in->my_dev;
+ int ok = 1;
+ u32 base_offset;
+
+ if (!tn)
+ return 1;
+
+ if (level > 0) {
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+ if (!tn->internal[i])
+ continue;
+ ok = yaffs2_checkpt_tnode_worker(in,
+ tn->internal[i],
+ level - 1,
+ (chunk_offset <<
+ YAFFS_TNODES_INTERNAL_BITS) + i);
+ }
+ return ok;
+ }
+
+ /* Level 0 tnode */
+ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
+ ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
+ sizeof(base_offset));
+ if (ok)
+ ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
+ dev->tnode_size);
+
+ return ok;
+}
+
+static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
+{
+ u32 end_marker = ~0;
+ int ok = 1;
+
+ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ return ok;
+
+ ok = yaffs2_checkpt_tnode_worker(obj,
+ obj->variant.file_variant.top,
+ obj->variant.file_variant.
+ top_level, 0);
+ if (ok)
+ ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
+ sizeof(end_marker)) == sizeof(end_marker));
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
+{
+ u32 base_chunk;
+ int ok = 1;
+ struct yaffs_dev *dev = obj->my_dev;
+ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
+ struct yaffs_tnode *tn;
+ int nread = 0;
+
+ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
+ sizeof(base_chunk));
+
+ while (ok && (~base_chunk)) {
+ nread++;
+ /* Read level 0 tnode */
+
+ tn = yaffs_get_tnode(dev);
+ if (tn)
+ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
+ dev->tnode_size);
+ else
+ ok = 0;
+
+ if (tn && ok)
+ ok = yaffs_add_find_tnode_0(dev,
+ file_stuct_ptr,
+ base_chunk, tn) ? 1 : 0;
+
+ if (ok)
+ ok = (yaffs2_checkpt_rd
+ (dev, &base_chunk,
+ sizeof(base_chunk)) == sizeof(base_chunk));
+ }
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint read tnodes %d records, last %d. ok %d",
+ nread, base_chunk, ok);
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_checkpt_obj cp;
+ int i;
+ int ok = 1;
+ struct list_head *lh;
+
+ /* Iterate through the objects in each hash entry,
+ * dumping them to the checkpointing stream.
+ */
+
+ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
+ list_for_each(lh, &dev->obj_bucket[i].list) {
+ obj = list_entry(lh, struct yaffs_obj, hash_link);
+ if (!obj->defered_free) {
+ yaffs2_obj_checkpt_obj(&cp, obj);
+ cp.struct_type = sizeof(cp);
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
+ cp.obj_id, cp.parent_id,
+ cp.variant_type, cp.hdr_chunk, obj);
+
+ ok = (yaffs2_checkpt_wr(dev, &cp,
+ sizeof(cp)) == sizeof(cp));
+
+ if (ok &&
+ obj->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE)
+ ok = yaffs2_wr_checkpt_tnodes(obj);
+ }
+ }
+ }
+
+ /* Dump end of list */
+ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
+ cp.struct_type = sizeof(cp);
+
+ if (ok)
+ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_checkpt_obj cp;
+ int ok = 1;
+ int done = 0;
+ LIST_HEAD(hard_list);
+
+
+ while (ok && !done) {
+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+ if (cp.struct_type != sizeof(cp)) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "struct size %d instead of %d ok %d",
+ cp.struct_type, (int)sizeof(cp), ok);
+ ok = 0;
+ }
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "Checkpoint read object %d parent %d type %d chunk %d ",
+ cp.obj_id, cp.parent_id, cp.variant_type,
+ cp.hdr_chunk);
+
+ if (ok && cp.obj_id == ~0) {
+ done = 1;
+ } else if (ok) {
+ obj =
+ yaffs_find_or_create_by_number(dev, cp.obj_id,
+ cp.variant_type);
+ if (obj) {
+ ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
+ if (!ok)
+ break;
+ if (obj->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE) {
+ ok = yaffs2_rd_checkpt_tnodes(obj);
+ } else if (obj->variant_type ==
+ YAFFS_OBJECT_TYPE_HARDLINK) {
+ list_add(&obj->hard_links, &hard_list);
+ }
+ } else {
+ ok = 0;
+ }
+ }
+ }
+
+ if (ok)
+ yaffs_link_fixup(dev, &hard_list);
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
+{
+ u32 checkpt_sum;
+ int ok;
+
+ yaffs2_get_checkpt_sum(dev, &checkpt_sum);
+
+ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
+ sizeof(checkpt_sum));
+
+ if (!ok)
+ return 0;
+
+ return 1;
+}
+
+static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
+{
+ u32 checkpt_sum0;
+ u32 checkpt_sum1;
+ int ok;
+
+ yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
+
+ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
+ sizeof(checkpt_sum1));
+
+ if (!ok)
+ return 0;
+
+ if (checkpt_sum0 != checkpt_sum1)
+ return 0;
+
+ return 1;
+}
+
+static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
+{
+ int ok = 1;
+
+ if (!yaffs2_checkpt_required(dev)) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "skipping checkpoint write");
+ ok = 0;
+ }
+
+ if (ok)
+ ok = yaffs2_checkpt_open(dev, 1);
+
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint validity");
+ ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint device");
+ ok = yaffs2_wr_checkpt_dev(dev);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint objects");
+ ok = yaffs2_wr_checkpt_objs(dev);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "write checkpoint validity");
+ ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
+ }
+
+ if (ok)
+ ok = yaffs2_wr_checkpt_sum(dev);
+
+ if (!yaffs_checkpt_close(dev))
+ ok = 0;
+
+ if (ok)
+ dev->is_checkpointed = 1;
+ else
+ dev->is_checkpointed = 0;
+
+ return dev->is_checkpointed;
+}
+
+static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
+{
+ int ok = 1;
+
+ if (!dev->param.is_yaffs2)
+ ok = 0;
+
+ if (ok && dev->param.skip_checkpt_rd) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "skipping checkpoint read");
+ ok = 0;
+ }
+
+ if (ok)
+ ok = yaffs2_checkpt_open(dev, 0); /* open for read */
+
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint validity");
+ ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint device");
+ ok = yaffs2_rd_checkpt_dev(dev);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint objects");
+ ok = yaffs2_rd_checkpt_objs(dev);
+ }
+ if (ok) {
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint validity");
+ ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
+ }
+
+ if (ok) {
+ ok = yaffs2_rd_checkpt_sum(dev);
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "read checkpoint checksum %d", ok);
+ }
+
+ if (!yaffs_checkpt_close(dev))
+ ok = 0;
+
+ if (ok)
+ dev->is_checkpointed = 1;
+ else
+ dev->is_checkpointed = 0;
+
+ return ok ? 1 : 0;
+}
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
+{
+ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
+ dev->is_checkpointed = 0;
+ yaffs2_checkpt_invalidate_stream(dev);
+ }
+ if (dev->param.sb_dirty_fn)
+ dev->param.sb_dirty_fn(dev);
+}
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev)
+{
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "save entry: is_checkpointed %d",
+ dev->is_checkpointed);
+
+ yaffs_verify_objects(dev);
+ yaffs_verify_blocks(dev);
+ yaffs_verify_free_chunks(dev);
+
+ if (!dev->is_checkpointed) {
+ yaffs2_checkpt_invalidate(dev);
+ yaffs2_wr_checkpt_data(dev);
+ }
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
+ "save exit: is_checkpointed %d",
+ dev->is_checkpointed);
+
+ return dev->is_checkpointed;
+}
+
+int yaffs2_checkpt_restore(struct yaffs_dev *dev)
+{
+ int retval;
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "restore entry: is_checkpointed %d",
+ dev->is_checkpointed);
+
+ retval = yaffs2_rd_checkpt_data(dev);
+
+ if (dev->is_checkpointed) {
+ yaffs_verify_objects(dev);
+ yaffs_verify_blocks(dev);
+ yaffs_verify_free_chunks(dev);
+ }
+
+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+ "restore exit: is_checkpointed %d",
+ dev->is_checkpointed);
+
+ return retval;
+}
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
+{
+ /* if new_size > old_file_size.
+ * We're going to be writing a hole.
+ * If the hole is small then write zeros otherwise write a start
+ * of hole marker.
+ */
+ loff_t old_file_size;
+ int increase;
+ int small_hole;
+ int result = YAFFS_OK;
+ struct yaffs_dev *dev = NULL;
+ u8 *local_buffer = NULL;
+ int small_increase_ok = 0;
+
+ if (!obj)
+ return YAFFS_FAIL;
+
+ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ dev = obj->my_dev;
+
+ /* Bail out if not yaffs2 mode */
+ if (!dev->param.is_yaffs2)
+ return YAFFS_OK;
+
+ old_file_size = obj->variant.file_variant.file_size;
+
+ if (new_size <= old_file_size)
+ return YAFFS_OK;
+
+ increase = new_size - old_file_size;
+
+ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
+ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+ small_hole = 1;
+ else
+ small_hole = 0;
+
+ if (small_hole)
+ local_buffer = yaffs_get_temp_buffer(dev);
+
+ if (local_buffer) {
+ /* fill hole with zero bytes */
+ int pos = old_file_size;
+ int this_write;
+ int written;
+ memset(local_buffer, 0, dev->data_bytes_per_chunk);
+ small_increase_ok = 1;
+
+ while (increase > 0 && small_increase_ok) {
+ this_write = increase;
+ if (this_write > dev->data_bytes_per_chunk)
+ this_write = dev->data_bytes_per_chunk;
+ written =
+ yaffs_do_file_wr(obj, local_buffer, pos, this_write,
+ 0);
+ if (written == this_write) {
+ pos += this_write;
+ increase -= this_write;
+ } else {
+ small_increase_ok = 0;
+ }
+ }
+
+ yaffs_release_temp_buffer(dev, local_buffer);
+
+ /* If out of space then reverse any chunks we've added */
+ if (!small_increase_ok)
+ yaffs_resize_file_down(obj, old_file_size);
+ }
+
+ if (!small_increase_ok &&
+ obj->parent &&
+ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
+ /* Write a hole start header with the old file size */
+ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
+ }
+
+ return result;
+}
+
+struct yaffs_block_index {
+ int seq;
+ int block;
+};
+
+static int yaffs2_ybicmp(const void *a, const void *b)
+{
+ int aseq = ((struct yaffs_block_index *)a)->seq;
+ int bseq = ((struct yaffs_block_index *)b)->seq;
+ int ablock = ((struct yaffs_block_index *)a)->block;
+ int bblock = ((struct yaffs_block_index *)b)->block;
+
+ if (aseq == bseq)
+ return ablock - bblock;
+
+ return aseq - bseq;
+}
+
+static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi,
+ int blk, int chunk_in_block,
+ int *found_chunks,
+ u8 *chunk_data,
+ struct list_head *hard_list,
+ int summary_available)
+{
+ struct yaffs_obj_hdr *oh;
+ struct yaffs_obj *in;
+ struct yaffs_obj *parent;
+ int equiv_id;
+ int file_size;
+ int is_shrink;
+ int is_unlinked;
+ struct yaffs_ext_tags tags;
+ int result;
+ int alloc_failed = 0;
+ int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
+ struct yaffs_file_var *file_var;
+ struct yaffs_hardlink_var *hl_var;
+ struct yaffs_symlink_var *sl_var;
+
+ if (summary_available) {
+ result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
+ tags.seq_number = bi->seq_number;
+ }
+
+ if (!summary_available || tags.obj_id == 0) {
+ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
+ dev->tags_used++;
+ } else {
+ dev->summary_used++;
+ }
+
+ /* Let's have a good look at this chunk... */
+
+ if (!tags.chunk_used) {
+ /* An unassigned chunk in the block.
+ * If there are used chunks after this one, then
+ * it is a chunk that was skipped due to failing
+ * the erased check. Just skip it so that it can
+ * be deleted.
+ * But, more typically, We get here when this is
+ * an unallocated chunk and his means that
+ * either the block is empty or this is the one
+ * being allocated from
+ */
+
+ if (*found_chunks) {
+ /* This is a chunk that was skipped due
+ * to failing the erased check */
+ } else if (chunk_in_block == 0) {
+ /* We're looking at the first chunk in
+ * the block so the block is unused */
+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->n_erased_blocks++;
+ } else {
+ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ if (dev->seq_number == bi->seq_number) {
+ /* Allocating from this block*/
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Allocating from %d %d",
+ blk, chunk_in_block);
+
+ bi->block_state =
+ YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->alloc_block = blk;
+ dev->alloc_page = chunk_in_block;
+ dev->alloc_block_finder = blk;
+ } else {
+ /* This is a partially written block
+ * that is not the current
+ * allocation block.
+ */
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Partially written block %d detected. gc will fix this.",
+ blk);
+ }
+ }
+ }
+
+ dev->n_free_chunks++;
+
+ } else if (tags.ecc_result ==
+ YAFFS_ECC_RESULT_UNFIXED) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ " Unfixed ECC in chunk(%d:%d), chunk ignored",
+ blk, chunk_in_block);
+ dev->n_free_chunks++;
+ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
+ tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
+ tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
+ (tags.chunk_id > 0 &&
+ tags.n_bytes > dev->data_bytes_per_chunk) ||
+ tags.seq_number != bi->seq_number) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
+ blk, chunk_in_block, tags.obj_id,
+ tags.chunk_id, tags.n_bytes);
+ dev->n_free_chunks++;
+ } else if (tags.chunk_id > 0) {
+ /* chunk_id > 0 so it is a data chunk... */
+ unsigned int endpos;
+ u32 chunk_base = (tags.chunk_id - 1) *
+ dev->data_bytes_per_chunk;
+
+ *found_chunks = 1;
+
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ YAFFS_OBJECT_TYPE_FILE);
+ if (!in)
+ /* Out of memory */
+ alloc_failed = 1;
+
+ if (in &&
+ in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
+ chunk_base < in->variant.file_variant.shrink_size) {
+ /* This has not been invalidated by
+ * a resize */
+ if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
+ chunk, -1))
+ alloc_failed = 1;
+
+ /* File size is calculated by looking at
+ * the data chunks if we have not
+ * seen an object header yet.
+ * Stop this practice once we find an
+ * object header.
+ */
+ endpos = chunk_base + tags.n_bytes;
+
+ if (!in->valid &&
+ in->variant.file_variant.scanned_size < endpos) {
+ in->variant.file_variant.
+ scanned_size = endpos;
+ in->variant.file_variant.
+ file_size = endpos;
+ }
+ } else if (in) {
+ /* This chunk has been invalidated by a
+ * resize, or a past file deletion
+ * so delete the chunk*/
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ }
+ } else {
+ /* chunk_id == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make
+ * the object
+ */
+ *found_chunks = 1;
+
+ yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+ bi->pages_in_use++;
+
+ oh = NULL;
+ in = NULL;
+
+ if (tags.extra_available) {
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id,
+ tags.extra_obj_type);
+ if (!in)
+ alloc_failed = 1;
+ }
+
+ if (!in ||
+ (!in->valid && dev->param.disable_lazy_load) ||
+ tags.extra_shadows ||
+ (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+ /* If we don't have valid info then we
+ * need to read the chunk
+ * TODO In future we can probably defer
+ * reading the chunk and living with
+ * invalid data until needed.
+ */
+
+ result = yaffs_rd_chunk_tags_nand(dev,
+ chunk,
+ chunk_data,
+ NULL);
+
+ oh = (struct yaffs_obj_hdr *)chunk_data;
+
+ if (dev->param.inband_tags) {
+ /* Fix up the header if they got
+ * corrupted by inband tags */
+ oh->shadows_obj =
+ oh->inband_shadowed_obj_id;
+ oh->is_shrink =
+ oh->inband_is_shrink;
+ }
+
+ if (!in) {
+ in = yaffs_find_or_create_by_number(dev,
+ tags.obj_id, oh->type);
+ if (!in)
+ alloc_failed = 1;
+ }
+ }
+
+ if (!in) {
+ /* TODO Hoosterman we have a problem! */
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
+ tags.obj_id, chunk);
+ return YAFFS_FAIL;
+ }
+
+ if (in->valid) {
+ /* We have already filled this one.
+ * We have a duplicate that will be
+ * discarded, but we first have to suck
+ * out resize info if it is a file.
+ */
+ if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
+ ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+ (tags.extra_available &&
+ tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+ )) {
+ u32 this_size = (oh) ?
+ oh->file_size :
+ tags.extra_length;
+ u32 parent_obj_id = (oh) ?
+ oh->parent_obj_id :
+ tags.extra_parent_id;
+
+ is_shrink = (oh) ?
+ oh->is_shrink :
+ tags.extra_is_shrink;
+
+ /* If it is deleted (unlinked
+ * at start also means deleted)
+ * we treat the file size as
+ * being zeroed at this point.
+ */
+ if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
+ parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
+ this_size = 0;
+ is_shrink = 1;
+ }
+
+ if (is_shrink &&
+ in->variant.file_variant.shrink_size >
+ this_size)
+ in->variant.file_variant.shrink_size =
+ this_size;
+
+ if (is_shrink)
+ bi->has_shrink_hdr = 1;
+ }
+ /* Use existing - destroy this one. */
+ yaffs_chunk_del(dev, chunk, 1, __LINE__);
+ }
+
+ if (!in->valid && in->variant_type !=
+ (oh ? oh->type : tags.extra_obj_type))
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
+ oh ? oh->type : tags.extra_obj_type,
+ in->variant_type, tags.obj_id,
+ chunk);
+
+ if (!in->valid &&
+ (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+ tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle
+ * with directory structure */
+ in->valid = 1;
+
+ if (oh) {
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+ in->lazy_loaded = 0;
+ } else {
+ in->lazy_loaded = 1;
+ }
+ in->hdr_chunk = chunk;
+
+ } else if (!in->valid) {
+ /* we need to load this info */
+ in->valid = 1;
+ in->hdr_chunk = chunk;
+ if (oh) {
+ in->variant_type = oh->type;
+ in->yst_mode = oh->yst_mode;
+ yaffs_load_attribs(in, oh);
+
+ if (oh->shadows_obj > 0)
+ yaffs_handle_shadowed_obj(dev,
+ oh->shadows_obj, 1);
+
+ yaffs_set_obj_name_from_oh(in, oh);
+ parent = yaffs_find_or_create_by_number(dev,
+ oh->parent_obj_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ file_size = oh->file_size;
+ is_shrink = oh->is_shrink;
+ equiv_id = oh->equiv_id;
+ } else {
+ in->variant_type = tags.extra_obj_type;
+ parent = yaffs_find_or_create_by_number(dev,
+ tags.extra_parent_id,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ file_size = tags.extra_length;
+ is_shrink = tags.extra_is_shrink;
+ equiv_id = tags.extra_equiv_id;
+ in->lazy_loaded = 1;
+ }
+ in->dirty = 0;
+
+ if (!parent)
+ alloc_failed = 1;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ if (parent &&
+ parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variant_type =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->
+ variant.dir_variant.children);
+ } else if (!parent ||
+ parent->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /* Hoosterman, another problem....
+ * Trying to use a non-directory as a directory
+ */
+
+ yaffs_trace(YAFFS_TRACE_ERROR,
+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+ );
+ parent = dev->lost_n_found;
+ }
+ yaffs_add_obj_to_dir(parent, in);
+
+ is_unlinked = (parent == dev->del_dir) ||
+ (parent == dev->unlinked_dir);
+
+ if (is_shrink)
+ /* Mark the block */
+ bi->has_shrink_hdr = 1;
+
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent
+ * object is scanned we put them all in a list.
+ * After scanning is complete, we should have all the
+ * objects, so we run through this list and fix up all
+ * the chains.
+ */
+
+ switch (in->variant_type) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ file_var = &in->variant.file_variant;
+ if (file_var->scanned_size < file_size) {
+ /* This covers the case where the file
+ * size is greater than the data held.
+ * This will happen if the file is
+ * resized to be larger than its
+ * current data extents.
+ */
+ file_var->file_size = file_size;
+ file_var->scanned_size = file_size;
+ }
+
+ if (file_var->shrink_size > file_size)
+ file_var->shrink_size = file_size;
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ hl_var = &in->variant.hardlink_variant;
+ if (!is_unlinked) {
+ hl_var->equiv_id = equiv_id;
+ list_add(&in->hard_links, hard_list);
+ }
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ sl_var = &in->variant.symlink_variant;
+ if (oh) {
+ sl_var->alias =
+ yaffs_clone_str(oh->alias);
+ if (!sl_var->alias)
+ alloc_failed = 1;
+ }
+ break;
+ }
+ }
+ }
+ return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int yaffs2_scan_backwards(struct yaffs_dev *dev)
+{
+ int blk;
+ int block_iter;
+ int start_iter;
+ int end_iter;
+ int n_to_scan = 0;
+ enum yaffs_block_state state;
+ int c;
+ int deleted;
+ LIST_HEAD(hard_list);
+ struct yaffs_block_info *bi;
+ u32 seq_number;
+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+ u8 *chunk_data;
+ int found_chunks;
+ int alloc_failed = 0;
+ struct yaffs_block_index *block_index = NULL;
+ int alt_block_index = 0;
+ int summary_available;
+
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
+ dev->internal_start_block, dev->internal_end_block);
+
+ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ block_index =
+ kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
+
+ if (!block_index) {
+ block_index =
+ vmalloc(n_blocks * sizeof(struct yaffs_block_index));
+ alt_block_index = 1;
+ }
+
+ if (!block_index) {
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "yaffs2_scan_backwards() could not allocate block index!"
+ );
+ return YAFFS_FAIL;
+ }
+
+ dev->blocks_in_checkpt = 0;
+
+ chunk_data = yaffs_get_temp_buffer(dev);
+
+ /* Scan all the blocks to determine their state */
+ bi = dev->block_info;
+ for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+ blk++) {
+ yaffs_clear_chunk_bits(dev, blk);
+ bi->pages_in_use = 0;
+ bi->soft_del_pages = 0;
+
+ yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+ bi->block_state = state;
+ bi->seq_number = seq_number;
+
+ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+ bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+ "Block scanning block %d state %d seq %d",
+ blk, bi->block_state, seq_number);
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+ dev->blocks_in_checkpt++;
+
+ } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+ "block %d is bad", blk);
+ } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+ dev->n_erased_blocks++;
+ dev->n_free_chunks += dev->param.chunks_per_block;
+ } else if (bi->block_state ==
+ YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ /* Determine the highest sequence number */
+ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+ block_index[n_to_scan].seq = seq_number;
+ block_index[n_to_scan].block = blk;
+ n_to_scan++;
+ if (seq_number >= dev->seq_number)
+ dev->seq_number = seq_number;
+ } else {
+ /* TODO: Nasty sequence number! */
+ yaffs_trace(YAFFS_TRACE_SCAN,
+ "Block scanning block %d has bad sequence number %d",
+ blk, seq_number);
+ }
+ }
+ bi++;
+ }
+
+ yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
+
+ cond_resched();
+
+ /* Sort the blocks by sequence number */
+ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
+ yaffs2_ybicmp, NULL);
+
+ cond_resched();
+
+ yaffs_trace(YAFFS_TRACE_SCAN, "...done");
+
+ /* Now scan the blocks looking at the data. */
+ start_iter = 0;
+ end_iter = n_to_scan - 1;
+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
+
+ /* For each block.... backwards */
+ for (block_iter = end_iter;
+ !alloc_failed && block_iter >= start_iter;
+ block_iter--) {
+ /* Cooperative multitasking! This loop can run for so
+ long that watchdog timers expire. */
+ cond_resched();
+
+ /* get the block to scan in the correct order */
+ blk = block_index[block_iter].block;
+ bi = yaffs_get_block_info(dev, blk);
+ deleted = 0;
+
+ summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
+
+ /* For each chunk in each block that needs scanning.... */
+ found_chunks = 0;
+ if(summary_available)
+ c = dev->chunks_per_summary - 1;
+ else
+ c = dev->param.chunks_per_block - 1;
+
+ for (/* c is already initialised */;
+ !alloc_failed && c >= 0 &&
+ (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+ bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
+ c--) {
+ /* Scan backwards...
+ * Read the tags and decide what to do
+ */
+ if (yaffs2_scan_chunk(dev, bi, blk, c,
+ &found_chunks, chunk_data,
+ &hard_list, summary_available) ==
+ YAFFS_FAIL)
+ alloc_failed = 1;
+ }
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+ /* If we got this far while scanning, then the block
+ * is fully allocated. */
+ bi->block_state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+ /* Now let's see if it was dirty */
+ if (bi->pages_in_use == 0 &&
+ !bi->has_shrink_hdr &&
+ bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+ yaffs_block_became_dirty(dev, blk);
+ }
+ }
+
+ yaffs_skip_rest_of_block(dev);
+
+ if (alt_block_index)
+ vfree(block_index);
+ else
+ kfree(block_index);
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We have scanned all the objects, now it's time to add these
+ * hardlinks.
+ */
+ yaffs_link_fixup(dev, &hard_list);
+
+ yaffs_release_temp_buffer(dev, chunk_data);
+
+ if (alloc_failed)
+ return YAFFS_FAIL;
+
+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2-new/yaffs_yaffs2.h b/fs/yaffs2-new/yaffs_yaffs2.h
new file mode 100644
index 0000000000..2363bfd8bc
--- /dev/null
+++ b/fs/yaffs2-new/yaffs_yaffs2.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS2_H__
+#define __YAFFS_YAFFS2_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+ struct yaffs_block_info *bi);
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+ struct yaffs_block_info *bi);
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
+int yaffs2_checkpt_required(struct yaffs_dev *dev);
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
+int yaffs2_checkpt_save(struct yaffs_dev *dev);
+int yaffs2_checkpt_restore(struct yaffs_dev *dev);
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
+int yaffs2_scan_backwards(struct yaffs_dev *dev);
+
+#endif
diff --git a/fs/yaffs2-new/yaffscfg.h b/fs/yaffs2-new/yaffscfg.h
new file mode 100644
index 0000000000..3503dc863f
--- /dev/null
+++ b/fs/yaffs2-new/yaffscfg.h
@@ -0,0 +1,45 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Header file for using yaffs in an application via
+ * a direct interface.
+ */
+
+
+#ifndef __YAFFSCFG_H__
+#define __YAFFSCFG_H__
+
+
+#include "devextras.h"
+
+#define YAFFSFS_N_HANDLES 200
+
+
+typedef struct {
+ const char *prefix;
+ struct yaffs_DeviceStruct *dev;
+} yaffsfs_DeviceConfiguration;
+
+
+void yaffsfs_Lock(void);
+void yaffsfs_Unlock(void);
+
+__u32 yaffsfs_CurrentTime(void);
+
+void yaffsfs_SetError(int err);
+int yaffsfs_GetError(void);
+
+#endif
diff --git a/fs/yaffs2-new/yaffsfs.c b/fs/yaffs2-new/yaffsfs.c
new file mode 100644
index 0000000000..bbe91dbd92
--- /dev/null
+++ b/fs/yaffs2-new/yaffsfs.c
@@ -0,0 +1,1741 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* XXX U-BOOT XXX */
+#include <common.h>
+#include "malloc.h"
+
+#include <jffs2/load_kernel.h>
+
+
+#include "mtd_parts.h"
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+#include "yaffscfg.h"
+#include "yaffs_guts.h"
+#include "yportenv.h"
+#include "yaffs_mtdif.h"
+#include "yaffs_mtdif2.h"
+#include "yaffs_direct.h"
+#include "yaffsfs_errno.h"
+
+#include "yaffsfs.h"
+
+#if (CONFIG_SYS_MALLOC_LEN < (512 << 10))
+#error Malloc Area too small for YAFFS, increas CONFIG_SYS_MALLOC_LEN to >= 512KiB
+#endif
+
+/* YAFFSFS_RW_SIZE must be a power of 2 */
+#define YAFFSFS_RW_SHIFT (13)
+#define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT)
+
+typedef struct {
+ int count; /* Number of handles accessing this inode */
+ struct yaffs_obj *iObj;
+} yaffsfs_Inode;
+
+typedef struct{
+ u8 reading:1;
+ u8 writing:1;
+ u8 append:1;
+ u8 shareRead:1;
+ u8 shareWrite:1;
+ int inodeId:12; /* Index to corresponding yaffsfs_Inode */
+ int handleCount:10; /* Number of handles for this fd */
+ u32 position; /* current position in file */
+}yaffsfs_FileDes;
+
+typedef struct {
+ short int fdId;
+ short int useCount;
+} yaffsfs_Handle;
+
+static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
+static yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES];
+static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
+
+static int yaffsfs_handlesInitialised;
+
+/*
+ * yaffsfs_InitHandle
+ * Inilitalise handle management on start-up.
+ */
+
+static void yaffsfs_InitHandles(void)
+{
+ int i;
+ if(yaffsfs_handlesInitialised)
+ return;
+
+ memset(yaffsfs_inode,0,sizeof(yaffsfs_inode));
+ memset(yaffsfs_fd,0,sizeof(yaffsfs_fd));
+ memset(yaffsfs_handle,0,sizeof(yaffsfs_handle));
+
+ for(i = 0; i < YAFFSFS_N_HANDLES; i++)
+ yaffsfs_fd[i].inodeId = -1;
+ for(i = 0; i < YAFFSFS_N_HANDLES; i++)
+ yaffsfs_handle[i].fdId = -1;
+}
+
+static yaffsfs_Handle *yaffsfs_HandleToPointer(int h)
+{
+ if(h >= 0 && h <= YAFFSFS_N_HANDLES)
+ return &yaffsfs_handle[h];
+ return NULL;
+}
+
+static yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle)
+{
+ yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+ if(h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES)
+ return &yaffsfs_fd[h->fdId];
+
+ return NULL;
+}
+
+static yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
+{
+ yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);
+
+ if(fd && fd->handleCount > 0 &&
+ fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
+ return &yaffsfs_inode[fd->inodeId];
+
+ return NULL;
+}
+
+static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
+{
+ yaffsfs_Inode *in = yaffsfs_HandleToInode(handle);
+
+ if(in)
+ return in->iObj;
+
+ return NULL;
+}
+
+
+/*
+ * yaffsfs_FindInodeIdForObject
+ * Find the inode entry for an object, if it exists.
+ */
+
+static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj)
+{
+ int i;
+ int ret = -1;
+
+ if(obj)
+ obj = yaffs_get_equivalent_obj(obj);
+
+ /* Look for it in open inode table*/
+ for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
+ if(yaffsfs_inode[i].iObj == obj)
+ ret = i;
+ }
+ return ret;
+}
+
+/*
+ * yaffsfs_GetInodeIdForObject
+ * Grab an inode entry when opening a new inode.
+ */
+static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)
+{
+ int i;
+ int ret;
+ yaffsfs_Inode *in = NULL;
+
+ if(obj)
+ obj = yaffs_get_equivalent_obj(obj);
+
+ ret = yaffsfs_FindInodeIdForObject(obj);
+
+ for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
+ if(!yaffsfs_inode[i].iObj)
+ ret = i;
+ }
+
+ if(ret>=0){
+ in = &yaffsfs_inode[ret];
+ if(!in->iObj)
+ in->count = 0;
+ in->iObj = obj;
+ in->count++;
+ }
+
+
+ return ret;
+}
+
+/* yaffsfs_FindDevice
+ * yaffsfs_FindRoot
+ * Scan the parttion list to find the root; split out rest of path from
+ * Initialial partition. path must be /<partition>/<dir-or-file> */
+
+#define N_MAX_PARTLEN 64
+
+#include "nand.h"
+#include "yaffsfs_errno.h"
+#include "yaffs_trace.h"
+
+typedef struct
+{
+ u32 magic;
+ yaffs_dirent de; /* directory entry being used by this dsc */
+ YCHAR name[NAME_MAX+1]; /* name of directory being searched */
+ struct yaffs_obj *dirObj; /* ptr to directory being searched */
+ struct yaffs_obj *nextReturn; /* obj to be returned by next readddir */
+ int offset;
+ struct list_head others;
+} yaffsfs_DirectorySearchContext;
+
+static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj);
+static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc);
+
+typedef enum {
+ YAFFSFS_ACTION_CREATE,
+ YAFFSFS_ACTION_FIND,
+ YAFFSFS_ACTION_DESTROY
+} yaffsfs_action_t;
+
+extern nand_info_t nand_info[];
+
+static struct yaffs_dev *yaffsfs_FindDevice(const char *path, char **restOfPath, yaffsfs_action_t action)
+{
+ int slash_cnt, i, ret;
+ char partname[N_MAX_PARTLEN];
+ void *part_priv;
+ loff_t part_off, part_size;
+ int part_idx;
+ struct mtd_device *dev;
+ void *cookie;
+ struct yaffs_dev *flashDev;
+ struct yaffs_param *param;
+ struct yaffs_direct_context *context = NULL;
+ struct mtd_info *mtd;
+
+ if (!path)
+ return NULL;
+ if (*path != '/') {
+ printf("Path '%s' does not start with '/'!\n", path);
+ return NULL;
+ }
+ path++; /* Skip over leading '/' */
+
+ for (slash_cnt=i=0; i<N_MAX_PARTLEN && path[i]; ++i) {
+ if (path[i] == '/')
+ break;
+ partname[i] = path[i];
+ }
+ partname[i] = '\0';
+
+ /* save rest of path(if exists) */
+ *restOfPath = (char *)path+i;
+ if (**restOfPath == '/')
+ (*restOfPath)++;
+
+ /* Find the partition */
+ ret = mtd_get_part_priv(partname, &part_idx, &dev, &part_off, &part_size, &cookie, &part_priv, 1);
+ if (ret)
+ return NULL;
+
+ switch(action) {
+ case YAFFSFS_ACTION_FIND:
+ return (struct yaffs_dev *)part_priv;
+
+ case YAFFSFS_ACTION_CREATE:
+ if (part_priv) {
+ printf("Huh? mount of partition '%s' already has device %p\n", partname, part_priv);
+ return NULL;
+ }
+
+ /* First time we're seeing this device, create it using
+ information inside of the MTD_DEVICE structure */
+ flashDev = malloc(sizeof(struct yaffs_dev));
+ if (!flashDev) {
+ printf("%s:%d out of memory!\n", __FUNCTION__, __LINE__);
+ return NULL;
+ }
+ memset(flashDev, 0, sizeof(*flashDev));
+
+ context = malloc(sizeof(struct yaffs_direct_context));
+ if (!context) {
+ printf("%s:%d out of memory!\n", __FUNCTION__, __LINE__);
+ free(flashDev);
+ return NULL;
+ }
+
+ /* Side effect of mtd_get_part_priv() is to set nand_curr_device */
+ mtd = &nand_info[nand_curr_device];
+
+ flashDev->driver_context = mtd;
+
+ memset(context, 0, sizeof(*context));
+ flashDev->os_context = context;
+ yaffs_dev_to_lc(flashDev)->spare_buffer =
+ malloc(mtd->oobsize);
+
+ param = &(flashDev->param);
+
+ param->start_block = part_off / mtd->erasesize;
+ param->end_block = (part_off + part_size - 1) / mtd->erasesize;
+#if 0
+ printf("%s: part_off %x part_size %x startBlock %u endBlock %u\n", __FUNCTION__, (unsigned int)part_off, (unsigned int)part_size, param->start_block, param->end_block);
+#endif
+ i = param->end_block - param->start_block + 1;
+
+ /* limit number of reserved blocks to 10% of available space;
+ * 3 minimum, 8 maximum */
+ param->n_reserved_blocks = i/10;
+ if (param->n_reserved_blocks > 8)
+ param->n_reserved_blocks = 8;
+ if (param->n_reserved_blocks < 3)
+ param->n_reserved_blocks = 3;
+
+
+
+ param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
+ param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
+ param->bad_block_fn = nandmtd2_mark_block_bad;
+ param->query_block_fn = nandmtd2_query_block;
+ param->is_yaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ param->total_bytes_per_chunk = mtd->writesize;
+ param->chunks_per_block = mtd->erasesize / mtd->writesize;
+#else
+ param->total_bytes_per_chunk = mtd->oobblock;
+ param->chunks_per_block = mtd->erasesize / mtd->oobblock;
+#endif
+ /* ... and common functions */
+ param->erase_fn = nandmtd_erase_block;
+ param->initialise_flash_fn = nandmtd_initialise;
+ param->remove_obj_fn = yaffsfs_RemoveObjectCallback;
+
+ /* If the OOB area has only 16 bytes available can't
+ ECC the tag (must assume OOB is ECC'd already) */
+ if (mtd->ecclayout && mtd->ecclayout->oobavail <= 16) {
+ printf("ECC oobavail <= 16; forcing \"tags-ecc-off\"\n");
+ param->no_tags_ecc = 1;
+ }
+
+ mtd_set_part_priv(cookie, flashDev);
+
+ return flashDev;
+
+ case YAFFSFS_ACTION_DESTROY:
+ flashDev = (struct yaffs_dev *)part_priv;
+ if (yaffs_dev_to_lc(flashDev)->spare_buffer)
+ free(yaffs_dev_to_lc(flashDev)->spare_buffer);
+ if (flashDev->os_context)
+ free(flashDev->os_context);
+ free(part_priv);
+ mtd_set_part_priv(cookie, NULL);
+ return NULL;
+
+ default:
+ printf("%s: unknown action %d\n", __FUNCTION__, (int)action);
+ return NULL;
+ }
+
+}
+
+static struct yaffs_obj *yaffsfs_FindRoot(const char *path, char **restOfPath)
+{
+
+ struct yaffs_dev *dev;
+
+ dev= yaffsfs_FindDevice(path,restOfPath, YAFFSFS_ACTION_FIND);
+ if(dev && dev->is_mounted)
+ {
+ return dev->root_dir;
+ }
+ return NULL;
+}
+
+loff_t yaffs_freespace(const char *path)
+{
+ loff_t retVal=-1;
+ struct yaffs_dev *dev=NULL;
+ char *dummy;
+
+ yaffsfs_Lock();
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_FIND);
+ if (!dev) {
+ yaffsfs_set_error(-ENODEV);
+ } else if(dev->is_mounted) {
+ retVal = yaffs_get_n_free_chunks(dev);
+ retVal *= dev->data_bytes_per_chunk;
+ } else {
+ yaffsfs_set_error(-EPERM);
+ }
+
+ yaffsfs_Unlock();
+ return retVal;
+}
+
+#define yaffsfs_IsPathDivider(x) ((x) == '/')
+
+/* Forward references */
+static struct yaffs_obj *yaffsfs_find_object(struct yaffs_obj *rel_dir,
+ const char *path, int sym_depth, int getEquiv,
+ struct yaffs_obj **dir_out, int *not_dir, int *loop);
+
+static struct yaffs_obj *yaffsfs_follow_link(struct yaffs_obj *obj,int symDepth, int *loop)
+{
+ if (obj)
+ obj = yaffs_get_equivalent_obj(obj);
+
+ while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+ {
+ YCHAR *alias = obj->variant.symlink_variant.alias;
+
+ if(yaffsfs_IsPathDivider(*alias))
+ /* Starts with a /, need to scan from root up */
+ obj = yaffsfs_find_object(NULL,alias,symDepth++,
+ 1,NULL,NULL,loop);
+ else
+ /* Relative to here, so use the parent of the symlink as a start */
+ obj = yaffsfs_find_object(obj->parent,alias,symDepth++,
+ 1,NULL,NULL,loop);
+ }
+ return obj;
+}
+
+#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
+
+// yaffsfs_find_directory
+// Parse a path to determine the directory and the name within the directory.
+//
+// eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
+
+static struct yaffs_obj *yaffsfs_do_find_directory(struct yaffs_obj *startDir,
+ const YCHAR *path, YCHAR **name, int symDepth,
+ int *notDir,int *loop)
+{
+ struct yaffs_obj *dir;
+ YCHAR *restOfPath;
+ YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
+ int i;
+
+ if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES){
+ if(loop)
+ *loop = 1;
+ return NULL;
+ }
+
+ if(startDir){
+ dir = startDir;
+ restOfPath = (YCHAR *)path;
+ }
+ else
+ dir = yaffsfs_FindRoot(path,&restOfPath);
+
+
+ while(dir){
+ /*
+ * parse off /.
+ * curve ball: also throw away surplus '/'
+ * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
+ */
+ while(yaffsfs_IsPathDivider(*restOfPath))
+ restOfPath++; /* get rid of '/' */
+
+ *name = restOfPath;
+ i = 0;
+
+ while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
+ if (i < YAFFS_MAX_NAME_LENGTH){
+ str[i] = *restOfPath;
+ str[i+1] = '\0';
+ i++;
+ }
+ restOfPath++;
+ }
+
+ if(!*restOfPath)
+ /* got to the end of the string */
+ return dir;
+ else{
+ if(strcmp(str,_Y(".")) == 0){
+ /* Do nothing */
+ } else if(strcmp(str,_Y("..")) == 0) {
+ dir = dir->parent;
+ } else{
+ dir = yaffs_find_by_name(dir,str);
+
+ dir = yaffsfs_follow_link(dir,symDepth,loop);
+
+ if(dir && dir->variant_type !=
+ YAFFS_OBJECT_TYPE_DIRECTORY){
+ if(notDir)
+ *notDir = 1;
+ dir = NULL;
+ }
+
+ }
+ }
+ }
+ /* directory did not exist. */
+ return NULL;
+}
+
+static struct yaffs_obj *yaffsfs_find_directory(struct yaffs_obj *relDir,
+ const YCHAR *path,
+ YCHAR **name,
+ int symDepth,
+ int *notDir,
+ int *loop)
+{
+ return yaffsfs_do_find_directory(relDir,path,name,symDepth,notDir,loop);
+}
+
+
+static struct yaffs_obj *yaffsfs_find_object(struct yaffs_obj *relative_dir,
+ const char *path, int sym_depth, int get_equiv,
+ struct yaffs_obj **dir_out, int *not_dir, int *loop)
+{
+ struct yaffs_obj *dir;
+ struct yaffs_obj *obj;
+ char *name;
+
+ dir = yaffsfs_find_directory(relative_dir, path, &name, sym_depth, not_dir, loop);
+
+ if (dir_out)
+ *dir_out = dir;
+
+
+ if (dir && *name)
+ obj = yaffs_find_by_name(dir, name);
+ else
+ obj = dir;
+
+ if (get_equiv)
+ obj = yaffs_get_equivalent_obj(obj);
+
+ return obj;
+}
+
+int yaffsfs_mount(const char *path)
+{
+ int retVal=-1;
+ int result=YAFFS_FAIL;
+ struct yaffs_dev *dev=NULL;
+ char *dummy;
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "yaffs: Mounting %s",path);
+
+ yaffsfs_Lock();
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_CREATE);
+ if(dev)
+ {
+ if(!dev->is_mounted)
+ {
+ result = yaffs_guts_initialise(dev);
+ if(result == YAFFS_FAIL)
+ {
+ yaffsfs_FindDevice(path, &dummy, YAFFSFS_ACTION_DESTROY);
+ // todo error - mount failed
+ yaffsfs_set_error(-ENOMEM);
+ }
+ retVal = result ? 0 : -1;
+
+ }
+ else
+ {
+ //todo error - already mounted.
+ yaffsfs_set_error(-EBUSY);
+ }
+ }
+ else
+ {
+ // todo error - no device
+ yaffsfs_set_error(-ENODEV);
+ }
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+int yaffsfs_unmount(const char *path)
+{
+ int retVal=-1;
+ struct yaffs_dev *dev=NULL;
+ char *dummy;
+
+ yaffsfs_Lock();
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_FIND);
+ if(dev)
+ {
+ if(dev->is_mounted)
+ {
+ yaffs_flush_whole_cache(dev);
+ yaffs_checkpoint_save(dev);
+
+ yaffs_deinitialise(dev);
+
+ yaffsfs_FindDevice(path, &dummy, YAFFSFS_ACTION_DESTROY);
+
+ retVal = 0;
+ }
+ else
+ {
+ //todo error - not mounted.
+ yaffsfs_set_error(-EINVAL);
+
+ }
+ }
+ else
+ {
+ // todo error - no device
+ yaffsfs_set_error(-ENODEV);
+ }
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+static struct list_head search_contexts;
+
+static int yaffsfs_CheckPath(const YCHAR *path)
+{
+ int n=0;
+ int divs=0;
+ while(*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100){
+ if(yaffsfs_IsPathDivider(*path)){
+ n=0;
+ divs++;
+ } else
+ n++;
+ path++;
+ }
+
+ return (*path) ? -1 : 0;
+}
+
+static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
+{
+ if(dsc &&
+ dsc->dirObj &&
+ dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+
+ dsc->offset = 0;
+
+ if( list_empty(&dsc->dirObj->variant.dir_variant.children))
+ dsc->nextReturn = NULL;
+ else
+ dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
+ struct yaffs_obj,siblings);
+ } else {
+ /* Hey someone isn't playing nice! */
+ }
+}
+
+static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
+{
+
+ struct list_head *i;
+ yaffsfs_DirectorySearchContext *dsc;
+
+ /* if search contexts not initilised then skip */
+ if(!search_contexts.next)
+ return;
+
+ /* Iterate through the directory search contexts.
+ * If any are the one being removed, then advance the dsc to
+ * the next one to prevent a hanging ptr.
+ */
+ list_for_each(i, &search_contexts) {
+ if (i) {
+ dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
+ if(dsc->nextReturn == obj)
+ yaffsfs_DirAdvance(dsc);
+ }
+ }
+
+}
+
+yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
+{
+ yaffs_DIR *dir = NULL;
+ struct yaffs_obj *obj = NULL;
+ yaffsfs_DirectorySearchContext *dsc = NULL;
+ int notDir = 0;
+ int loop = 0;
+
+ if(!dirname){
+ yaffsfs_set_error(-EFAULT);
+ return NULL;
+ }
+
+ if(yaffsfs_CheckPath(dirname) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return NULL;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_find_object(NULL,dirname,0,1,NULL,&notDir,&loop);
+
+ if(!obj && notDir)
+ yaffsfs_set_error(-ENOTDIR);
+ else if(loop)
+ yaffsfs_set_error(-ELOOP);
+ else if(!obj)
+ yaffsfs_set_error(-ENOENT);
+ else if(obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffsfs_set_error(-ENOTDIR);
+ else {
+
+ dsc = kmalloc(sizeof(yaffsfs_DirectorySearchContext), 0);
+ dir = (yaffs_DIR *)dsc;
+
+ if(dsc){
+ memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
+ dsc->magic = YAFFS_MAGIC;
+ dsc->dirObj = obj;
+ strncpy(dsc->name,dirname,NAME_MAX);
+ INIT_LIST_HEAD(&dsc->others);
+
+ if(!search_contexts.next)
+ INIT_LIST_HEAD(&search_contexts);
+
+ list_add(&dsc->others,&search_contexts);
+ yaffsfs_SetDirRewound(dsc);
+ }
+
+ }
+
+ yaffsfs_Unlock();
+
+ return dir;
+}
+
+static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
+{
+ if(dsc &&
+ dsc->dirObj &&
+ dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+
+ if( dsc->nextReturn == NULL ||
+ list_empty(&dsc->dirObj->variant.dir_variant.children))
+ dsc->nextReturn = NULL;
+ else {
+ struct list_head *next = dsc->nextReturn->siblings.next;
+
+ if( next == &dsc->dirObj->variant.dir_variant.children)
+ dsc->nextReturn = NULL; /* end of list */
+ else
+ dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
+ }
+ } else {
+ /* Hey someone isn't playing nice! */
+ }
+}
+
+static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
+{
+ YCHAR *alt_path = NULL;
+ int path_length;
+ int i;
+
+ /*
+ * We don't have a definition for max path length.
+ * We will use 3 * max name length instead.
+ */
+ *ret_path = NULL;
+ path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
+
+ /* If the last character is a path divider, then we need to
+ * trim it back so that the name look-up works properly.
+ * eg. /foo/new_dir/ -> /foo/newdir
+ * Curveball: Need to handle multiple path dividers:
+ * eg. /foof/sdfse///// -> /foo/sdfse
+ */
+ if(path_length > 0 &&
+ yaffsfs_IsPathDivider(path[path_length-1])){
+ alt_path = kmalloc(path_length + 1, 0);
+ if(!alt_path)
+ return -1;
+ strcpy(alt_path, path);
+ for(i = path_length-1;
+ i >= 0 && yaffsfs_IsPathDivider(alt_path[i]);
+ i--)
+ alt_path[i] = (YCHAR) 0;
+ }
+ *ret_path = alt_path;
+ return 0;
+}
+
+struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
+{
+ yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
+ struct yaffs_dirent *retVal = NULL;
+
+ yaffsfs_Lock();
+
+ if(dsc && dsc->magic == YAFFS_MAGIC){
+ yaffsfs_set_error(0);
+ if(dsc->nextReturn){
+ dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
+ dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
+ dsc->de.d_off = dsc->offset++;
+ yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
+ if(strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
+ {
+ /* this should not happen! */
+ strcpy(dsc->de.d_name,_Y("zz"));
+ }
+ dsc->de.d_reclen = sizeof(struct yaffs_dirent);
+ retVal = &dsc->de;
+ yaffsfs_DirAdvance(dsc);
+ } else
+ retVal = NULL;
+ } else
+ yaffsfs_set_error(-EBADF);
+
+ yaffsfs_Unlock();
+
+ return retVal;
+
+}
+
+int yaffsfs_do_unlink(const YCHAR *path,int isDirectory)
+{
+ struct yaffs_obj *dir = NULL;
+ struct yaffs_obj *obj = NULL;
+ YCHAR *name;
+ int result = YAFFS_FAIL;
+ int notDir = 0;
+ int loop = 0;
+
+ if(!path){
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ if(yaffsfs_CheckPath(path) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_find_object(NULL,path,0,0,NULL,NULL,NULL);
+ dir = yaffsfs_find_directory(NULL,path,&name,0,&notDir,&loop);
+
+ if(!dir && notDir)
+ yaffsfs_set_error(-ENOTDIR);
+ else if(loop)
+ yaffsfs_set_error(-ELOOP);
+ else if(!dir)
+ yaffsfs_set_error(-ENOENT);
+ else if(strncmp(name,_Y("."),2) == 0)
+ yaffsfs_set_error(-EINVAL);
+ else if(!obj)
+ yaffsfs_set_error(-ENOENT);
+ else if(obj->my_dev->read_only)
+ yaffsfs_set_error(-EROFS);
+ else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffsfs_set_error(-EISDIR);
+ else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffsfs_set_error(-ENOTDIR);
+ else if(isDirectory && obj == obj->my_dev->root_dir)
+ yaffsfs_set_error(-EBUSY); /* Can't rmdir a root */
+ else {
+ result = yaffs_unlinker(dir,name);
+
+ if(result == YAFFS_FAIL && isDirectory)
+ yaffsfs_set_error(-ENOTEMPTY);
+ }
+
+ yaffsfs_Unlock();
+
+ return (result == YAFFS_FAIL) ? -1 : 0;
+}
+
+int yaffs_unlink(const YCHAR *path)
+{
+ return yaffsfs_do_unlink(path,0);
+}
+
+
+int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
+{
+ struct yaffs_obj *olddir = NULL;
+ struct yaffs_obj *newdir = NULL;
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *newobj = NULL;
+ YCHAR *oldname;
+ YCHAR *newname;
+ int result= YAFFS_FAIL;
+ int rename_allowed = 1;
+ int notOldDir = 0;
+ int notNewDir = 0;
+ int oldLoop = 0;
+ int newLoop = 0;
+
+ YCHAR *alt_newpath=NULL;
+
+ if(!oldPath || !newPath){
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ if(yaffsfs_CheckPath(oldPath) < 0 ||
+ yaffsfs_CheckPath(newPath) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if(yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0){
+ yaffsfs_set_error(-ENOMEM);
+ return -1;
+ }
+ if(alt_newpath)
+ newPath = alt_newpath;
+
+ yaffsfs_Lock();
+
+
+ olddir = yaffsfs_find_directory(NULL,oldPath,&oldname,0,&notOldDir,&oldLoop);
+ newdir = yaffsfs_find_directory(NULL,newPath,&newname,0,&notNewDir,&newLoop);
+ obj = yaffsfs_find_object(NULL,oldPath,0,0,NULL,NULL,NULL);
+ newobj = yaffsfs_find_object(NULL,newPath,0,0,NULL,NULL,NULL);
+
+ /* If the object being renamed is a directory and the
+ * path ended with a "/" then the olddir == obj.
+ * We pass through NULL for the old name to tell the lower layers
+ * to use olddir as the object.
+ */
+
+ if(olddir == obj)
+ oldname = NULL;
+
+ if((!olddir && notOldDir) || (!newdir && notNewDir)) {
+ yaffsfs_set_error(-ENOTDIR);
+ rename_allowed = 0;
+ } else if(oldLoop || newLoop) {
+ yaffsfs_set_error(-ELOOP);
+ rename_allowed = 0;
+ } else if (olddir && oldname && strncmp(oldname, _Y("."),2) == 0){
+ yaffsfs_set_error(-EINVAL);
+ rename_allowed = 0;
+ }else if(!olddir || !newdir || !obj) {
+ yaffsfs_set_error(-ENOENT);
+ rename_allowed = 0;
+ } else if(obj->my_dev->read_only){
+ yaffsfs_set_error(-EROFS);
+ rename_allowed = 0;
+ } else if(yaffs_is_non_empty_dir(newobj)){
+ yaffsfs_set_error(-ENOTEMPTY);
+ rename_allowed = 0;
+ } else if(olddir->my_dev != newdir->my_dev) {
+ /* Rename must be on same device */
+ yaffsfs_set_error(-EXDEV);
+ rename_allowed = 0;
+ } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+ /*
+ * It is a directory, check that it is not being renamed to
+ * being its own decendent.
+ * Do this by tracing from the new directory back to the root,
+ * checking for obj
+ */
+
+ struct yaffs_obj *xx = newdir;
+
+ while( rename_allowed && xx){
+ if(xx == obj)
+ rename_allowed = 0;
+ xx = xx->parent;
+ }
+ if(!rename_allowed)
+ yaffsfs_set_error(-EINVAL);
+ }
+
+ if(rename_allowed)
+ result = yaffs_rename_obj(olddir,oldname,newdir,newname);
+
+ yaffsfs_Unlock();
+
+ if(alt_newpath)
+ kfree(alt_newpath);
+
+ return (result == YAFFS_FAIL) ? -1 : 0;
+}
+
+static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
+{
+ int retVal = -ENOENT;
+
+ obj = yaffs_get_equivalent_obj(obj);
+
+ if(obj && buf){
+ buf->st_dev = (int)obj->my_dev->os_context;
+ buf->st_ino = obj->obj_id;
+ buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
+
+ if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+ buf->st_mode |= S_IFDIR;
+ else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+ buf->st_mode |= S_IFLNK;
+ else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+ buf->st_mode |= S_IFREG;
+
+ buf->st_nlink = yaffs_get_obj_link_count(obj);
+ buf->st_uid = 0;
+ buf->st_gid = 0;;
+ buf->st_rdev = obj->yst_rdev;
+ buf->st_size = yaffs_get_obj_length(obj);
+ buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
+ buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
+#if CONFIG_YAFFS_WINCE
+ buf->yst_wince_atime[0] = obj->win_atime[0];
+ buf->yst_wince_atime[1] = obj->win_atime[1];
+ buf->yst_wince_ctime[0] = obj->win_ctime[0];
+ buf->yst_wince_ctime[1] = obj->win_ctime[1];
+ buf->yst_wince_mtime[0] = obj->win_mtime[0];
+ buf->yst_wince_mtime[1] = obj->win_mtime[1];
+#else
+ buf->yst_atime = obj->yst_atime;
+ buf->yst_ctime = obj->yst_ctime;
+ buf->yst_mtime = obj->yst_mtime;
+#endif
+ retVal = 0;
+ }
+ return retVal;
+}
+
+static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_obj *dir = NULL;
+
+ int retVal = -1;
+ int notDir = 0;
+ int loop = 0;
+
+ yaffsfs_Lock();
+ obj = yaffsfs_find_object(NULL,path,0,1,&dir,&notDir,&loop);
+
+ if(!doLStat && obj)
+ {
+ obj = yaffsfs_follow_link(obj,0,&loop);
+ }
+
+ if(obj)
+ {
+ retVal = yaffsfs_DoStat(obj,buf);
+ }
+ else
+ {
+ // todo error not found
+ yaffsfs_set_error((retVal = -ENOENT));
+ }
+
+ yaffsfs_Unlock();
+
+ return retVal;
+
+}
+
+static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
+{
+ struct yaffs_obj *obj;
+
+ obj = in->iObj;
+
+ if(obj->unlinked)
+ yaffs_del_obj(obj);
+
+ obj->my_inode = NULL;
+ in->iObj = NULL;
+
+}
+
+static void yaffsfs_PutInode(int inodeId)
+{
+ if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
+ yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
+ in->count--;
+ if(in->count <= 0){
+ yaffsfs_ReleaseInode(in);
+ in->count = 0;
+ }
+ }
+}
+
+static int yaffsfs_NewHandle(yaffsfs_Handle **hptr)
+{
+ int i;
+ yaffsfs_Handle *h;
+
+ for(i = 0; i < YAFFSFS_N_HANDLES; i++){
+ h = &yaffsfs_handle[i];
+ if(h->useCount < 1){
+ memset(h,0,sizeof(yaffsfs_Handle));
+ h->fdId=-1;
+ h->useCount=1;
+ if(hptr)
+ *hptr = h;
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int yaffsfs_NewHandleAndFileDes(void)
+{
+ int i;
+ yaffsfs_FileDes *fd;
+ yaffsfs_Handle *h = NULL;
+ int handle = yaffsfs_NewHandle(&h);
+
+ if(handle < 0)
+ return -1;
+
+ for(i = 0; i < YAFFSFS_N_HANDLES; i++){
+ fd = &yaffsfs_fd[i];
+ if(fd->handleCount < 1){
+ memset(fd,0,sizeof(yaffsfs_FileDes));
+ fd->inodeId=-1;
+ fd->handleCount=1;
+ h->fdId = i;
+ return handle;
+ }
+ }
+
+ /* Dump the handle because we could not get a fd */
+ h->useCount = 0;
+ return -1;
+}
+
+/*
+ * yaffs_get_handle
+ * Increase use of handle when reading/writing a file
+ * Also gets the file descriptor.
+ */
+
+static int yaffsfs_GetHandle(int handle)
+{
+ yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+ if(h && h->useCount > 0){
+ h->useCount++;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * yaffs_put_handle
+ * Let go of a handle when closing a file or aborting an open or
+ * ending a read or write.
+ */
+
+static int yaffsfs_PutFileDes(int fdId)
+{
+ yaffsfs_FileDes *fd;
+
+ if(fdId >= 0 && fdId < YAFFSFS_N_HANDLES){
+ fd = &yaffsfs_fd[fdId];
+ fd->handleCount--;
+ if(fd->handleCount < 1){
+ if(fd->inodeId >= 0){
+ yaffsfs_PutInode(fd->inodeId);
+ fd->inodeId = -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int yaffsfs_PutHandle(int handle)
+{
+ yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+ if(h && h->useCount > 0){
+ h->useCount--;
+ if(h->useCount < 1){
+ yaffsfs_PutFileDes(h->fdId);
+ h->fdId = -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int yaffsfs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *dir = NULL;
+ YCHAR *name;
+ int handle = -1;
+ yaffsfs_FileDes *fd = NULL;
+ int openDenied = 0;
+ int symDepth = 0;
+ int errorReported = 0;
+ int rwflags = oflag & ( O_RDWR | O_RDONLY | O_WRONLY);
+ u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
+ u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
+ u8 sharedReadAllowed;
+ u8 sharedWriteAllowed;
+ u8 alreadyReading;
+ u8 alreadyWriting;
+ u8 readRequested;
+ u8 writeRequested;
+ int notDir = 0;
+ int loop = 0;
+
+ if(!path) {
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ if(yaffsfs_CheckPath(path) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return -1;
+ }
+
+ /* O_EXCL only has meaning if O_CREAT is specified */
+ if(!(oflag & O_CREAT))
+ oflag &= ~(O_EXCL);
+
+ /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
+ if( (oflag & O_CREAT) & (oflag & O_EXCL))
+ oflag &= ~(O_TRUNC);
+
+ /* Todo: Are there any more flag combos to sanitise ? */
+
+ /* Figure out if reading or writing is requested */
+
+ readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
+ writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
+
+ yaffsfs_Lock();
+
+ handle = yaffsfs_NewHandleAndFileDes();
+
+ if(handle < 0){
+ yaffsfs_set_error(-ENFILE);
+ errorReported = 1;
+ } else {
+
+ fd = yaffsfs_HandleToFileDes(handle);
+
+ /* try to find the exisiting object */
+ obj = yaffsfs_find_object(NULL,path,0,1,NULL,NULL,NULL);
+
+ obj = yaffsfs_follow_link(obj,symDepth++,&loop);
+
+ if(obj &&
+ obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
+ obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+ obj = NULL;
+
+
+ if(obj){
+
+ /* The file already exists or it might be a directory */
+
+ /* If it is a directory then we can't open it as a file */
+ if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+ openDenied = 1;
+ yaffsfs_set_error(-EISDIR);
+ errorReported = 1;
+ }
+
+ /* Open should fail if O_CREAT and O_EXCL are specified since
+ * the file exists
+ */
+ if(!errorReported && (oflag & O_EXCL) && (oflag & O_CREAT)){
+ openDenied = 1;
+ yaffsfs_set_error(-EEXIST);
+ errorReported = 1;
+ }
+
+ /* Check file permissions */
+ if( readRequested && !(obj->yst_mode & S_IREAD))
+ openDenied = 1;
+
+ if( writeRequested && !(obj->yst_mode & S_IWRITE))
+ openDenied = 1;
+
+ if( !errorReported && writeRequested &&
+ obj->my_dev->read_only){
+ openDenied = 1;
+ yaffsfs_set_error(-EROFS);
+ errorReported = 1;
+ }
+
+ if(openDenied && !errorReported ) {
+ /* Error if the file exists but permissions are refused. */
+ yaffsfs_set_error(-EACCES);
+ errorReported = 1;
+ }
+
+ /* Check sharing of an existing object. */
+ if(!openDenied){
+ yaffsfs_FileDes *fdx;
+ int i;
+
+ sharedReadAllowed = 1;
+ sharedWriteAllowed = 1;
+ alreadyReading = 0;
+ alreadyWriting = 0;
+ for( i = 0; i < YAFFSFS_N_HANDLES; i++){
+ fdx = &yaffsfs_fd[i];
+ if(fdx->handleCount > 0 &&
+ fdx->inodeId >= 0 &&
+ yaffsfs_inode[fdx->inodeId].iObj == obj){
+ if(!fdx->shareRead)
+ sharedReadAllowed = 0;
+ if(!fdx->shareWrite)
+ sharedWriteAllowed = 0;
+ if(fdx->reading)
+ alreadyReading = 1;
+ if(fdx->writing)
+ alreadyWriting = 1;
+ }
+ }
+
+
+
+ if((!sharedReadAllowed && readRequested)||
+ (!shareRead && alreadyReading) ||
+ (!sharedWriteAllowed && writeRequested) ||
+ (!shareWrite && alreadyWriting)){
+ openDenied = 1;
+ yaffsfs_set_error(-EBUSY);
+ errorReported=1;
+ }
+ }
+
+ }
+
+ /* If we could not open an existing object, then let's see if
+ * the directory exists. If not, error.
+ */
+ if(!obj && !errorReported){
+ dir = yaffsfs_find_directory(NULL,path,&name,0,&notDir,&loop);
+ if(!dir && notDir){
+ yaffsfs_set_error(-ENOTDIR);
+ errorReported = 1;
+ } else if(loop){
+ yaffsfs_set_error(-ELOOP);
+ errorReported = 1;
+ } else if(!dir){
+ yaffsfs_set_error(-ENOENT);
+ errorReported = 1;
+ }
+ }
+
+ if(!obj && dir && !errorReported && (oflag & O_CREAT)) {
+ /* Let's see if we can create this file if it does not exist. */
+ if(dir->my_dev->read_only){
+ yaffsfs_set_error(-EROFS);
+ errorReported = 1;
+ } else
+ obj = yaffs_create_file(dir,name,mode,0,0);
+
+ if(!obj && !errorReported){
+ yaffsfs_set_error(-ENOSPC);
+ errorReported = 1;
+ }
+ }
+
+ if(!obj && dir && !errorReported && !(oflag & O_CREAT)) {
+ /* Error if the file does not exist and CREAT is not set. */
+ yaffsfs_set_error(-ENOENT);
+ errorReported = 1;
+ }
+
+ if(obj && !openDenied) {
+ int inodeId = yaffsfs_GetInodeIdForObject(obj);
+
+ if(inodeId<0) {
+ /*
+ * Todo: Fix any problem if inodes run out, though that
+ * can't happen if the number of inode items >= number of handles.
+ */
+ }
+
+ fd->inodeId = inodeId;
+ fd->reading = readRequested;
+ fd->writing = writeRequested;
+ fd->append = (oflag & O_APPEND) ? 1 : 0;
+ fd->position = 0;
+ fd->shareRead = shareRead;
+ fd->shareWrite = shareWrite;
+
+ /* Hook inode to object */
+ obj->my_inode = (void*) &yaffsfs_inode[inodeId];
+
+ if((oflag & O_TRUNC) && fd->writing)
+ yaffs_resize_file(obj,0);
+ } else {
+ yaffsfs_PutHandle(handle);
+ if(!errorReported)
+ yaffsfs_set_error(0); /* Problem */
+ handle = -1;
+ }
+ }
+
+ yaffsfs_Unlock();
+
+ return handle;
+}
+
+int yaffs_open(const YCHAR *path, int oflag, int mode)
+{
+ return yaffsfs_open_sharing(path, oflag, mode,
+ YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
+}
+
+int yaffs_stat(const char *path, struct yaffs_stat *buf)
+{
+ return yaffsfs_DoStatOrLStat(path,buf,0);
+}
+
+int yaffs_close(int handle)
+{
+ yaffsfs_Handle *h = NULL;
+ struct yaffs_obj *obj = NULL;
+ int retVal = -1;
+
+ yaffsfs_Lock();
+
+ h = yaffsfs_HandleToPointer(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if(!h || !obj)
+ yaffsfs_set_error(-EBADF);
+ else {
+ /* clean up */
+ yaffs_flush_file(obj,1,0);
+ yaffsfs_PutHandle(handle);
+ retVal = 0;
+ }
+
+ yaffsfs_Unlock();
+
+ return retVal;
+}
+
+int yaffsfs_do_write(int handle, const void *buf, unsigned int nbyte)
+{
+ yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ int pos = 0;
+ int nWritten = -1;
+ int writeThrough = 0;
+
+ yaffsfs_Lock();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if(!fd || !obj)
+ {
+ // bad handle
+ yaffsfs_set_error(-EBADF);
+ }
+ else if( fd && obj && !fd->writing)
+ {
+ yaffsfs_set_error(-EPERM);
+ }
+ else if( fd && obj)
+ {
+ if(fd->append)
+ {
+ pos = yaffs_get_obj_length(obj);
+ }
+ else
+ {
+ pos = fd->position;
+ }
+
+ nWritten = yaffs_wr_file(obj,buf,pos,nbyte,writeThrough);
+
+ if(nWritten >= 0)
+ {
+ fd->position = pos + nWritten;
+
+ /* If amount written not same as nbytes then
+ * filesystem must have run out of space */
+ if (nWritten != nbyte)
+ yaffsfs_set_error(-ENOSPC);
+ }
+ else
+ {
+ //todo error
+ }
+
+ }
+
+ yaffsfs_Unlock();
+
+
+ return (nWritten >= 0) ? nWritten : -1;
+
+}
+
+int yaffs_write(int handle, void *buf, unsigned int nbyte)
+{
+ return yaffsfs_do_write(handle, buf, nbyte);
+}
+
+int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, int isPread, int offset)
+{
+ yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ int pos = 0;
+ int startPos = 0;
+ int endPos = 0;
+ int nRead = 0;
+ int nToRead = 0;
+ int totalRead = 0;
+ unsigned int maxRead;
+ u8 *buf = (u8 *)vbuf;
+
+ if(!vbuf){
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if(!fd || !obj){
+ /* bad handle */
+ yaffsfs_set_error(-EBADF);
+ totalRead = -1;
+ } else if(!fd->reading){
+ /* Not a reading handle */
+ yaffsfs_set_error(-EINVAL);
+ totalRead = -1;
+ } else if(nbyte > YAFFS_MAX_FILE_SIZE){
+ yaffsfs_set_error(-EINVAL);
+ totalRead = -1;
+ } else {
+ if(isPread)
+ startPos = offset;
+ else
+ startPos = fd->position;
+
+ pos = startPos;
+
+ if(yaffs_get_obj_length(obj) > pos)
+ maxRead = yaffs_get_obj_length(obj) - pos;
+ else
+ maxRead = 0;
+
+ if(nbyte > maxRead)
+ nbyte = maxRead;
+
+
+ yaffsfs_GetHandle(handle);
+
+ endPos = pos + nbyte;
+
+ if(pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
+ nbyte > YAFFS_MAX_FILE_SIZE ||
+ endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE){
+ totalRead = -1;
+ nbyte = 0;
+ }
+
+ while(nbyte > 0) {
+ nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
+ if(nToRead > nbyte)
+ nToRead = nbyte;
+
+ /* Tricky bit...
+ * Need to reverify object in case the device was
+ * unmounted in another thread.
+ */
+ obj = yaffsfs_HandleToObject(handle);
+ if(!obj)
+ nRead = 0;
+ else
+ nRead = yaffs_file_rd(obj,buf,pos,nToRead);
+
+ if(nRead > 0){
+ totalRead += nRead;
+ pos += nRead;
+ buf += nRead;
+ }
+
+ if(nRead == nToRead)
+ nbyte-=nRead;
+ else
+ nbyte = 0; /* no more to read */
+
+
+ if(nbyte > 0){
+ yaffsfs_Unlock();
+ yaffsfs_Lock();
+ }
+
+ }
+
+ yaffsfs_PutHandle(handle);
+
+ if(!isPread) {
+ if(totalRead >= 0)
+ fd->position = startPos + totalRead;
+ else
+ yaffsfs_set_error(-EINVAL);
+ }
+
+ }
+
+ yaffsfs_Unlock();
+
+ return (totalRead >= 0) ? totalRead : -1;
+
+}
+
+int yaffs_read(int handle, void *buf, unsigned int nbyte)
+{
+ return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
+}
+
+
+int yaffs_mkdir(const YCHAR *path, mode_t mode)
+{
+ struct yaffs_obj *parent = NULL;
+ struct yaffs_obj *dir = NULL;
+ YCHAR *name;
+ YCHAR *alt_path = NULL;
+ int retVal= -1;
+ int notDir = 0;
+ int loop = 0;
+
+ if(!path){
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ if(yaffsfs_CheckPath(path) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
+ yaffsfs_set_error(-ENOMEM);
+ return -1;
+ }
+ if(alt_path)
+ path = alt_path;
+
+ yaffsfs_Lock();
+ parent = yaffsfs_find_directory(NULL,path,&name,0,&notDir,&loop);
+ if(!parent && notDir)
+ yaffsfs_set_error(-ENOTDIR);
+ else if(loop)
+ yaffsfs_set_error(-ELOOP);
+ else if(!parent)
+ yaffsfs_set_error(-ENOENT);
+ else if(strnlen(name,5) == 0){
+ /* Trying to make the root itself */
+ yaffsfs_set_error(-EEXIST);
+ } else if(parent->my_dev->read_only)
+ yaffsfs_set_error(-EROFS);
+ else {
+ dir = yaffs_create_dir(parent,name,mode,0,0);
+ if(dir)
+ retVal = 0;
+ else if (yaffs_find_by_name(parent,name))
+ yaffsfs_set_error(-EEXIST); /* the name already exists */
+ else
+ yaffsfs_set_error(-ENOSPC); /* just assume no space */
+ }
+
+ yaffsfs_Unlock();
+
+ if(alt_path)
+ kfree(alt_path);
+
+ return retVal;
+}
+
+int yaffs_rmdir(const YCHAR *path)
+{
+ int result;
+ YCHAR *alt_path;
+
+ if(!path){
+ yaffsfs_set_error(-EFAULT);
+ return -1;
+ }
+
+ if(yaffsfs_CheckPath(path) < 0){
+ yaffsfs_set_error(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
+ yaffsfs_set_error(-ENOMEM);
+ return -1;
+ }
+ if(alt_path)
+ path = alt_path;
+ result = yaffsfs_do_unlink(path,1);
+ if(alt_path)
+ kfree(alt_path);
+ return result;
+}
+
+int yaffs_DumpDevStruct(const char *path)
+{
+ char *rest;
+
+ struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
+
+ if(obj)
+ {
+ struct yaffs_dev *dev = obj->my_dev;
+
+ printf("\n"
+ "nStartBlock.......... %d\n"
+ "nEndBlock............ %d\n"
+ "nReserveredBlocks.... %d\n"
+ "nPageWrites.......... %d\n"
+ "nPageReads........... %d\n"
+ "nBlockErasures....... %d\n"
+ "nGCCopies............ %d\n"
+ "garbageCollections... %d\n"
+ "passiveGarbageColl'ns %d\n",
+ dev->param.start_block,
+ dev->param.end_block,
+ dev->param.n_reserved_blocks,
+ dev->n_page_writes,
+ dev->n_page_reads,
+ dev->n_erasures,
+ dev->n_gc_copies,
+ dev->all_gcs,
+ dev->passive_gc_count
+ );
+
+ }
+ return 0;
+}
+
+void yaffsfs_initialise(void)
+{
+ yaffsfs_InitHandles();
+}
diff --git a/fs/yaffs2-new/yaffsfs.h b/fs/yaffs2-new/yaffsfs.h
new file mode 100644
index 0000000000..1e7040ea90
--- /dev/null
+++ b/fs/yaffs2-new/yaffsfs.h
@@ -0,0 +1,64 @@
+
+extern int cmd_yaffs_mount(const char *path);
+extern int cmd_yaffs_unmount(const char *path);
+extern int cmd_yaffs_ls(const char *mountpt, int longlist);
+extern int cmd_yaffs_df(const char *path, loff_t *size);
+extern int cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
+extern int cmd_yaffs_mread_file(char *fn, char *addr, long *size);
+extern int cmd_yaffs_mkdir(const char *dir);
+extern int cmd_yaffs_rmdir(const char *dir);
+extern int cmd_yaffs_rm(const char *path);
+extern int cmd_yaffs_mv(const char *oldPath, const char *newPath);
+
+extern int yaffsfs_mount(const char *path);
+extern int yaffsfs_unmount(const char *path);
+
+
+#define YAFFS_SHARE_READ 1
+#define YAFFS_SHARE_WRITE 2
+
+#define YAFFS_MAX_FILE_SIZE (0x7ffffff)
+
+struct yaffs_dirent{
+ long d_ino; /* inode number */
+ off_t d_off; /* offset to this dirent */
+ unsigned short d_reclen; /* length of this d_name */
+ char d_name [NAME_MAX+1]; /* file name (null-terminated) */
+ unsigned d_dont_use; /* debug pointer, not for public consumption */
+};
+
+typedef struct yaffs_dirent yaffs_dirent;
+
+
+typedef struct __opaque yaffs_DIR;
+
+struct yaffs_stat {
+ int st_dev; /* device */
+ int st_ino; /* inode */
+ mode_t st_mode; /* protection */
+ int st_nlink; /* number of hard links */
+ int st_uid; /* user ID of owner */
+ int st_gid; /* group ID of owner */
+ unsigned st_rdev; /* device type (if inode device) */
+ off_t st_size; /* total size, in bytes */
+ unsigned long st_blksize; /* blocksize for filesystem I/O */
+ unsigned long st_blocks; /* number of blocks allocated */
+ unsigned long yst_atime; /* time of last access */
+ unsigned long yst_mtime; /* time of last modification */
+ unsigned long yst_ctime; /* time of last change */
+};
+
+extern loff_t yaffs_freespace(const YCHAR *path);
+extern int yaffs_unlink(const YCHAR *path);
+extern int yaffs_open(const char *path, int oflag, int mode) ;
+extern int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
+extern int yaffs_write(int fd, void *buf, unsigned int nbyte) ;
+extern int yaffs_close(int fd);
+extern yaffs_DIR *yaffs_opendir(const char *dirname);
+extern struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp);
+extern int yaffs_stat(const char *path, struct yaffs_stat *buf) ;
+extern int yaffs_mkdir(const char *path, mode_t mode);
+extern int yaffs_rmdir(const char *path);
+extern int yaffs_rename(const char *new_path, const char *old_path);
+
+extern void yaffsfs_initialise(void);
diff --git a/fs/yaffs2-new/yaffsfs_errno.c b/fs/yaffs2-new/yaffsfs_errno.c
new file mode 100644
index 0000000000..380dfd60cc
--- /dev/null
+++ b/fs/yaffs2-new/yaffsfs_errno.c
@@ -0,0 +1,119 @@
+/*
+ * (C) Copyright 2011 Logic Product Development, Inc.
+ * Author :
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * YAFFS Errno handling
+ *
+ * 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 "yaffsfs_errno.h"
+
+int yaffsfs_errno;
+char *yaffsfs_errstr;
+void yaffsfs_set_error(int x)
+{
+ yaffsfs_errno = x;
+ switch(x) {
+ case 0:
+ yaffsfs_errstr = "Success";
+ break;
+ case -EPERM:
+ yaffsfs_errstr = "Operation not permitted";
+ break;
+ case -ENOENT:
+ yaffsfs_errstr = "No such file or directory";
+ break;
+ case -EBADF:
+ yaffsfs_errstr = "Bad file number";
+ break;
+ case -ENOMEM:
+ yaffsfs_errstr = "Out of memory";
+ break;
+ case -EACCES:
+ yaffsfs_errstr = "Permission denied";
+ break;
+ case -EFAULT:
+ yaffsfs_errstr = "Bad address";
+ break;
+ case -EBUSY:
+ yaffsfs_errstr = "Device or resource busy";
+ break;
+ case -EEXIST:
+ yaffsfs_errstr = "File exists";
+ break;
+ case -ENODEV:
+ yaffsfs_errstr = "No such device";
+ break;
+ case -ENOTDIR:
+ yaffsfs_errstr = "Not a directory";
+ break;
+ case -EISDIR:
+ yaffsfs_errstr = "Is a directory";
+ break;
+ case -EINVAL:
+ yaffsfs_errstr = "Invalid argument";
+ break;
+ case -ENFILE:
+ yaffsfs_errstr = "File table overflow";
+ break;
+ case -ENOSPC:
+ yaffsfs_errstr = "No space left on device";
+ break;
+ case -EROFS:
+ yaffsfs_errstr = "Read-only file system";
+ break;
+ case -ERANGE:
+ yaffsfs_errstr = "Math result not representable";
+ break;
+ case -ENAMETOOLONG:
+ yaffsfs_errstr = "File name too long";
+ break;
+ case -ENOTEMPTY:
+ yaffsfs_errstr = "Directory not empty";
+ break;
+ case -ELOOP:
+ yaffsfs_errstr = "Too many symbolic links encountered";
+ break;
+ case -ENODATA:
+ yaffsfs_errstr = "No data available";
+ break;
+ case -EBADMSG:
+ yaffsfs_errstr = "Not a data message";
+ break;
+ case -EUCLEAN:
+ yaffsfs_errstr = "Structure needs cleaning";
+ break;
+ default:
+ printf("%s: Huh? yaffs_errno called from %p with %d\n",
+ __FUNCTION__, __builtin_return_address(0), x);
+ yaffsfs_errstr = "Unknown!";
+ break;
+ }
+}
+
+int yaffsfs_get_error(char **errstr)
+{
+ if (errstr)
+ *errstr = yaffsfs_errstr;
+ return yaffsfs_errno;
+}
+
diff --git a/fs/yaffs2-new/yaffsfs_errno.h b/fs/yaffs2-new/yaffsfs_errno.h
new file mode 100644
index 0000000000..cad7a0d0b7
--- /dev/null
+++ b/fs/yaffs2-new/yaffsfs_errno.h
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2011 Logic Product Development, Inc.
+ * Author :
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * YAFFS Errno handling
+ *
+ * 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
+ */
+
+extern void yaffsfs_set_error(int x);
+extern int yaffsfs_get_error(char **errstr);
+
+#ifndef EPERM
+#define EPERM 1
+#endif
+
+#ifndef ENOENT
+#define ENOENT 2
+#endif
+
+#ifndef EBADF
+#define EBADF 9
+#endif
+
+#ifndef ENOMEM
+#define ENOMEM 12
+#endif
+
+#ifndef EACCES
+#define EACCES 13
+#endif
+
+#ifndef EFAULT
+#define EFAULT 14
+#endif
+
+#ifndef EBUSY
+#define EBUSY 16
+#endif
+
+#ifndef EEXIST
+#define EEXIST 17
+#endif
+
+#ifndef EXDEV
+#define EXDEV 18
+#endif
+
+#ifndef ENODEV
+#define ENODEV 19
+#endif
+
+#ifndef ENOTDIR
+#define ENOTDIR 20
+#endif
+
+#ifndef EISDIR
+#define EISDIR 21
+#endif
+
+#ifndef EINVAL
+#define EINVAL 22
+#endif
+
+#ifndef ENFILE
+#define ENFILE 23
+#endif
+
+#ifndef ENOSPC
+#define ENOSPC 28
+#endif
+
+#ifndef EROFS
+#define EROFS 30
+#endif
+
+#ifndef ERANGE
+#define ERANGE 34
+#endif
+
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG 36
+#endif
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY 39
+#endif
+
+#ifndef ELOOP
+#define ELOOP 40
+#endif
+
+#ifndef ENODATA
+#define ENODATA 61
+#endif
+
+#ifndef EBADMSG
+#define EBADMSG 74
+#endif
+
+#ifndef EUCLEAN
+#define EUCLEAN 117
+#endif
diff --git a/fs/yaffs2-new/ydirectenv.h b/fs/yaffs2-new/ydirectenv.h
new file mode 100644
index 0000000000..e9a0174f66
--- /dev/null
+++ b/fs/yaffs2-new/ydirectenv.h
@@ -0,0 +1,97 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * ydirectenv.h: Environment wrappers for YAFFS direct.
+ */
+
+#ifndef __YDIRECTENV_H__
+#define __YDIRECTENV_H__
+
+/* Direct interface */
+
+#include "devextras.h"
+
+/* XXX U-BOOT XXX */
+#if 0
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+#include "assert.h"
+#endif
+#if 1
+#include "yaffs_malloc.h"
+#endif
+
+/* XXX U-BOOT XXX */
+#if 0
+#define YBUG() assert(1)
+#endif
+
+#define YCHAR char
+#define _Y(x) x
+#if 0
+#define yaffs_strcpy(a,b) strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
+#define yaffs_strlen(s) strlen(s)
+#define yaffs_sprintf sprintf
+#define yaffs_toupper(a) toupper(a)
+#endif
+
+#ifdef NO_Y_INLINE
+#define Y_INLINE
+#else
+#define Y_INLINE inline
+#endif
+
+#define cond_resched() do {} while(0)
+
+#define abs(x) ((x) < 0 ? -(x) : (x))
+
+#define YYIELD() do {} while(0)
+
+void yaffs_qsort(void *aa, size_t n, size_t es,
+ int (*cmp)(const void *, const void *));
+
+#define sort(base, n, sz, cmp_fn, swp) yaffs_qsort(base, n, sz, cmp_fn)
+
+#if 0
+//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
+//#define YALERT(s) YINFO(s)
+
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+#endif
+
+#define YAFFS_LOSTNFOUND_NAME "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX "obj"
+//#define YPRINTF(x) printf x
+
+#include "yaffscfg.h"
+
+#define Y_CURRENT_TIME yaffsfs_CurrentTime()
+#define Y_TIME_CONVERT(x) x
+
+#define YAFFS_ROOT_MODE 0666
+#define YAFFS_LOSTNFOUND_MODE 0666
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+
+#endif
diff --git a/fs/yaffs2-new/yportenv.h b/fs/yaffs2-new/yportenv.h
new file mode 100644
index 0000000000..0d8215049c
--- /dev/null
+++ b/fs/yaffs2-new/yportenv.h
@@ -0,0 +1,239 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+/* XXX U-BOOT XXX */
+#ifndef CONFIG_YAFFS_DIRECT
+#define CONFIG_YAFFS_DIRECT
+#endif
+
+#if defined CONFIG_YAFFS_WINCE
+
+#include "ywinceenv.h"
+
+/* XXX U-BOOT XXX */
+#elif 0 /* defined __KERNEL__ */
+
+#include "moduleconfig.h"
+
+/* Linux kernel */
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#if 0
+#define _Y(x) x
+#define yaffs_strcpy(a,b) strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
+#define yaffs_strlen(s) strlen(s)
+#define yaffs_sprintf sprintf
+#define yaffs_toupper(a) toupper(a)
+#endif
+
+#define Y_INLINE inline
+
+#define YAFFS_LOSTNFOUND_NAME "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX "obj"
+
+/* #define YPRINTF(x) printk x */
+#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
+#define YFREE(x) kfree(x)
+#define YMALLOC_ALT(x) vmalloc(x)
+#define YFREE_ALT(x) vfree(x)
+#define YMALLOC_DMA(x) YMALLOC(x)
+
+// KR - added for use in scan so processes aren't blocked indefinitely.
+#define YYIELD() schedule()
+
+#define YAFFS_ROOT_MODE 0666
+#define YAFFS_LOSTNFOUND_MODE 0666
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
+#define Y_TIME_CONVERT(x) (x).tv_sec
+#else
+#define Y_CURRENT_TIME CURRENT_TIME
+#define Y_TIME_CONVERT(x) (x)
+#endif
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#define TENDSTR "\n"
+#define TSTR(x) KERN_WARNING x
+#define TOUT(p) printk p
+
+#define yaffs_trace(mask, fmt, args...) \
+ do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
+ printk(KERN_WARNING "yaffs: " fmt, ## args); \
+ } while (0)
+
+#define compile_time_assertion(assertion) \
+ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
+
+#elif defined CONFIG_YAFFS_DIRECT
+
+/* Direct interface */
+#include "ydirectenv.h"
+
+#elif defined CONFIG_YAFFS_UTIL
+
+/* Stuff for YAFFS utilities */
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "devextras.h"
+
+#define YMALLOC(x) malloc(x)
+#define YFREE(x) free(x)
+#define YMALLOC_ALT(x) malloc(x)
+#define YFREE_ALT(x) free(x)
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x) x
+#define yaffs_strcpy(a,b) strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strlen(s) strlen(s)
+#define yaffs_sprintf sprintf
+#define yaffs_toupper(a) toupper(a)
+
+#define Y_INLINE inline
+
+/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
+/* #define YALERT(s) YINFO(s) */
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+
+#define YAFFS_LOSTNFOUND_NAME "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX "obj"
+/* #define YPRINTF(x) printf x */
+
+#define YAFFS_ROOT_MODE 0666
+#define YAFFS_LOSTNFOUND_MODE 0666
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#else
+/* Should have specified a configuration type */
+#error Unknown configuration
+
+#endif
+
+#ifndef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+/* Mode flags */
+
+#ifndef XATTR_CREATE
+#define XATTR_CREATE 1
+#endif
+
+#ifndef XATTR_REPLACE
+#define XATTR_REPLACE 2
+#endif
+
+#ifndef S_IFMT
+#define S_IFMT 0170000
+#endif
+
+#ifndef S_IFLNK
+#define S_IFLNK 0120000
+#endif
+
+#ifndef S_IFDIR
+#define S_IFDIR 0040000
+#endif
+
+#ifndef S_IFREG
+#define S_IFREG 0100000
+#endif
+
+#ifndef S_IREAD
+#define S_IREAD 0000400
+#endif
+
+#ifndef S_IWRITE
+#define S_IWRITE 0000200
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 00
+#endif
+
+#ifndef O_WRONLY
+#define O_WRONLY 01
+#endif
+
+#ifndef O_RDWR
+#define O_RDWR 02
+#endif
+
+#ifndef O_CREAT
+#define O_CREAT 0100
+#endif
+
+#ifndef O_EXCL
+#define O_EXCL 0200
+#endif
+
+#ifndef O_TRUNC
+#define O_TRUNC 01000
+#endif
+
+#ifndef O_APPEND
+#define O_APPEND 02000
+#endif
+
+/* Errno entries */
+
+#include "yaffsfs_errno.h"
+
+/* see yaffs_fs.c */
+extern unsigned int yaffs_traceMask;
+extern unsigned int yaffs_wr_attempts;
+
+#define CONFIG_YAFFS_DEBUG
+
+#ifdef CONFIG_YAFFS_DEBUG
+#define yaffs_trace(msk, fmt, ...) do { \
+ if (yaffs_trace_mask & (msk)) \
+ printf(fmt "\n", ##__VA_ARGS__); \
+ } while (0)
+#else
+#define yaffs_trace(msk, fmt, ...) do { \
+ } while (0)
+#endif
+
+#endif
diff --git a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h
index f6e53610d6..b0147b85a4 100644
--- a/fs/yaffs2/devextras.h
+++ b/fs/yaffs2/devextras.h
@@ -41,169 +41,7 @@ typedef unsigned __u32;
#endif
#include <asm/types.h>
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-#define prefetch(x) 1
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-#define INIT_LIST_HEAD(ptr) do { \
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static __inline__ void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static __inline__ void list_add(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static __inline__ void list_add_tail(struct list_head *new,
- struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static __inline__ void __list_del(struct list_head *prev,
- struct list_head *next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static __inline__ void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static __inline__ void list_del_init(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static __inline__ int list_empty(struct list_head *head)
-{
- return head->next == head;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static __inline__ void list_splice(struct list_head *list,
- struct list_head *head)
-{
- struct list_head *first = list->next;
-
- if (first != list) {
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
- }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-/**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next, prefetch(pos->next); pos != (head); \
- pos = pos->next, prefetch(pos->next))
-
-/**
- * list_for_each_safe - iterate over a list safe against removal
- * of list entry
- * @pos: the &struct list_head to use as a loop counter.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
+#include <linux/list.h>
/*
* File types
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index b368844296..29d70aa49f 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -78,11 +78,15 @@ static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name,
int force, int isShrink, int shadows);
static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj);
static int yaffs_CheckStructures(void);
+#ifdef YAFFS_USE_DELETEWORKER
static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
int chunkOffset, int *limit);
+#endif
static int yaffs_DoGenericObjectDeletion(yaffs_Object * in);
+#if 0
static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo);
+#endif
static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
@@ -396,10 +400,12 @@ static int yaffs_SkipVerification(yaffs_Device *dev)
return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
}
+#ifdef YAFFS_USE_SKIPFULLVERIFICATION
static int yaffs_SkipFullVerification(yaffs_Device *dev)
{
return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
}
+#endif
static int yaffs_SkipNANDVerification(yaffs_Device *dev)
{
@@ -596,7 +602,7 @@ static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh,
}
-
+#ifdef YAFFS_USE_VERIFYTNODEWORKER
static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn,
__u32 level, int chunkOffset)
{
@@ -642,7 +648,7 @@ static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn,
return ok;
}
-
+#endif
static void yaffs_VerifyFile(yaffs_Object *obj)
{
@@ -1546,7 +1552,7 @@ static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk,
return -1;
}
-
+#ifdef YAFFS_USE_DELETEWORKER
/* DeleteWorker scans backwards through the tnode tree and deletes all the
* chunks and tnodes in the file
* Returns 1 if the tree was deleted.
@@ -1643,6 +1649,7 @@ static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
return 1;
}
+#endif
static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk)
{
@@ -2140,7 +2147,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
{
yaffs_Object *theObject;
- yaffs_Tnode *tn;
+ yaffs_Tnode *tn = NULL;
if (number < 0) {
number = yaffs_CreateNewObjectNumber(dev);
@@ -2255,7 +2262,7 @@ static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
const YCHAR * aliasString, __u32 rdev)
{
yaffs_Object *in;
- YCHAR *str;
+ YCHAR *str = NULL;
yaffs_Device *dev = parent->myDev;
@@ -4605,8 +4612,8 @@ int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
int nBytes)
{
- int chunk;
- int start;
+ __u32 chunk;
+ __u32 start;
int nToCopy;
int n = nBytes;
int nDone = 0;
@@ -4725,8 +4732,8 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
int nBytes, int writeThrough)
{
- int chunk;
- int start;
+ __u32 chunk;
+ __u32 start;
int nToCopy;
int n = nBytes;
int nDone = 0;
@@ -4960,8 +4967,8 @@ int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize)
{
int oldFileSize = in->variant.fileVariant.fileSize;
- int newSizeOfPartialChunk;
- int newFullChunks;
+ __u32 newSizeOfPartialChunk;
+ __u32 newFullChunks;
yaffs_Device *dev = in->myDev;
@@ -5391,7 +5398,7 @@ static int yaffs_Scan(yaffs_Device * dev)
yaffs_BlockState state;
yaffs_Object *hardList = NULL;
yaffs_BlockInfo *bi;
- int sequenceNumber;
+ __u32 sequenceNumber;
yaffs_ObjectHeader *oh;
yaffs_Object *in;
yaffs_Object *parent;
@@ -5958,7 +5965,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev)
yaffs_BlockState state;
yaffs_Object *hardList = NULL;
yaffs_BlockInfo *bi;
- int sequenceNumber;
+ __u32 sequenceNumber;
yaffs_ObjectHeader *oh;
yaffs_Object *in;
yaffs_Object *parent;
@@ -7232,7 +7239,7 @@ int yaffs_GutsInitialise(yaffs_Device * dev)
dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
}
- buf = dev->srCache = YMALLOC(srCacheBytes);
+ buf = (__u8 *)(dev->srCache = YMALLOC(srCacheBytes));
if(dev->srCache)
memset(dev->srCache,0,srCacheBytes);
@@ -7489,3 +7496,18 @@ static int yaffs_CheckStructures(void)
return YAFFS_OK;
}
+
+#ifdef NO_Y_INLINE
+/* Function to manipulate block info */
+yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
+{
+ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
+ blk));
+ YBUG();
+ }
+ return &dev->blockInfo[blk - dev->internalStartBlock];
+}
+#endif
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index 1f75efd098..ee3dd26095 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -584,7 +584,7 @@ struct yaffs_DeviceStruct {
yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
- yaffs_BlockState * state, int *sequenceNumber);
+ yaffs_BlockState * state, __u32 *sequenceNumber);
#endif
int isYaffs2;
@@ -801,6 +801,9 @@ typedef struct {
__u32 head;
} yaffs_CheckpointValidity;
+#ifdef NO_Y_INLINE
+extern yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk);
+#else
/* Function to manipulate block info */
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
{
@@ -813,6 +816,7 @@ static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
}
return &dev->blockInfo[blk - dev->internalStartBlock];
}
+#endif
/*----------------------- YAFFS Functions -----------------------*/
diff --git a/fs/yaffs2/yaffs_malloc.h b/fs/yaffs2/yaffs_malloc.h
index 3ed6175163..67d09e82c0 100644
--- a/fs/yaffs2/yaffs_malloc.h
+++ b/fs/yaffs2/yaffs_malloc.h
@@ -19,7 +19,11 @@
#include <stdlib.h>
#endif
-void *yaffs_malloc(size_t size);
+#ifdef YAFFS_DEBUG_MALLOC
+extern void *yaffs_malloc(const char *func, int line, size_t size);
+#else
+extern void *yaffs_malloc(size_t size);
+#endif
void yaffs_free(void *ptr);
#endif
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
index f569b999f4..8a7f72778b 100644
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -192,7 +192,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
- yaffs_BlockState * state, int *sequenceNumber)
+ yaffs_BlockState * state, __u32 *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
index b67ba52aa4..19f63b3368 100644
--- a/fs/yaffs2/yaffs_mtdif2.h
+++ b/fs/yaffs2/yaffs_mtdif2.h
@@ -24,6 +24,6 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
- yaffs_BlockState * state, int *sequenceNumber);
+ yaffs_BlockState * state, __u32 *sequenceNumber);
#endif
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
index e790be61a5..4077634693 100644
--- a/fs/yaffs2/yaffs_nand.c
+++ b/fs/yaffs2/yaffs_nand.c
@@ -101,7 +101,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
- unsigned *sequenceNumber)
+ __u32 *sequenceNumber)
{
blockNo -= dev->blockOffset;
diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
index 48e3f7ec6d..9a17c02f20 100644
--- a/fs/yaffs2/yaffs_nand.h
+++ b/fs/yaffs2/yaffs_nand.h
@@ -33,7 +33,7 @@ int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
- unsigned *sequenceNumber);
+ __u32 *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
index 70a8a8c72a..ae14beb80e 100644
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -502,7 +502,7 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state,
- int *sequenceNumber)
+ __u32 *sequenceNumber)
{
yaffs_Spare spare0, spare1;
diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
index a61e3ba14f..169be0ce66 100644
--- a/fs/yaffs2/yaffs_tagscompat.h
+++ b/fs/yaffs2/yaffs_tagscompat.h
@@ -31,7 +31,7 @@ int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
- state, int *sequenceNumber);
+ state, __u32 *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
diff --git a/fs/yaffs2/yaffscfg.c b/fs/yaffs2/yaffscfg.c
index 16e84a4210..e5739a8452 100644
--- a/fs/yaffs2/yaffscfg.c
+++ b/fs/yaffs2/yaffscfg.c
@@ -61,10 +61,25 @@ __u32 yaffsfs_CurrentTime(void)
return 0;
}
+#ifdef YAFFS_DEBUG_MALLOC
+void *yaffs_malloc(const char *func, int line, size_t size)
+{
+ void *ptr;
+ ptr = malloc(size);
+ if (!ptr)
+ printf("%s:%d %s failed to allocate %u bytes!\n", func, line, __FUNCTION__, (unsigned int) size);
+ return ptr;
+}
+#else
void *yaffs_malloc(size_t size)
{
- return malloc(size);
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ printf("%s failed to allocate %u bytes!\n", __FUNCTION__, (unsigned int)size);
}
+#endif
void yaffs_free(void *ptr)
{
@@ -92,179 +107,15 @@ static int isMounted = 0;
#define MOUNT_POINT "/flash"
extern nand_info_t nand_info[];
-/* XXX U-BOOT XXX */
-#if 0
-static yaffs_Device ramDev;
-static yaffs_Device bootDev;
-static yaffs_Device flashDev;
-#endif
-
-static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
-/* XXX U-BOOT XXX */
-#if 0
- { "/ram", &ramDev},
- { "/boot", &bootDev},
- { "/flash", &flashDev},
-#else
- { MOUNT_POINT, 0},
-#endif
- {(void *)0,(void *)0}
-};
int yaffs_StartUp(void)
{
- struct mtd_info *mtd = &nand_info[0];
- int yaffsVersion = 2;
- int nBlocks;
-
- yaffs_Device *flashDev = calloc(1, sizeof(yaffs_Device));
- yaffsfs_config[0].dev = flashDev;
-
- /* store the mtd device for later use */
- flashDev->genericDevice = mtd;
-
- // Stuff to configure YAFFS
- // Stuff to initialise anything special (eg lock semaphore).
- yaffsfs_LocalInitialisation();
-
- // Set up devices
-
-/* XXX U-BOOT XXX */
-#if 0
- // /ram
- ramDev.nBytesPerChunk = 512;
- ramDev.nChunksPerBlock = 32;
- ramDev.nReservedBlocks = 2; // Set this smaller for RAM
- ramDev.startBlock = 1; // Can't use block 0
- ramDev.endBlock = 127; // Last block in 2MB.
- ramDev.useNANDECC = 1;
- ramDev.nShortOpCaches = 0; // Disable caching on this device.
- ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
- ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
- ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
- ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
- ramDev.initialiseNAND = yramdisk_InitialiseNAND;
-
- // /boot
- bootDev.nBytesPerChunk = 612;
- bootDev.nChunksPerBlock = 32;
- bootDev.nReservedBlocks = 5;
- bootDev.startBlock = 1; // Can't use block 0
- bootDev.endBlock = 127; // Last block in 2MB.
- bootDev.useNANDECC = 0; // use YAFFS's ECC
- bootDev.nShortOpCaches = 10; // Use caches
- bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
- bootDev.writeChunkToNAND = yflash_WriteChunkToNAND;
- bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND;
- bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
- bootDev.initialiseNAND = yflash_InitialiseNAND;
-#endif
-
- // /flash
- flashDev->nReservedBlocks = 5;
-// flashDev->nShortOpCaches = (options.no_cache) ? 0 : 10;
- flashDev->nShortOpCaches = 10; // Use caches
- flashDev->useNANDECC = 0; // do not use YAFFS's ECC
-
- if (yaffsVersion == 2)
- {
- flashDev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND;
- flashDev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND;
- flashDev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
- flashDev->queryNANDBlock = nandmtd2_QueryNANDBlock;
- flashDev->spareBuffer = YMALLOC(mtd->oobsize);
- flashDev->isYaffs2 = 1;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
- flashDev->nDataBytesPerChunk = mtd->writesize;
- flashDev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
-#else
- flashDev->nDataBytesPerChunk = mtd->oobblock;
- flashDev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
-#endif
- nBlocks = mtd->size / mtd->erasesize;
-
- flashDev->nCheckpointReservedBlocks = 10;
- flashDev->startBlock = 0;
- flashDev->endBlock = nBlocks - 1;
- }
- else
- {
- flashDev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
- flashDev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
- flashDev->isYaffs2 = 0;
- nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
- flashDev->startBlock = 320;
- flashDev->endBlock = nBlocks - 1;
- flashDev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
- flashDev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
- }
-
- /* ... and common functions */
- flashDev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
- flashDev->initialiseNAND = nandmtd_InitialiseNAND;
-
- yaffs_initialise(yaffsfs_config);
+ yaffs_initialise(NULL);
return 0;
}
-
-void make_a_file(char *yaffsName,char bval,int sizeOfFile)
-{
- int outh;
- int i;
- unsigned char buffer[100];
-
- outh = yaffs_open(yaffsName, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
- if (outh < 0)
- {
- printf("Error opening file: %d\n", outh);
- return;
- }
-
- memset(buffer,bval,100);
-
- do{
- i = sizeOfFile;
- if(i > 100) i = 100;
- sizeOfFile -= i;
-
- yaffs_write(outh,buffer,i);
-
- } while (sizeOfFile > 0);
-
-
- yaffs_close(outh);
-}
-
-void read_a_file(char *fn)
-{
- int h;
- int i = 0;
- unsigned char b;
-
- h = yaffs_open(fn, O_RDWR,0);
- if(h<0)
- {
- printf("File not found\n");
- return;
- }
-
- while(yaffs_read(h,&b,1)> 0)
- {
- printf("%02x ",b);
- i++;
- if(i > 32)
- {
- printf("\n");
- i = 0;;
- }
- }
- printf("\n");
- yaffs_close(h);
-}
-
void cmd_yaffs_mount(char *mp)
{
yaffs_StartUp();
@@ -275,45 +126,20 @@ void cmd_yaffs_mount(char *mp)
printf("Error mounting %s, return value: %d\n", mp, yaffsfs_GetError());
}
-static void checkMount(void)
-{
- if( !isMounted )
- {
- cmd_yaffs_mount(MOUNT_POINT);
- }
-}
-
void cmd_yaffs_umount(char *mp)
{
- checkMount();
if( yaffs_unmount(mp) == -1)
printf("Error umounting %s, return value: %d\n", mp, yaffsfs_GetError());
}
-void cmd_yaffs_write_file(char *yaffsName,char bval,int sizeOfFile)
-{
- checkMount();
- make_a_file(yaffsName,bval,sizeOfFile);
-}
-
-
-void cmd_yaffs_read_file(char *fn)
-{
- checkMount();
- read_a_file(fn);
-}
-
-
-void cmd_yaffs_mread_file(char *fn, char *addr)
+void cmd_yaffs_mread_file(char *fn, char *addr, long *size)
{
int h;
struct yaffs_stat s;
- checkMount();
-
yaffs_stat(fn,&s);
- printf ("Copy %s to 0x%08x... ", fn, addr);
+ printf ("Copy %s to 0x%p... ", fn, addr);
h = yaffs_open(fn, O_RDWR,0);
if(h<0)
{
@@ -323,6 +149,7 @@ void cmd_yaffs_mread_file(char *fn, char *addr)
yaffs_read(h,addr,(int)s.st_size);
printf("\t[DONE]\n");
+ *size = s.st_size;
yaffs_close(h);
}
@@ -332,7 +159,6 @@ void cmd_yaffs_mwrite_file(char *fn, char *addr, int size)
{
int outh;
- checkMount();
outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE);
if (outh < 0)
{
@@ -353,7 +179,6 @@ void cmd_yaffs_ls(const char *mountpt, int longlist)
struct yaffs_stat stat;
char tempstr[255];
- checkMount();
d = yaffs_opendir(mountpt);
if(!d)
@@ -368,7 +193,7 @@ void cmd_yaffs_ls(const char *mountpt, int longlist)
{
sprintf(tempstr, "%s/%s", mountpt, de->d_name);
yaffs_stat(tempstr, &stat);
- printf("%-25s\t%7d\n",de->d_name, stat.st_size);
+ printf("%-25s\t%7ld\n",de->d_name, stat.st_size);
}
else
{
@@ -378,11 +203,22 @@ void cmd_yaffs_ls(const char *mountpt, int longlist)
}
}
+int cmd_yaffs_df(const char *path, loff_t *space)
+{
+ loff_t free_space;
+ int ret = 0;
+
+ free_space = yaffs_freespace(path);
+ if (free_space == -1) {
+ ret = yaffsfs_GetError();
+ } else
+ *space = free_space;
+
+ return ret;
+}
void cmd_yaffs_mkdir(const char *dir)
{
- checkMount();
-
int retval = yaffs_mkdir(dir, 0);
if ( retval < 0)
@@ -391,8 +227,6 @@ void cmd_yaffs_mkdir(const char *dir)
void cmd_yaffs_rmdir(const char *dir)
{
- checkMount();
-
int retval = yaffs_rmdir(dir);
if ( retval < 0)
@@ -401,8 +235,6 @@ void cmd_yaffs_rmdir(const char *dir)
void cmd_yaffs_rm(const char *path)
{
- checkMount();
-
int retval = yaffs_unlink(path);
if ( retval < 0)
@@ -411,8 +243,6 @@ void cmd_yaffs_rm(const char *path)
void cmd_yaffs_mv(const char *oldPath, const char *newPath)
{
- checkMount();
-
int retval = yaffs_rename(newPath, oldPath);
if ( retval < 0)
diff --git a/fs/yaffs2/yaffsfs.c b/fs/yaffs2/yaffsfs.c
index 111cb348c0..1636baab97 100644
--- a/fs/yaffs2/yaffsfs.c
+++ b/fs/yaffs2/yaffsfs.c
@@ -15,14 +15,24 @@
#include <common.h>
#include <malloc.h>
+#include <jffs2/load_kernel.h>
+
#include "yaffsfs.h"
#include "yaffs_guts.h"
#include "yaffscfg.h"
#include "yportenv.h"
-/* XXX U-BOOT XXX */
-#if 0
-#include <string.h> // for memset
+#include "yaffs_mtdif.h"
+#include "yaffs_mtdif2.h"
+#include "yaffs_flashif.h"
+#include "nand.h"
+
+#include "mtd_parts.h"
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+#if (CONFIG_SYS_MALLOC_LEN < (512 << 10))
+#error Malloc Area too small for YAFFS, increas CONFIG_SYS_MALLOC_LEN to >= 512KiB
#endif
#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
@@ -34,10 +44,6 @@
const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $";
-// configurationList is the list of devices that are supported
-static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
-
-
/* Some forward references */
static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
@@ -151,58 +157,135 @@ int yaffsfs_Match(char a, char b)
return (a == b);
}
-// yaffsfs_FindDevice
-// yaffsfs_FindRoot
-// Scan the configuration list to find the root.
-// Curveballs: Should match paths that end in '/' too
-// Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
-static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
+/* yaffsfs_FindDevice
+ * yaffsfs_FindRoot
+ * Scan the parttion list to find the root; split out rest of path from
+ * Initialial partition. path must be /<partition>/<dir-or-file> */
+
+#define N_MAX_PARTLEN 64
+
+typedef enum {
+ YAFFSFS_ACTION_CREATE,
+ YAFFSFS_ACTION_FIND,
+ YAFFSFS_ACTION_DESTROY
+} yaffsfs_action_t;
+
+static struct yaffs_dev *yaffsfs_FindDevice(const char *path, char **restOfPath, yaffsfs_action_t action)
{
- yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
- const char *leftOver;
- const char *p;
- yaffs_Device *retval = NULL;
- int thisMatchLength;
- int longestMatch = -1;
-
- // Check all configs, choose the one that:
- // 1) Actually matches a prefix (ie /a amd /abc will not match
- // 2) Matches the longest.
- while(cfg && cfg->prefix && cfg->dev)
- {
- leftOver = path;
- p = cfg->prefix;
- thisMatchLength = 0;
-
- while(*p && //unmatched part of prefix
- strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
- *leftOver &&
- yaffsfs_Match(*p,*leftOver))
- {
- p++;
- leftOver++;
- thisMatchLength++;
+ int slash_cnt, i, ret;
+ char partname[N_MAX_PARTLEN];
+ void *part_priv;
+ loff_t part_off, part_size;
+ int part_idx;
+ struct mtd_device *dev;
+ void *cookie;
+ struct yaffs_dev *flashDev;
+ struct mtd_info *mtd;
+
+ if (!path)
+ return NULL;
+ if (*path != '/') {
+ printf("Path '%s' does not start with '/'!\n", path);
+ return NULL;
+ }
+ path++; /* Skip over leading '/' */
+
+ for (slash_cnt=i=0; i<N_MAX_PARTLEN && path[i]; ++i) {
+ if (path[i] == '/')
+ break;
+ partname[i] = path[i];
+ }
+ partname[i] = '\0';
+
+ /* save rest of path(if exists) */
+ *restOfPath = (char *)path+i;
+ if (**restOfPath == '/')
+ (*restOfPath)++;
+
+ /* Find the partition */
+ ret = mtd_get_part_priv(partname, &part_idx, &dev, &part_off, &part_size, &cookie, &part_priv);
+ if (ret)
+ return NULL;
+
+ switch(action) {
+ case YAFFSFS_ACTION_FIND:
+ return (struct yaffs_dev *)part_priv;
+
+ case YAFFSFS_ACTION_CREATE:
+ if (part_priv) {
+ printf("Huh? mount of partition '%s' already has device %p\n", partname, part_priv);
+ return NULL;
}
- if((!*p || strcmp(p,"/") == 0) && // end of prefix
- (!*leftOver || *leftOver == '/') && // no more in this path name part
- (thisMatchLength > longestMatch))
- {
- // Matched prefix
- *restOfPath = (char *)leftOver;
- retval = cfg->dev;
- longestMatch = thisMatchLength;
+
+ /* First time we're seeing this device, create it using
+ information inside of the MTD_DEVICE structure */
+ flashDev = malloc(sizeof(struct yaffs_dev));
+ if (!flashDev) {
+ printf("%s:%d out of memory!\n", __FUNCTION__, __LINE__);
+ return NULL;
}
- cfg++;
+ memset(flashDev, 0, sizeof(*flashDev));
+
+
+ printf("%s: initialise struct yaffs_dev %p\n", __FUNCTION__, flashDev);
+
+ /* Side effect of mtd_get_part_priv() is to set nand_curr_device */
+ mtd = &nand_info[nand_curr_device];
+
+ flashDev->genericDevice = mtd;
+ flashDev->startBlock = part_off / mtd->erasesize;
+ flashDev->endBlock = (part_off + part_size - 1) / mtd->erasesize;
+#if 0
+ printf("%s: part_off %x part_size %x startBlock %u endBlock %u\n", __FUNCTION__, (unsigned int)part_off, (unsigned int)part_size, flashDev->startBlock, flashDev->endBlock);
+#endif
+ flashDev->nReservedBlocks = 5;
+
+ flashDev->writeChunkWithTagsToNAND = nandmtd2_WriteChunkWithTagsToNAND;
+ flashDev->readChunkWithTagsFromNAND = nandmtd2_ReadChunkWithTagsFromNAND;
+ flashDev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+ flashDev->queryNANDBlock = nandmtd2_QueryNANDBlock;
+ flashDev->isYaffs2 = 1;
+#if 1
+ Yaffs_DeviceToContext(dev)->spareBuffer = YMALLOC(mtd->oobsize);
+#else
+ flashDev->spareBuffer = YMALLOC(mtd->oobsize);
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ flashDev->nDataBytesPerChunk = mtd->writesize;
+ flashDev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+ flashDev->nDataBytesPerChunk = mtd->oobblock;
+ flashDev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+ flashDev->nCheckpointReservedBlocks = 10;
+
+ /* ... and common functions */
+ flashDev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+ flashDev->initialiseNAND = nandmtd_InitialiseNAND;
+ flashDev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
+
+ mtd_set_part_priv(cookie, flashDev);
+
+ return flashDev;
+
+ case YAFFSFS_ACTION_DESTROY:
+ free(part_priv);
+ mtd_set_part_priv(cookie, NULL);
+ return NULL;
+
+ default:
+ printf("%s: unknown action %d\n", __FUNCTION__, (int)action);
+ return NULL;
}
- return retval;
+
}
static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
{
- yaffs_Device *dev;
+ struct yaffs_dev *dev;
- dev= yaffsfs_FindDevice(path,restOfPath);
+ dev= yaffsfs_FindDevice(path,restOfPath, YAFFSFS_ACTION_FIND);
if(dev && dev->isMounted)
{
return dev->rootDir;
@@ -1032,13 +1115,13 @@ int yaffs_mount(const char *path)
{
int retVal=-1;
int result=YAFFS_FAIL;
- yaffs_Device *dev=NULL;
+ struct yaffs_dev *dev=NULL;
char *dummy;
T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path));
yaffsfs_Lock();
- dev = yaffsfs_FindDevice(path,&dummy);
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_CREATE);
if(dev)
{
if(!dev->isMounted)
@@ -1071,11 +1154,11 @@ int yaffs_mount(const char *path)
int yaffs_unmount(const char *path)
{
int retVal=-1;
- yaffs_Device *dev=NULL;
+ struct yaffs_dev *dev=NULL;
char *dummy;
yaffsfs_Lock();
- dev = yaffsfs_FindDevice(path,&dummy);
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_FIND);
if(dev)
{
if(dev->isMounted)
@@ -1098,6 +1181,8 @@ int yaffs_unmount(const char *path)
{
yaffs_Deinitialise(dev);
+ yaffsfs_FindDevice(path, &dummy, YAFFSFS_ACTION_DESTROY);
+
retVal = 0;
}
else
@@ -1127,11 +1212,11 @@ int yaffs_unmount(const char *path)
loff_t yaffs_freespace(const char *path)
{
loff_t retVal=-1;
- yaffs_Device *dev=NULL;
+ struct yaffs_dev *dev=NULL;
char *dummy;
yaffsfs_Lock();
- dev = yaffsfs_FindDevice(path,&dummy);
+ dev = yaffsfs_FindDevice(path,&dummy, YAFFSFS_ACTION_FIND);
if(dev && dev->isMounted)
{
retVal = yaffs_GetNumberOfFreeChunks(dev);
@@ -1151,21 +1236,7 @@ loff_t yaffs_freespace(const char *path)
void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
{
-
- yaffsfs_DeviceConfiguration *cfg;
-
- yaffsfs_configurationList = cfgList;
-
yaffsfs_InitHandles();
-
- cfg = yaffsfs_configurationList;
-
- while(cfg && cfg->prefix && cfg->dev)
- {
- cfg->dev->isMounted = 0;
- cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
- cfg++;
- }
}
@@ -1487,7 +1558,7 @@ int yaffs_DumpDevStruct(const char *path)
if(obj)
{
- yaffs_Device *dev = obj->myDev;
+ struct yaffs_dev *dev = obj->myDev;
printf("\n"
"nPageWrites.......... %d\n"
diff --git a/fs/yaffs2/ydirectenv.h b/fs/yaffs2/ydirectenv.h
index b555810844..12b910b7d0 100644
--- a/fs/yaffs2/ydirectenv.h
+++ b/fs/yaffs2/ydirectenv.h
@@ -54,12 +54,18 @@
#define Y_INLINE inline
#endif
+#ifdef YAFFS_DEBUG_MALLOC
+#define YMALLOC(x) yaffs_malloc(__FUNCTION__, __LINE__, (x))
+#define YMALLOC_ALT(x) yaffs_malloc(__FUNCTION__, __LINE__, (x))
+#define YMALLOC_DMA(x) yaffs_malloc(__FUNCTION__, __LINE__, (x))
+#else
#define YMALLOC(x) yaffs_malloc(x)
-#define YFREE(x) free(x)
#define YMALLOC_ALT(x) yaffs_malloc(x)
+#define YMALLOC_DMA(x) yaffs_malloc(x)
+#endif
+#define YFREE(x) free(x)
#define YFREE_ALT(x) free(x)
-#define YMALLOC_DMA(x) yaffs_malloc(x)
#define YYIELD() do {} while(0)
diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
index bbab14d503..28bdff386f 100644
--- a/fs/yaffs2/yportenv.h
+++ b/fs/yaffs2/yportenv.h
@@ -96,6 +96,8 @@
#elif defined CONFIG_YAFFS_DIRECT
+#define YAFFS_DEBUG_MALLOC /* Complain if yaffs_malloc() fails */
+
/* Direct interface */
#include "ydirectenv.h"
diff --git a/include/common.h b/include/common.h
index 1e21b7a3d5..8b32431b56 100644
--- a/include/common.h
+++ b/include/common.h
@@ -307,6 +307,13 @@ void pciinfo (int, int);
int misc_init_f (void);
int misc_init_r (void);
+/* Environment/nand support functions */
+extern void nand_setup_default_ecc_method(void);
+extern void nand_switch_ecc_default(int *ecc_method);
+extern void nand_switch_ecc_method(int ecc_method);
+extern int setenv_reserved_name(const char *name);
+extern void touchup_env(void);
+
/* common/exports.c */
void jumptable_init(void);
@@ -724,6 +731,14 @@ int pcmcia_init (void);
* Board-specific Platform code can reimplement show_boot_progress () if needed
*/
void show_boot_progress(int val);
+#ifdef CONFIG_BOARD_LCD_SETMEM
+ulong board_lcd_setmem (ulong addr);
+#endif
+
+#ifdef CONFIG_LCD_PERCENT
+extern void lcd_percent_init(int total_size);
+extern void lcd_percent_update(int size);
+#endif
/* Multicore arch functions */
#ifdef CONFIG_MP
diff --git a/include/configs/omap3logic.h b/include/configs/omap3logic.h
new file mode 100644
index 0000000000..1aaf292089
--- /dev/null
+++ b/include/configs/omap3logic.h
@@ -0,0 +1,633 @@
+/*
+ * (C) Copyright 2006-2008
+ * Texas Instruments.
+ * Author :
+ * Manikandan Pillai <mani.pillai@ti.com>
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Mohammed Khasim <khasim@ti.com>
+ *
+ * Manikandan Pillai <mani.pillai@ti.com>
+ *
+ * Configuration settings for the TI OMAP3 EVM board.
+ *
+ * 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_ARMV7 1 /* This is an ARM V7 CPU core */
+#define CONFIG_OMAP 1 /* in a TI OMAP core */
+#define CONFIG_OMAP34XX 1 /* which is a 34XX */
+#define CONFIG_OMAP3430 1 /* which is in a 3430 */
+#define CONFIG_OMAP3_LOGIC 1 /* working with Logic OMAP boards */
+
+/* Define following to enable new product ID code. */
+#define CONFIG_OMAP3_LOGIC_USE_NEW_PRODUCT_ID 1
+
+#define CONFIG_SDRC /* The chip has SDRC controller */
+
+#include <asm/arch/cpu.h> /* get chip and board defs */
+#include <asm/arch/omap3.h>
+
+/*
+ * Display CPU and Board information
+ */
+#define CONFIG_DISPLAY_CPUINFO 1
+#define CONFIG_DISPLAY_BOARDINFO 1
+
+/* Clock Defines */
+#define V_OSCK 26000000 /* Clock output from T2 */
+#define V_SCLK (V_OSCK >> 1)
+
+#undef CONFIG_USE_IRQ /* no support for IRQs */
+#define CONFIG_MISC_INIT_R
+
+#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS 1
+#define CONFIG_INITRD_TAG 1
+#define CONFIG_REVISION_TAG 1
+
+#define CONFIG_CMDLINE_EDITING 1 /* cmd line edit/history */
+#define CONFIG_ZERO_BOOTDELAY_CHECK 1 /* check keypress with zero bootdelay */
+
+/*
+ * Size of malloc() pool
+ */
+#define CONFIG_ENV_SIZE (128 << 10) /* 128 KiB */
+ /* Sector */
+#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (6 << 20))
+
+/*
+ * Add GDB information (section starts) into bdinfo; used in gdb
+ * "add-symbol-file" to specify start of .data, .bss, .rodata sections
+ */
+#define CONFIG_GDB_SECTION_STARTS
+
+/*
+ * Hardware drivers
+ */
+
+/*
+ * NS16550 Configuration
+ */
+#define V_NS16550_CLK 48000000 /* 48MHz (APLL96/2) */
+
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+#define CONFIG_SYS_NS16550_REG_SIZE (-4)
+#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK
+
+/*
+ * select serial console configuration
+ */
+#define CONFIG_CONS_INDEX 1
+#define CONFIG_SYS_NS16550_COM1 OMAP34XX_UART1
+#define CONFIG_SERIAL1 1 /* UART1 on OMAP3 EVMOMAP Logic boards */
+
+/* allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+/* But don't allow overwriting "defaultecc" */
+#define CONFIG_CHECK_SETENV
+
+#define CONFIG_BAUDRATE 115200
+#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\
+ 115200}
+#define CONFIG_MMC 1
+#define CONFIG_OMAP3_MMC 1
+#define CONFIG_DOS_PARTITION 1
+
+/* DDR - I use Micron DDR */
+#define CONFIG_OMAP3_MICRON_DDR 1
+
+/* USB
+ * Enable CONFIG_MUSB_HCD for Host functionalities MSC, keyboard
+ * Enable CONFIG_MUSB_UDD for Device functionalities.
+ */
+#define CONFIG_USB_OMAP3 1
+#define CONFIG_MUSB_HCD 1
+/* #define CONFIG_MUSB_UDC 1 */
+
+#ifdef CONFIG_USB_OMAP3
+
+#ifdef CONFIG_MUSB_HCD
+#define CONFIG_CMD_USB
+
+#define CONFIG_USB_STORAGE
+#define CONGIG_CMD_STORAGE
+#define CONFIG_CMD_FAT
+
+#ifdef CONFIG_USB_KEYBOARD
+#define CONFIG_SYS_USB_EVENT_POLL
+// #define CONFIG_PREBOOT "usb start"
+#endif /* CONFIG_USB_KEYBOARD */
+
+#endif /* CONFIG_MUSB_HCD */
+
+#ifdef CONFIG_MUSB_UDC
+/* USB device configuration */
+#define CONFIG_USB_DEVICE 1
+#define CONFIG_USB_TTY 1
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV 1
+/* Change these to suit your needs */
+#define CONFIG_USBD_VENDORID 0x0451
+#define CONFIG_USBD_PRODUCTID 0x5678
+#define CONFIG_USBD_MANUFACTURER "Texas Instruments"
+#define CONFIG_USBD_PRODUCT_NAME "EVM"
+#endif /* CONFIG_MUSB_UDC */
+
+#endif /* CONFIG_USB_OMAP3 */
+
+/* commands to include */
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_EXT2 /* EXT2 Support */
+#define CONFIG_CMD_FAT /* FAT support */
+#define CONFIG_CMD_JFFS2 /* JFFS2 Support */
+#define CONFIG_CMD_NAND_YAFFS /* YAFFS NAND Support */
+// #define CONFIG_YAFFS2 /* YAFFS2 Support */
+#define CONFIG_YAFFS2_NEW /* Newer YAFFS2 Support */
+
+#define CONFIG_CMD_I2C /* I2C serial bus support */
+#define CONFIG_CMD_MMC /* MMC support */
+#define CONFIG_CMD_NAND /* NAND support */
+#define CONFIG_MTD_DEVICE /* needed for MTD mtdparts support */
+#define CONFIG_CMD_MTDPARTS /* MTD partition support */
+#define MTDIDS_DEFAULT "nand0=omap2-nand.0"
+#define MTDPARTS_DEFAULT "mtdparts=omap2-nand.0:512k(x-loader),"\
+ "1664k(u-boot),384k(u-boot-env),"\
+ "5m(kernel),20m(ramdisk),-(fs)"
+#define CONFIG_NAND_SET_DEFAULT /* Set default NAND access method */
+#define CONFIG_NAND_MULTIPLE_ECC /* NAND has multiple ECC methods */
+#define CONFIG_TOUCHUP_ENV /* Set board-specific environment vars */
+#define CONFIG_CMD_NAND_LOCK_UNLOCK /* nand (un)lock commands */
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_CACHE /* Cache control */
+#define CONFIG_CMD_TIME /* time command */
+
+#define CONFIG_L2_OFF 1 /* Keep L2 Cache Disabled */
+
+#define BOARD_LATE_INIT
+
+#define CONFIG_CMD_FLASH /* flinfo, erase, protect */
+#undef CONFIG_CMD_FPGA /* FPGA configuration Support */
+#undef CONFIG_CMD_IMI /* iminfo */
+#undef CONFIG_CMD_IMLS /* List all found images */
+
+#define CONFIG_CMD_GPMC_CONFIG /* gpmc_config */
+#define CONFIG_CMD_MUX_CONFIG /* mux_config */
+#define CONFIG_CMD_SDRC_CONFIG /* sdrc_config */
+
+#define CONFIG_HARD_I2C 1
+#define CONFIG_SYS_I2C_SPEED 100000
+#define CONFIG_SYS_I2C_SLAVE 1
+#define CONFIG_SYS_I2C_BUS 0
+#define CONFIG_SYS_I2C_BUS_SELECT 1
+#define CONFIG_DRIVER_OMAP34XX_I2C 1
+#define CONFIG_I2C_MULTI_BUS 1
+
+#define CONFIG_MTD_DEBUG 1
+#define CONFIG_MTD_DEBUG_VERBOSE -1
+#define CONFIG_MTD_SKIP_BBTSCAN 1 /* Skip NAND bad block scan */
+#define CONFIG_TOOL_SIGNGP 1
+
+/*
+ * TWL4030
+ */
+#define CONFIG_TWL4030_POWER 1
+#define CONFIG_TWL4030_GPIO 1
+#define CONFIG_TWL4030_PWM 1
+#define CONFIG_TWL4030_CHARGING 1
+
+/* Charge the batter unless $disablecharging == "yes" */
+#define CONFIG_ENABLE_TWL4030_CHARGING 1
+
+/*
+ * Board NAND Info.
+ */
+#define CONFIG_SYS_NAND_ADDR NAND_BASE /* physical address */
+ /* to access nand */
+#define CONFIG_SYS_NAND_BASE NAND_BASE /* physical address */
+ /* to access */
+ /* nand at CS0 */
+
+#define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of */
+ /* NAND devices */
+#define CONFIG_JFFS2_NAND
+/* nand device jffs2 lives on */
+#define CONFIG_JFFS2_DEV "nand0"
+/* start of jffs2 partition */
+#define CONFIG_JFFS2_PART_OFFSET 0x680000
+#define CONFIG_JFFS2_PART_SIZE 0xf980000 /* sz of jffs2 part */
+
+/* Environment information */
+#define CONFIG_BOOTDELAY 3
+
+#define CONFIG_BOOTFILE uImage
+
+#define CONFIG_PREBOOT \
+ "echo ; " \
+ "echo =================================== NOTICE ===================================;" \
+ "echo \"The U-Boot environment was not found. If the display is not set properly \";"\
+ "echo \"linux will not have video support.\";" \
+ "echo ; " \
+ "echo \"Valid display options are:\";" \
+ "echo \" 2 == LQ121S1DG31 TFT SVGA (12.1) Sharp\";" \
+ "echo \" 3 == LQ036Q1DA01 TFT QVGA (3.6) Sharp w/ASIC\";" \
+ "echo \" 5 == LQ064D343 TFT VGA (6.4) Sharp\";" \
+ "echo \" 7 == LQ10D368 TFT VGA (10.4) Sharp\";" \
+ "echo \" 15 == LQ043T1DG01 TFT WQVGA (4.3) Sharp (DEFAULT)\";" \
+ "echo \" vga[-16 OR -24] LCD VGA 640x480\";" \
+ "echo \" svga[-16 OR -24] LCD SVGA 800x600\";" \
+ "echo \" xga[-16 OR -24] LCD XGA 1024x768\";" \
+ "echo \" 720p[-16 OR -24] LCD 720P 1280x720\";" \
+ "echo \" sxga[-16 OR -24] LCD SXGA 1280x1024\";" \
+ "echo \" uxga[-16 OR -24] LCD UXGA 1600x1200\";" \
+ "echo ; " \
+ "echo \"Default `display` environment variable is now being set to: 15\";" \
+ "setenv display 15;" \
+ "setenv preboot;" \
+ "echo ; " \
+ "echo \"At the U-Boot prompt type commands: `setenv display <num>`, then type\";" \
+ "echo \"`saveenv` to save the environment to NAND flash. This will avoid seeing\";" \
+ "echo \"this notice on future boots\" ; " \
+ "echo =================================== NOTICE ===================================;" \
+ "echo ; "
+
+#ifdef CONFIG_USB_TTY
+#define OMAP3LOGIC_USBTTY "usbtty=cdc_acm\0"
+#else
+#define OMAP3LOGIC_USBTTY
+#endif
+
+#define CONFIG_BOOTCOMMAND \
+ "run autoboot"
+
+#define CONFIG_MMC_BOOTSCRIPT_NAME \
+ "boot.scr"
+
+/*****************************************************************************/
+/* Default Environment */
+/* */
+/* When reconfiguring the boot environment, be sure to set the environment */
+/* variables as indicated below for a successful boot. */
+/* */
+/* - $kernel_location */
+/* Must always be set. Values can be ram, nand, mmc, or tftp. */
+/* */
+/* - $rootfs_location */
+/* Must always be set. Values can be ram, tftp, /dev, nfs, mmc, or nand. */
+/* */
+/* - $rootfs_type */
+/* Must always be set. Values can be ramdisk, jffs, yaffs, ext3, or nfs. */
+/* */
+/* - $loadaddr */
+/* Must always be set. */
+/* */
+/* - If booting from /dev based file system, then $rootfs_device must be */
+/* set. */
+/* - If booting from a ramdisk image, then $ramdisksize, and $ramdiskaddr */
+/* must be set. */
+/* - If booting from an nfs location, then $serverip, $nfsrootpath, and */
+/* $nfsoptions must be set. */
+/* - If booting from nand, $ramdisk_nand_offset, $ramdisk_nand_size, */
+/* $kernel_nand_offset, and $kernel_nand_size must be set. */
+/* - If booting from a file system, $ramdiskimage, and $kernelimage must be */
+/* set. */
+/* - Optionally, a boot script named "boot.scr" can be placed in SD to */
+/* override any other boot scripts. */
+/*****************************************************************************/
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ OMAP3LOGIC_USBTTY \
+ "bootargs=\0" \
+ "otherbootargs=ignore_loglevel early_printk no_console_suspend \0" \
+ "consoledevice=ttyO0\0" \
+ "setconsole=setenv console ${consoledevice},${baudrate}n8\0" \
+ "mtdids=" MTDIDS_DEFAULT "\0" \
+ "mtdparts=" MTDPARTS_DEFAULT "\0" \
+ "disablecharging=no\0" \
+ "mmc_bootscript_addr=0x80FF0000\0" \
+ "disablecharging no\0" \
+ "display=15\0" \
+ "loadaddr=0x81000000\0" \
+ "kernel_location=mmc \0" \
+ "rootfs_location=mmc \0" \
+ "rootfs_type=ramdisk \0" \
+ "rootfs_device=/dev/mtdblock4 \0" \
+ "ramdisksize=64000\0" \
+ "ramdiskaddr=0x82000000\0" \
+ "ramdiskimage=rootfs.ext2.gz.uboot\0" \
+ "ramdisk_nand_offset=0x00680000\0" \
+ "ramdisk_nand_size=0x00d40000\0" \
+ "kernel_nand_offset=0x00280000 \0" \
+ "kernel_nand_size=0x00400000 \0" \
+ "kernelimage=uImage \0" \
+ "serverip=192.168.3.5\0" \
+ "nfsrootpath=/opt/nfs-exports/ltib-omap\0" \
+ "nfsoptions=,wsize=1500,rsize=1500\0" \
+ "rotation=0\0" \
+ "autoboot=echo \"\n== Checking mmc1 for alternate boot script " CONFIG_MMC_BOOTSCRIPT_NAME " ==\"; " \
+ "if mmc init; then " \
+ "if run loadbootscript; then " \
+ "echo \"\"; " \
+ "echo \"== Found script on mmc 1, starting ==\"; " \
+ "run bootscript; " \
+ "else " \
+ "echo \"\"; " \
+ "echo \"== Script not found on mmc 1, proceeding with defaultboot ==\"; " \
+ "run defaultboot;" \
+ "fi; " \
+ "else run defaultboot; fi\0" \
+ "loadbootscript=fatload mmc 1 $mmc_bootscript_addr " CONFIG_MMC_BOOTSCRIPT_NAME "\0" \
+ "bootscript=source ${mmc_bootscript_addr}\0" \
+ "vrfb_arg=if itest ${rotation} -ne 0; then " \
+ "setenv bootargs ${bootargs} omapfb.vrfb=y omapfb.rotate=${rotation}; " \
+ "fi\0" \
+ "dump_bootargs=echo \"\"; echo \"== Kernel bootargs ==\"; echo $bootargs; echo \"\"; \0" \
+ "dump_boot_sources=echo \"kernel_location: $kernel_location, " \
+ "rootfs_location: $rootfs_location, " \
+ "rootfs_type: $rootfs_type\"; " \
+ "echo \"\"; " \
+ "\0" \
+ "load_kernel=if test $kernel_location = 'ram'; then " \
+ "echo \"== kernel located at $loadaddr ==\"; " \
+ "echo \"\"; " \
+ "setenv bootm_arg1 ${loadaddr};" \
+ "else if test $kernel_location = 'nand'; then " \
+ "echo \"== Loading kernel from nand to $loadaddr ==\"; " \
+ "nand read.i $loadaddr $kernel_nand_offset $kernel_nand_size; " \
+ "echo \"\"; " \
+ "setenv bootm_arg1 ${loadaddr};" \
+ "else if test $kernel_location = 'mmc'; then " \
+ "echo \"== Loading kernel file $kernelimage to $loadaddr ==\"; " \
+ "mmc init; " \
+ "fatload mmc 1 $loadaddr $kernelimage; " \
+ "echo \"\"; " \
+ "setenv bootm_arg1 ${loadaddr};" \
+ "else if test $kernel_location = 'tftp'; then " \
+ "echo \"== Loading kernel file $kernelimage to $loadaddr ==\"; " \
+ "tftpboot $loadaddr $kernelimage; " \
+ "echo \"\"; " \
+ "setenv bootm_arg1 ${loadaddr};" \
+ "else "\
+ "echo \"== kernel_location must be set to ram, nand, mmc, or tftp!! ==\"; " \
+ "echo \"\"; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi " \
+ "\0" \
+ "load_rootfs=if test $rootfs_location = 'ram'; then " \
+ "echo \"== rootfs located at $ramdiskaddr ==\"; " \
+ "echo \"\"; " \
+ "setenv bootm_arg2 ${ramdiskaddr}; " \
+ "else if test $rootfs_location = 'tftp'; then " \
+ "echo \"== Loading rootfs file $ramdiskimage to $ramdiskaddr ==\"; " \
+ "tftpboot $ramdiskaddr $ramdiskimage;" \
+ "echo \"\"; " \
+ "setenv bootm_arg2 ${ramdiskaddr}; " \
+ "else if test $rootfs_location = '/dev'; then " \
+ "echo \"== rootfs located in $rootfs_device ==\"; " \
+ "echo \"\"; " \
+ "setenv bootargs ${bootargs} root=${rootfs_device}; " \
+ "setenv bootm_arg2; " \
+ "else if test $rootfs_location = 'nfs'; then " \
+ "echo \"== rootfs located at $nfs_root_path on server $serverip ==\"; " \
+ "echo \"\"; " \
+ "setenv bootargs ${bootargs} root=/dev/nfs; " \
+ "setenv bootm_arg2; " \
+ "else if test $rootfs_location = 'mmc'; then " \
+ "echo \"== Loading rootfs file $ramdiskimage to $ramdiskaddr ==\"; " \
+ "fatload mmc 1 ${ramdiskaddr} ${ramdiskimage}; "\
+ "setenv bootm_arg2 ${ramdiskaddr}; " \
+ "else if test $rootfs_location = 'nand'; then " \
+ "echo \"== Loading rootfs from nand to $ramdiskaddr ==\"; " \
+ "nand read.i $ramdiskaddr $ramdisk_nand_offset $ramdisk_nand_size; " \
+ "setenv bootm_arg2 ${ramdiskaddr}; " \
+ "else "\
+ "echo \"== rootfs_location must be set to ram, tftp, /dev, nfs, mmc, or nand!! == \"; " \
+ "echo \"\"; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi " \
+ "\0" \
+ "set_rootfs_type=if test $rootfs_type = 'ramdisk'; then " \
+ "setenv bootargs ${bootargs} root=/dev/ram rw ramdisk_size=${ramdisksize}; " \
+ "else if test $rootfs_type = 'jffs'; then " \
+ "setenv bootargs ${bootargs} rw rootfstype=jffs2;" \
+ "else if test $rootfs_type = 'yaffs'; then " \
+ "setenv bootargs ${bootargs} rw rootfstype=yaffs2;" \
+ "else if test $rootfs_type = 'ext3'; then " \
+ "setenv bootargs ${bootargs} rw rootfstype=ext3 rootwait; " \
+ "else if test $rootfs_type = 'nfs'; then " \
+ "setenv bootargs ${bootargs} rw nfsroot=${serverip}:${nfsrootpath}${nfsoptions} ip=dhcp; " \
+ "else "\
+ "echo \"$rootfs_type must be set to ramdisk, jffs, yaffs, ext3, or nfs\"; " \
+ "echo \"\"; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi; " \
+ "fi " \
+ "\0" \
+ "addmtdparts=setenv bootargs ${bootargs} ${mtdparts} \0" \
+ "common_bootargs=" \
+ " setenv bootargs ${bootargs} display=${display} ${otherbootargs}; " \
+ " run addmtdparts; " \
+ " run vrfb_arg; " \
+ " \0" \
+ "dump_run_bootm=" \
+ " echo \"bootm $bootm_arg1 $bootm_arg2\"; " \
+ " echo \"\"; " \
+ " bootm $bootm_arg1 $bootm_arg2\0" \
+ "defaultboot=" \
+ " run dump_boot_sources; " \
+ " run setconsole; setenv bootargs console=${console}; " \
+ " run common_bootargs; " \
+ " run load_kernel; " \
+ " run load_rootfs; " \
+ " run set_rootfs_type; " \
+ " run dump_bootargs; " \
+ " run dump_run_bootm; " \
+ "\0"
+
+
+#define CONFIG_AUTO_COMPLETE 1
+/*
+ * Miscellaneous configurable options
+ */
+#define CONFIG_SYS_LONGHELP /* undef to save memory */
+#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+#define CONFIG_SYS_PROMPT "OMAP Logic # "
+#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
+ sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS 64 /* max number of command */
+ /* args */
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE (CONFIG_SYS_CBSIZE)
+/* memtest works on */
+#define CONFIG_SYS_MEMTEST_START (OMAP34XX_SDRC_CS0)
+#define CONFIG_SYS_MEMTEST_END (OMAP34XX_SDRC_CS0 + \
+ 0x01F00000) /* 31MB */
+
+#define CONFIG_SYS_LOAD_ADDR (OMAP34XX_SDRC_CS0) /* default load */
+ /* address */
+
+/*
+ * OMAP3 has 12 GP timers, they can be driven by the system clock
+ * (12/13/16.8/19.2/38.4MHz) or by 32KHz clock. We use 13MHz (V_SCLK).
+ * This rate is divided by a local divisor.
+ */
+#define CONFIG_SYS_TIMERBASE OMAP34XX_GPT2
+#define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */
+#define CONFIG_SYS_HZ 1000
+
+/*-----------------------------------------------------------------------
+ * Stack sizes
+ *
+ * The stack sizes are set up in start.S using the settings below
+ */
+#define CONFIG_STACKSIZE (128 << 10) /* regular stack 128 KiB */
+#ifdef CONFIG_USE_IRQ
+#define CONFIG_STACKSIZE_IRQ (4 << 10) /* IRQ stack 4 KiB */
+#define CONFIG_STACKSIZE_FIQ (4 << 10) /* FIQ stack 4 KiB */
+#endif
+
+/*-----------------------------------------------------------------------
+ * Physical Memory Map
+ */
+#define CONFIG_NR_DRAM_BANKS 2 /* CS1 may or may not be populated */
+#define PHYS_SDRAM_1 OMAP34XX_SDRC_CS0
+#define PHYS_SDRAM_1_SIZE (32 << 20) /* at least 32 MiB */
+#define PHYS_SDRAM_2 OMAP34XX_SDRC_CS1
+
+/* SDRAM Bank Allocation method */
+#define SDRC_R_B_C 1
+
+/*-----------------------------------------------------------------------
+ * FLASH and environment organization
+ */
+
+/* variable that's non-zero if flash exists */
+#define CONFIG_SYS_FLASH_PRESENCE omap3logic_flash_exists
+#ifndef __ASSEMBLY__
+extern int omap3logic_flash_exists;
+#endif
+#define CONFIG_SYS_FLASH_BASE 0x10000000 /* FLASH base address */
+#define CONFIG_SYS_FLASH_SIZE 8 /* 8MB */
+#define CONFIG_SYS_MAX_FLASH_SECT (64+8) /* 8MB/128K */
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+#undef CONFIG_SYS_FLASH_CHECKSUM
+#define CONFIG_SYS_FLASH_CFI /* use the Common Flash Interface */
+#define CONFIG_FLASH_CFI_DRIVER /* use the CFI driver */
+
+
+/* **** PISMO SUPPORT *** */
+
+/* Configure the PISMO */
+#define PISMO1_NAND_SIZE GPMC_SIZE_128M
+
+#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* Reserve 2 sectors */
+
+/* Monitor at start of flash */
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
+
+#define SMNAND_ENV_OFFSET 0x220000 /* environment starts here */
+
+#if defined(CONFIG_CMD_NAND)
+#define CONFIG_NAND_OMAP_GPMC
+#define CONFIG_MTD_NAND_BCH
+#define CONFIG_MTD_NAND_ECC_BCH
+#define CONFIG_BCH
+#define GPMC_NAND_ECC_LP_x16_LAYOUT 1
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET SMNAND_ENV_OFFSET
+#endif
+
+#define CONFIG_ENV_ADDR CONFIG_ENV_OFFSET
+#define CONFIG_ENV_RANGE (3 * CONFIG_ENV_SIZE)
+
+/*
+ * Support for relocation
+ */
+#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
+#define CONFIG_SYS_INIT_RAM_ADDR 0x4020f800
+#define CONFIG_SYS_INIT_RAM_SIZE 0x800
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \
+ CONFIG_SYS_INIT_RAM_SIZE - \
+ GENERATED_GBL_DATA_SIZE)
+
+/*
+ * Define the board revision statically
+ */
+/* #define CONFIG_STATIC_BOARD_REV OMAP3EVM_BOARD_GEN_2 */
+
+/*----------------------------------------------------------------------------
+ * SMSC9115 Ethernet from SMSC9118 family
+ *----------------------------------------------------------------------------
+ */
+#if defined(CONFIG_CMD_NET)
+
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X
+#define CONFIG_SMC911X_16_BIT
+#define CONFIG_SMC911X_BASE 0x08000000
+
+#endif /* (CONFIG_CMD_NET) */
+
+/*
+ * BOOTP fields
+ */
+
+#define CONFIG_BOOTP_SUBNETMASK 0x00000001
+#define CONFIG_BOOTP_GATEWAY 0x00000002
+#define CONFIG_BOOTP_HOSTNAME 0x00000004
+#define CONFIG_BOOTP_BOOTPATH 0x00000010
+
+/* Add graphics support */
+#define CONFIG_VIDEO_OMAP3
+#define CONFIG_LCD
+#define LCD_BPP LCD_COLOR16
+#define CONFIG_CMD_BMP
+#define CONFIG_BMP_16BPP
+#define CONFIG_VIDEO_BMP_GZIP
+#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE (2 << 20)
+#define CONFIG_SPLASH_SCREEN
+#define CONFIG_SPLASH_SCREEN_ALIGN 1
+#define CONFIG_SYS_WHITE_ON_BLACK /* White characters on black background */
+
+/* Have board_set_lcdmem() function */
+#define CONFIG_BOARD_LCD_SETMEM
+
+/* Have percent ouptut function for LCD */
+#define CONFIG_LCD_PERCENT
+
+#endif /* __CONFIG_H */
diff --git a/include/environment.h b/include/environment.h
index 53d92df1f2..5180320b62 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -172,6 +172,9 @@ void set_default_env(const char *s);
/* Import from binary representation into hash table */
int env_import(const char *buf, int check);
+/* Check a read environment to see if its valid */
+int env_check_valid(const char *buf);
+
#endif
#endif /* _ENVIRONMENT_H_ */
diff --git a/include/jffs2/load_kernel.h b/include/jffs2/load_kernel.h
index 906eb3d3cd..7d549d957f 100644
--- a/include/jffs2/load_kernel.h
+++ b/include/jffs2/load_kernel.h
@@ -77,7 +77,7 @@ struct mtdids {
/* common/cmd_jffs2.c */
extern int mtdparts_init(void);
extern int find_dev_and_part(const char *id, struct mtd_device **dev,
- u8 *part_num, struct part_info **part);
+ u8 *part_num, struct part_info **part, int quiet);
extern struct mtd_device *device_find(u8 type, u8 num);
#endif /* load_kernel_h */
diff --git a/include/lcd.h b/include/lcd.h
index 0e098d925e..f01cba7181 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -34,6 +34,7 @@ extern char lcd_is_enabled;
extern int lcd_line_length;
extern int lcd_color_fg;
extern int lcd_color_bg;
+extern int console_color_black, console_color_white;
/*
* Frame buffer memory information
@@ -235,6 +236,7 @@ void lcd_show_board_info(void);
#define LCD_COLOR4 2
#define LCD_COLOR8 3
#define LCD_COLOR16 4
+#define LCD_COLOR24 5
/*----------------------------------------------------------------------*/
#if defined(CONFIG_LCD_INFO_BELOW_LOGO)
@@ -261,42 +263,6 @@ void lcd_show_board_info(void);
#define NCOLORS(bit_code) (1 << NBITS(bit_code))
/************************************************************************/
-/* ** CONSOLE CONSTANTS */
-/************************************************************************/
-#if LCD_BPP == LCD_MONOCHROME
-
-/*
- * Simple black/white definitions
- */
-# define CONSOLE_COLOR_BLACK 0
-# define CONSOLE_COLOR_WHITE 1 /* Must remain last / highest */
-
-#elif LCD_BPP == LCD_COLOR8
-
-/*
- * 8bpp color definitions
- */
-# define CONSOLE_COLOR_BLACK 0
-# define CONSOLE_COLOR_RED 1
-# define CONSOLE_COLOR_GREEN 2
-# define CONSOLE_COLOR_YELLOW 3
-# define CONSOLE_COLOR_BLUE 4
-# define CONSOLE_COLOR_MAGENTA 5
-# define CONSOLE_COLOR_CYAN 6
-# define CONSOLE_COLOR_GREY 14
-# define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */
-
-#else
-
-/*
- * 16bpp color definitions
- */
-# define CONSOLE_COLOR_BLACK 0x0000
-# define CONSOLE_COLOR_WHITE 0xffff /* Must remain last / highest */
-
-#endif /* color definitions */
-
-/************************************************************************/
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
diff --git a/include/linux/bch.h b/include/linux/bch.h
new file mode 100644
index 0000000000..295b4ef153
--- /dev/null
+++ b/include/linux/bch.h
@@ -0,0 +1,79 @@
+/*
+ * Generic binary BCH encoding/decoding library
+ *
+ * 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.
+ *
+ * Copyright © 2011 Parrot S.A.
+ *
+ * Author: Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * Description:
+ *
+ * This library provides runtime configurable encoding/decoding of binary
+ * Bose-Chaudhuri-Hocquenghem (BCH) codes.
+*/
+#ifndef _BCH_H
+#define _BCH_H
+
+#include <linux/types.h>
+
+/**
+ * struct bch_control - BCH control structure
+ * @m: Galois field order
+ * @n: maximum codeword size in bits (= 2^m-1)
+ * @t: error correction capability in bits
+ * @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
+ * @ecc_bytes: ecc max size (m*t bits) in bytes
+ * @a_pow_tab: Galois field GF(2^m) exponentiation lookup table
+ * @a_log_tab: Galois field GF(2^m) log lookup table
+ * @mod8_tab: remainder generator polynomial lookup tables
+ * @ecc_buf: ecc parity words buffer
+ * @ecc_buf2: ecc parity words buffer
+ * @xi_tab: GF(2^m) base for solving degree 2 polynomial roots
+ * @syn: syndrome buffer
+ * @cache: log-based polynomial representation buffer
+ * @elp: error locator polynomial
+ * @poly_2t: temporary polynomials of degree 2t
+ */
+struct bch_control {
+ unsigned int m;
+ unsigned int n;
+ unsigned int t;
+ unsigned int ecc_bits;
+ unsigned int ecc_bytes;
+/* private: */
+ uint16_t *a_pow_tab;
+ uint16_t *a_log_tab;
+ uint32_t *mod8_tab;
+ uint32_t *ecc_buf;
+ uint32_t *ecc_buf2;
+ unsigned int *xi_tab;
+ unsigned int *syn;
+ int *cache;
+ struct gf_poly *elp;
+ struct gf_poly *poly_2t[4];
+};
+
+struct bch_control *init_bch(int m, int t, unsigned int prim_poly);
+
+void free_bch(struct bch_control *bch);
+
+void encode_bch(struct bch_control *bch, const uint8_t *data,
+ unsigned int len, uint8_t *ecc);
+
+int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
+ const uint8_t *recv_ecc, const uint8_t *calc_ecc,
+ const unsigned int *syn, unsigned int *errloc);
+
+#endif /* _BCH_H */
diff --git a/include/linux/mtd/compat.h b/include/linux/mtd/compat.h
index 39c693f7a8..8727a36707 100644
--- a/include/linux/mtd/compat.h
+++ b/include/linux/mtd/compat.h
@@ -17,11 +17,21 @@
#define KERN_INFO
#define KERN_DEBUG
+#ifndef kmalloc
#define kmalloc(size, flags) malloc(size)
+#endif
+#ifndef kzalloc
#define kzalloc(size, flags) calloc(size, 1)
+#endif
+#ifndef vmalloc
#define vmalloc(size) malloc(size)
+#endif
+#ifndef kfree
#define kfree(ptr) free(ptr)
+#endif
+#ifndef vfree
#define vfree(ptr) free(ptr)
+#endif
#define DECLARE_WAITQUEUE(...) do { } while (0)
#define add_wait_queue(...) do { } while (0)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 3b18d7d688..74ef50737f 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -293,11 +293,13 @@ static inline void mtd_erase_callback(struct erase_info *instr)
#define MTD_DEBUG_LEVEL1 (1) /* Audible */
#define MTD_DEBUG_LEVEL2 (2) /* Loud */
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
+#define MTD_DEBUG_LEVEL4 (4) /* Picky */
#ifdef CONFIG_MTD_DEBUG
+extern int mtd_debug_verbose;
#define MTDDEBUG(n, args...) \
do { \
- if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
+ if (n <= mtd_debug_verbose) \
printk(KERN_INFO args); \
} while(0)
#else /* CONFIG_MTD_DEBUG */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 987a2ec85d..d2032b47c5 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -88,6 +88,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
#define NAND_CMD_READID 0x90
#define NAND_CMD_PARAM 0xec
#define NAND_CMD_ERASE2 0xd0
+#define NAND_CMD_SETFEATURE 0xee
+#define NAND_CMD_GETFEATURE 0xef
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
@@ -95,6 +97,11 @@ extern void nand_wait_ready(struct mtd_info *mtd);
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
+/* Extended commands for ONFI devices */
+#define NAND_CMD_READ_PARAM 0xec
+#define NAND_CMD_GET_FEATURES 0xee
+#define NAND_CMD_SET_FEATURES 0xef
+
/* Extended commands for AG-AND device */
/*
* Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
@@ -132,6 +139,9 @@ typedef enum {
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
NAND_ECC_HW_OOB_FIRST,
+ NAND_ECC_CHIP, /* ECC hardware in-chip */
+ NAND_ECC_SOFT_BCH, /* Soft BCH ECC engine */
+ NAND_ECC_HW_BCH, /* If NAND uses soft-BCH instead of ECC_CHIP */
} nand_ecc_modes_t;
/*
@@ -308,6 +318,7 @@ struct nand_hw_control {
* @prepad: padding information for syndrome based ecc generators
* @postpad: padding information for syndrome based ecc generators
* @layout: ECC layout control struct pointer
+ * @priv: pointer to private ecc control data
* @hwctl: function to control hardware ecc generator. Must only
* be provided if an hardware ECC is available
* @calculate: function for ecc calculation or readback from ecc hardware
@@ -328,6 +339,7 @@ struct nand_ecc_ctrl {
int prepad;
int postpad;
struct nand_ecclayout *layout;
+ void *priv;
void (*hwctl)(struct mtd_info *mtd, int mode);
int (*calculate)(struct mtd_info *mtd,
const uint8_t *dat,
@@ -438,6 +450,10 @@ struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
+ uint8_t maf_id, dev_id; /* manufacturer/device identifier */
+ uint8_t has_chip_ecc; /* !0 if chip has intern ECC engine */
+ uint8_t ecc_status; /* status of read w/ECC */
+
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
@@ -623,4 +639,20 @@ struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
return chip->priv;
}
+extern int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+extern int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi);
+extern void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+extern int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+extern void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+extern int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd);
+extern int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page);
+
+
#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
new file mode 100644
index 0000000000..74acf53675
--- /dev/null
+++ b/include/linux/mtd/nand_bch.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * 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 file is the header for the NAND BCH ECC implementation.
+ */
+
+#ifndef __MTD_NAND_BCH_H__
+#define __MTD_NAND_BCH_H__
+
+struct mtd_info;
+struct nand_bch_control;
+
+#if defined(CONFIG_MTD_NAND_ECC_BCH)
+
+static inline int mtd_nand_has_bch(void) { return 1; }
+
+/*
+ * Calculate BCH ecc code
+ */
+int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code);
+
+/*
+ * Detect and correct bit errors
+ */
+int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
+ u_char *calc_ecc);
+/*
+ * Initialize BCH encoder/decoder
+ */
+struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+ unsigned int eccbytes, struct nand_ecclayout **ecclayout);
+/*
+ * Release BCH encoder/decoder resources
+ */
+void nand_bch_free(struct nand_bch_control *nbc);
+
+#else /* !CONFIG_MTD_NAND_ECC_BCH */
+
+static inline int mtd_nand_has_bch(void) { return 0; }
+
+static inline int
+nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ return -1;
+}
+
+static inline int
+nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+ return -1;
+}
+
+static inline struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+ unsigned int eccbytes, struct nand_ecclayout **ecclayout)
+{
+ return NULL;
+}
+
+static inline void nand_bch_free(struct nand_bch_control *nbc) {}
+
+#endif /* CONFIG_MTD_NAND_ECC_BCH */
+
+#endif /* __MTD_NAND_BCH_H__ */
diff --git a/include/mtd_parts.h b/include/mtd_parts.h
new file mode 100644
index 0000000000..87e2882c69
--- /dev/null
+++ b/include/mtd_parts.h
@@ -0,0 +1,35 @@
+/*
+ * (C) Copyright 2011
+ * Logic Product Devleopemnt <www.logicpd.com>
+ * Peter Barada <peter.barada@logicpd.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
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __MTD_PARTS_H__
+#define __MTD_PARTS_H__
+extern int mtd_get_part_priv(const char *partname, int *idx,
+ struct mtd_device **dev, loff_t *off,
+ loff_t *size, void **cookie, void **priv, int quiet);
+
+extern void mtd_set_part_priv(void *cookie, void *priv);
+
+extern int mtd_id_parse(const char *id, const char **ret_id,
+ u8 *dev_type, u8 *dev_num, int quiet);
+extern int mtdparts_init(void);
+#endif
diff --git a/include/nand.h b/include/nand.h
index 7459bd0330..f7b0a60b8a 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -25,6 +25,7 @@
#define _NAND_H_
extern void nand_init(void);
+extern int nand_set_dev(int idx);
#include <linux/mtd/compat.h>
#include <linux/mtd/mtd.h>
@@ -126,6 +127,9 @@ int nand_lock( nand_info_t *meminfo, int tight );
int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
+int nand_get_features( nand_info_t *meminfo, uint8_t faddr, uint8_t *features);
+int nand_set_features( nand_info_t *meminfo, uint8_t faddr, uint8_t *features);
+
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
void board_nand_select_device(struct nand_chip *nand, int chip);
#endif
diff --git a/include/twl4030.h b/include/twl4030.h
index 930c285c26..6d5bb1553a 100644
--- a/include/twl4030.h
+++ b/include/twl4030.h
@@ -356,6 +356,22 @@
#define TWL4030_KEYPAD_CTRL_SOFTMODEN (1 << 1)
#define TWL4030_KEYPAD_CTRL_SOFT_NRST (1 << 0)
+/* Main charge */
+#define TWL4030_MAIN_CHARGE_BCIMFKEY 0x85
+#define TWL4030_MAIN_CHARGE_BCIMFEN1 0x86
+#define TWL4030_MAIN_CHARGE_BCIMFTH1 0x8A
+
+#define TWL4030_MAIN_CHARGE_BCIMFKEY_MFKEY1 0x57
+#define TWL4030_MAIN_CHARGE_BCIMFKEY_MFKEY5 0xD2
+#define TWL4030_MAIN_CHARGE_BCIMFEN1_VBATOV1EN (1 << 7)
+#define TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_MASK 0x0F
+#define TWL4030_MAIN_CHARGE_BCIMFTH1_VBATOV1TH_2636_mV 0x00
+
+/* INTBR */
+#define TWL4030_INTBR_GPBR1 0x91
+#define TWL4030_INTBR_GPBR1_MADC_HFCLK_EN 0x80
+#define TWL4030_INTBR_GPBR1_DEFAULT_MADC_CLK_EN 0x10
+
/* USB */
#define TWL4030_USB_VENDOR_ID_LO 0x00
#define TWL4030_USB_VENDOR_ID_HI 0x01
@@ -482,6 +498,58 @@
#define TWL4030_USB_PHY_CLK_CTRL_STS 0xFF
/*
+ * GPIO Block Register offsets (use TWL4030_CHIP_GPIO)
+ */
+
+#define REG_GPIODATAIN1 0x0
+#define REG_GPIODATAIN2 0x1
+#define REG_GPIODATAIN3 0x2
+#define REG_GPIODATADIR1 0x3
+#define REG_GPIODATADIR2 0x4
+#define REG_GPIODATADIR3 0x5
+#define REG_GPIODATAOUT1 0x6
+#define REG_GPIODATAOUT2 0x7
+#define REG_GPIODATAOUT3 0x8
+#define REG_CLEARGPIODATAOUT1 0x9
+#define REG_CLEARGPIODATAOUT2 0xA
+#define REG_CLEARGPIODATAOUT3 0xB
+#define REG_SETGPIODATAOUT1 0xC
+#define REG_SETGPIODATAOUT2 0xD
+#define REG_SETGPIODATAOUT3 0xE
+#define REG_GPIO_DEBEN1 0xF
+#define REG_GPIO_DEBEN2 0x10
+#define REG_GPIO_DEBEN3 0x11
+#define REG_GPIO_CTRL 0x12
+#define REG_GPIOPUPDCTR1 0x13
+#define REG_GPIOPUPDCTR2 0x14
+#define REG_GPIOPUPDCTR3 0x15
+#define REG_GPIOPUPDCTR4 0x16
+#define REG_GPIOPUPDCTR5 0x17
+#define REG_GPIO_ISR1A 0x19
+#define REG_GPIO_ISR2A 0x1A
+#define REG_GPIO_ISR3A 0x1B
+#define REG_GPIO_IMR1A 0x1C
+#define REG_GPIO_IMR2A 0x1D
+#define REG_GPIO_IMR3A 0x1E
+#define REG_GPIO_ISR1B 0x1F
+#define REG_GPIO_ISR2B 0x20
+#define REG_GPIO_ISR3B 0x21
+#define REG_GPIO_IMR1B 0x22
+#define REG_GPIO_IMR2B 0x23
+#define REG_GPIO_IMR3B 0x24
+#define REG_GPIO_EDR1 0x28
+#define REG_GPIO_EDR2 0x29
+#define REG_GPIO_EDR3 0x2A
+#define REG_GPIO_EDR4 0x2B
+#define REG_GPIO_EDR5 0x2C
+#define REG_GPIO_SIH_CTRL 0x2D
+
+/* Up to 18 signals are available as GPIOs, when their
+ * pins are not assigned to another use (such as ULPI/USB).
+ */
+#define TWL4030_GPIO_MAX 18
+
+/*
* Convience functions to read and write from TWL4030
*
* chip_no is the i2c address, it must be one of the chip addresses
@@ -511,6 +579,8 @@ static inline int twl4030_i2c_read_u8(u8 chip_no, u8 *val, u8 reg)
/* For hardware resetting */
void twl4030_power_reset_init(void);
+/* For power down */
+void twl4030_power_off(void);
/* For setting device group and voltage */
void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
u8 dev_grp, u8 dev_grp_sel);
@@ -518,6 +588,8 @@ void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
void twl4030_power_init(void);
/* For initializing mmc power */
void twl4030_power_mmc_init(void);
+/* For charging */
+int twl4030_enable_charging(void);
/*
* LED
@@ -529,4 +601,19 @@ void twl4030_led_init(unsigned char ledon_mask);
*/
int twl4030_usb_ulpi_init(void);
+/*
+ * GPIO
+ */
+extern int twl4030_set_gpio_direction(unsigned int gpio, unsigned int is_input);
+extern int twl4030_set_gpio_dataout(unsigned int gpio, unsigned int enable);
+extern int twl4030_get_gpio_datain(unsigned int gpio);
+extern int twl4030_request_gpio(unsigned int gpio);
+extern void twl4030_free_gpio(unsigned int gpio);
+
+/*
+ * PWM
+ */
+extern int twl4030_set_pwm0(int level, int max_brightness);
+extern void twl4030_dump_pwm0(void);
+
#endif /* TWL4030_H */
diff --git a/lib/Makefile b/lib/Makefile
index afa6914e1b..71603bf82e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,6 +32,7 @@ COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o
COBJS-$(CONFIG_BZIP2) += bzlib_randtable.o
COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o
COBJS-$(CONFIG_USB_TTY) += circbuf.o
+COBJS-$(CONFIG_BCH) += bch.o
COBJS-y += crc7.o
COBJS-y += crc16.o
COBJS-y += crc32.o
diff --git a/lib/bch.c b/lib/bch.c
new file mode 100644
index 0000000000..8a41fb8cb6
--- /dev/null
+++ b/lib/bch.c
@@ -0,0 +1,1409 @@
+/*
+ * Generic binary BCH encoding/decoding library
+ *
+ * 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.
+ *
+ * Copyright © 2011 Parrot S.A.
+ *
+ * Author: Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * Description:
+ *
+ * This library provides runtime configurable encoding/decoding of binary
+ * Bose-Chaudhuri-Hocquenghem (BCH) codes.
+ *
+ * Call init_bch to get a pointer to a newly allocated bch_control structure for
+ * the given m (Galois field order), t (error correction capability) and
+ * (optional) primitive polynomial parameters.
+ *
+ * Call encode_bch to compute and store ecc parity bytes to a given buffer.
+ * Call decode_bch to detect and locate errors in received data.
+ *
+ * On systems supporting hw BCH features, intermediate results may be provided
+ * to decode_bch in order to skip certain steps. See decode_bch() documentation
+ * for details.
+ *
+ * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of
+ * parameters m and t; thus allowing extra compiler optimizations and providing
+ * better (up to 2x) encoding performance. Using this option makes sense when
+ * (m,t) are fixed and known in advance, e.g. when using BCH error correction
+ * on a particular NAND flash device.
+ *
+ * Algorithmic details:
+ *
+ * Encoding is performed by processing 32 input bits in parallel, using 4
+ * remainder lookup tables.
+ *
+ * The final stage of decoding involves the following internal steps:
+ * a. Syndrome computation
+ * b. Error locator polynomial computation using Berlekamp-Massey algorithm
+ * c. Error locator root finding (by far the most expensive step)
+ *
+ * In this implementation, step c is not performed using the usual Chien search.
+ * Instead, an alternative approach described in [1] is used. It consists in
+ * factoring the error locator polynomial using the Berlekamp Trace algorithm
+ * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial
+ * solving techniques [2] are used. The resulting algorithm, called BTZ, yields
+ * much better performance than Chien search for usual (m,t) values (typically
+ * m >= 13, t < 32, see [1]).
+ *
+ * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields
+ * of characteristic 2, in: Western European Workshop on Research in Cryptology
+ * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear.
+ * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over
+ * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996.
+ */
+
+#if 1
+#if 1
+#include <config.h>
+#include <common.h>
+#include <linux/mtd/compat.h>
+#include <malloc.h>
+#include <errno.h>
+#endif
+// #include <linux/kernel.h>
+// #include <linux/errno.h>
+// #include <linux/init.h>
+// #include <linux/module.h>
+// #include <linux/slab.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <linux/bch.h>
+#else
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <linux/bch.h>
+#endif
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+#define GF_M(_p) (CONFIG_BCH_CONST_M)
+#define GF_T(_p) (CONFIG_BCH_CONST_T)
+#define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1)
+#else
+#define GF_M(_p) ((_p)->m)
+#define GF_T(_p) ((_p)->t)
+#define GF_N(_p) ((_p)->n)
+#endif
+
+#define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
+#define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
+
+#ifdef DEBUG_BCH
+#define dbg(args...) printf(args);
+#define gf_poly_str(x) "x"
+#else
+#ifndef dbg
+#define dbg(_fmt, args...) do {} while (0)
+#endif
+#endif
+
+/*
+ * represent a polynomial over GF(2^m)
+ */
+struct gf_poly {
+ unsigned int deg; /* polynomial degree */
+ unsigned int c[0]; /* polynomial terms */
+};
+
+/* given its degree, compute a polynomial size in bytes */
+#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
+
+/* polynomial of degree 1 */
+struct gf_poly_deg1 {
+ struct gf_poly poly;
+ unsigned int c[2];
+};
+
+/*
+ * same as encode_bch(), but process input data one byte at a time
+ */
+static void encode_bch_unaligned(struct bch_control *bch,
+ const unsigned char *data, unsigned int len,
+ uint32_t *ecc)
+{
+ int i;
+ const uint32_t *p;
+ const int l = BCH_ECC_WORDS(bch)-1;
+
+ while (len--) {
+ p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
+
+ for (i = 0; i < l; i++)
+ ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
+
+ ecc[l] = (ecc[l] << 8)^(*p);
+ }
+}
+
+/*
+ * convert ecc bytes to aligned, zero-padded 32-bit ecc words
+ */
+static void load_ecc8(struct bch_control *bch, uint32_t *dst,
+ const uint8_t *src)
+{
+ uint8_t pad[4] = {0, 0, 0, 0};
+ unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+ for (i = 0; i < nwords; i++, src += 4)
+ dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
+
+ memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
+ dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
+}
+
+/*
+ * convert 32-bit ecc words to ecc bytes
+ */
+static void store_ecc8(struct bch_control *bch, uint8_t *dst,
+ const uint32_t *src)
+{
+ uint8_t pad[4];
+ unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+ for (i = 0; i < nwords; i++) {
+ *dst++ = (src[i] >> 24);
+ *dst++ = (src[i] >> 16) & 0xff;
+ *dst++ = (src[i] >> 8) & 0xff;
+ *dst++ = (src[i] >> 0) & 0xff;
+ }
+ pad[0] = (src[nwords] >> 24);
+ pad[1] = (src[nwords] >> 16) & 0xff;
+ pad[2] = (src[nwords] >> 8) & 0xff;
+ pad[3] = (src[nwords] >> 0) & 0xff;
+ memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
+}
+
+/**
+ * encode_bch - calculate BCH ecc parity of data
+ * @bch: BCH control structure
+ * @data: data to encode
+ * @len: data length in bytes
+ * @ecc: ecc parity data, must be initialized by caller
+ *
+ * The @ecc parity array is used both as input and output parameter, in order to
+ * allow incremental computations. It should be of the size indicated by member
+ * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
+ *
+ * The exact number of computed ecc parity bits is given by member @ecc_bits of
+ * @bch; it may be less than m*t for large values of t.
+ */
+void encode_bch(struct bch_control *bch, const uint8_t *data,
+ unsigned int len, uint8_t *ecc)
+{
+ const unsigned int l = BCH_ECC_WORDS(bch)-1;
+ unsigned int i, mlen;
+ unsigned long m;
+ uint32_t w, r[l+1];
+ const uint32_t * const tab0 = bch->mod8_tab;
+ const uint32_t * const tab1 = tab0 + 256*(l+1);
+ const uint32_t * const tab2 = tab1 + 256*(l+1);
+ const uint32_t * const tab3 = tab2 + 256*(l+1);
+ const uint32_t *pdata, *p0, *p1, *p2, *p3;
+
+ if (ecc) {
+ /* load ecc parity bytes into internal 32-bit buffer */
+ load_ecc8(bch, bch->ecc_buf, ecc);
+ } else {
+ memset(bch->ecc_buf, 0, sizeof(r));
+ }
+
+ /* process first unaligned data bytes */
+ m = ((unsigned long)data) & 3;
+ if (m) {
+ mlen = (len < (4-m)) ? len : 4-m;
+ encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
+ data += mlen;
+ len -= mlen;
+ }
+
+ /* process 32-bit aligned data words */
+ pdata = (uint32_t *)data;
+ mlen = len/4;
+ data += 4*mlen;
+ len -= 4*mlen;
+ memcpy(r, bch->ecc_buf, sizeof(r));
+
+ /*
+ * split each 32-bit word into 4 polynomials of weight 8 as follows:
+ *
+ * 31 ...24 23 ...16 15 ... 8 7 ... 0
+ * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt
+ * tttttttt mod g = r0 (precomputed)
+ * zzzzzzzz 00000000 mod g = r1 (precomputed)
+ * yyyyyyyy 00000000 00000000 mod g = r2 (precomputed)
+ * xxxxxxxx 00000000 00000000 00000000 mod g = r3 (precomputed)
+ * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt mod g = r0^r1^r2^r3
+ */
+ while (mlen--) {
+ /* input data is read in big-endian format */
+ w = r[0]^cpu_to_be32(*pdata++);
+ p0 = tab0 + (l+1)*((w >> 0) & 0xff);
+ p1 = tab1 + (l+1)*((w >> 8) & 0xff);
+ p2 = tab2 + (l+1)*((w >> 16) & 0xff);
+ p3 = tab3 + (l+1)*((w >> 24) & 0xff);
+
+ for (i = 0; i < l; i++)
+ r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
+
+ r[l] = p0[l]^p1[l]^p2[l]^p3[l];
+ }
+ memcpy(bch->ecc_buf, r, sizeof(r));
+
+ /* process last unaligned bytes */
+ if (len)
+ encode_bch_unaligned(bch, data, len, bch->ecc_buf);
+
+ /* store ecc parity bytes into original parity buffer */
+ if (ecc)
+ store_ecc8(bch, ecc, bch->ecc_buf);
+}
+// EXPORT_SYMBOL_GPL(encode_bch);
+
+static inline int modulo(struct bch_control *bch, unsigned int v)
+{
+ const unsigned int n = GF_N(bch);
+ while (v >= n) {
+ v -= n;
+ v = (v & n) + (v >> GF_M(bch));
+ }
+ return v;
+}
+
+/*
+ * shorter and faster modulo function, only works when v < 2N.
+ */
+static inline int mod_s(struct bch_control *bch, unsigned int v)
+{
+ const unsigned int n = GF_N(bch);
+ return (v < n) ? v : v-n;
+}
+
+static inline int deg(unsigned int poly)
+{
+ /* polynomial degree is the most-significant bit index */
+ return fls(poly)-1;
+}
+
+static inline int parity(unsigned int x)
+{
+ /*
+ * public domain code snippet, lifted from
+ * http://www-graphics.stanford.edu/~seander/bithacks.html
+ */
+ x ^= x >> 1;
+ x ^= x >> 2;
+ x = (x & 0x11111111U) * 0x11111111U;
+ return (x >> 28) & 1;
+}
+
+/* Galois field basic operations: multiply, divide, inverse, etc. */
+
+static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
+ unsigned int b)
+{
+ return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
+ bch->a_log_tab[b])] : 0;
+}
+
+static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
+{
+ return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
+}
+
+static inline unsigned int gf_div(struct bch_control *bch, unsigned int a,
+ unsigned int b)
+{
+ return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
+ GF_N(bch)-bch->a_log_tab[b])] : 0;
+}
+
+static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a)
+{
+ return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]];
+}
+
+static inline unsigned int a_pow(struct bch_control *bch, int i)
+{
+ return bch->a_pow_tab[modulo(bch, i)];
+}
+
+static inline int a_log(struct bch_control *bch, unsigned int x)
+{
+ return bch->a_log_tab[x];
+}
+
+static inline int a_ilog(struct bch_control *bch, unsigned int x)
+{
+ return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]);
+}
+
+/*
+ * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t
+ */
+static void compute_syndromes(struct bch_control *bch, uint32_t *ecc,
+ unsigned int *syn)
+{
+ int i, j, s;
+ unsigned int m;
+ uint32_t poly;
+ const int t = GF_T(bch);
+
+ s = bch->ecc_bits;
+
+ /* make sure extra bits in last ecc word are cleared */
+ m = ((unsigned int)s) & 31;
+ if (m)
+ ecc[s/32] &= ~((1u << (32-m))-1);
+ memset(syn, 0, 2*t*sizeof(*syn));
+
+ /* compute v(a^j) for j=1 .. 2t-1 */
+ do {
+ poly = *ecc++;
+ s -= 32;
+ while (poly) {
+ i = deg(poly);
+ for (j = 0; j < 2*t; j += 2)
+ syn[j] ^= a_pow(bch, (j+1)*(i+s));
+
+ poly ^= (1 << i);
+ }
+ } while (s > 0);
+
+ /* v(a^(2j)) = v(a^j)^2 */
+ for (j = 0; j < t; j++)
+ syn[2*j+1] = gf_sqr(bch, syn[j]);
+}
+
+static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src)
+{
+ memcpy(dst, src, GF_POLY_SZ(src->deg));
+}
+
+static int compute_error_locator_polynomial(struct bch_control *bch,
+ const unsigned int *syn)
+{
+ const unsigned int t = GF_T(bch);
+ const unsigned int n = GF_N(bch);
+ unsigned int i, j, tmp, l, pd = 1, d = syn[0];
+ struct gf_poly *elp = bch->elp;
+ struct gf_poly *pelp = bch->poly_2t[0];
+ struct gf_poly *elp_copy = bch->poly_2t[1];
+ int k, pp = -1;
+
+ memset(pelp, 0, GF_POLY_SZ(2*t));
+ memset(elp, 0, GF_POLY_SZ(2*t));
+
+ pelp->deg = 0;
+ pelp->c[0] = 1;
+ elp->deg = 0;
+ elp->c[0] = 1;
+
+ /* use simplified binary Berlekamp-Massey algorithm */
+ for (i = 0; (i < t) && (elp->deg <= t); i++) {
+ if (d) {
+ k = 2*i-pp;
+ gf_poly_copy(elp_copy, elp);
+ /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */
+ tmp = a_log(bch, d)+n-a_log(bch, pd);
+ for (j = 0; j <= pelp->deg; j++) {
+ if (pelp->c[j]) {
+ l = a_log(bch, pelp->c[j]);
+ elp->c[j+k] ^= a_pow(bch, tmp+l);
+ }
+ }
+ /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */
+ tmp = pelp->deg+k;
+ if (tmp > elp->deg) {
+ elp->deg = tmp;
+ gf_poly_copy(pelp, elp_copy);
+ pd = d;
+ pp = 2*i;
+ }
+ }
+ /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */
+ if (i < t-1) {
+ d = syn[2*i+2];
+ for (j = 1; j <= elp->deg; j++)
+ d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]);
+ }
+ }
+ dbg("elp=%s\n", gf_poly_str(elp));
+ return (elp->deg > t) ? -1 : (int)elp->deg;
+}
+
+/*
+ * solve a m x m linear system in GF(2) with an expected number of solutions,
+ * and return the number of found solutions
+ */
+static int solve_linear_system(struct bch_control *bch, unsigned int *rows,
+ unsigned int *sol, int nsol)
+{
+ const int m = GF_M(bch);
+ unsigned int tmp, mask;
+ int rem, c, r, p, k, param[m];
+
+ k = 0;
+ mask = 1 << m;
+
+ /* Gaussian elimination */
+ for (c = 0; c < m; c++) {
+ rem = 0;
+ p = c-k;
+ /* find suitable row for elimination */
+ for (r = p; r < m; r++) {
+ if (rows[r] & mask) {
+ if (r != p) {
+ tmp = rows[r];
+ rows[r] = rows[p];
+ rows[p] = tmp;
+ }
+ rem = r+1;
+ break;
+ }
+ }
+ if (rem) {
+ /* perform elimination on remaining rows */
+ tmp = rows[p];
+ for (r = rem; r < m; r++) {
+ if (rows[r] & mask)
+ rows[r] ^= tmp;
+ }
+ } else {
+ /* elimination not needed, store defective row index */
+ param[k++] = c;
+ }
+ mask >>= 1;
+ }
+ /* rewrite system, inserting fake parameter rows */
+ if (k > 0) {
+ p = k;
+ for (r = m-1; r >= 0; r--) {
+ if ((r > m-1-k) && rows[r])
+ /* system has no solution */
+ return 0;
+
+ rows[r] = (p && (r == param[p-1])) ?
+ p--, 1u << (m-r) : rows[r-p];
+ }
+ }
+
+ if (nsol != (1 << k))
+ /* unexpected number of solutions */
+ return 0;
+
+ for (p = 0; p < nsol; p++) {
+ /* set parameters for p-th solution */
+ for (c = 0; c < k; c++)
+ rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1);
+
+ /* compute unique solution */
+ tmp = 0;
+ for (r = m-1; r >= 0; r--) {
+ mask = rows[r] & (tmp|1);
+ tmp |= parity(mask) << (m-r);
+ }
+ sol[p] = tmp >> 1;
+ }
+ return nsol;
+}
+
+/*
+ * this function builds and solves a linear system for finding roots of a degree
+ * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m).
+ */
+static int find_affine4_roots(struct bch_control *bch, unsigned int a,
+ unsigned int b, unsigned int c,
+ unsigned int *roots)
+{
+ int i, j, k;
+ const int m = GF_M(bch);
+ unsigned int mask = 0xff, t, rows[16] = {0,};
+
+ j = a_log(bch, b);
+ k = a_log(bch, a);
+ rows[0] = c;
+
+ /* buid linear system to solve X^4+aX^2+bX+c = 0 */
+ for (i = 0; i < m; i++) {
+ rows[i+1] = bch->a_pow_tab[4*i]^
+ (a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^
+ (b ? bch->a_pow_tab[mod_s(bch, j)] : 0);
+ j++;
+ k += 2;
+ }
+ /*
+ * transpose 16x16 matrix before passing it to linear solver
+ * warning: this code assumes m < 16
+ */
+ for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) {
+ for (k = 0; k < 16; k = (k+j+1) & ~j) {
+ t = ((rows[k] >> j)^rows[k+j]) & mask;
+ rows[k] ^= (t << j);
+ rows[k+j] ^= t;
+ }
+ }
+ return solve_linear_system(bch, rows, roots, 4);
+}
+
+/*
+ * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r))
+ */
+static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly,
+ unsigned int *roots)
+{
+ int n = 0;
+
+ if (poly->c[0])
+ /* poly[X] = bX+c with c!=0, root=c/b */
+ roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+
+ bch->a_log_tab[poly->c[1]]);
+ return n;
+}
+
+/*
+ * compute roots of a degree 2 polynomial over GF(2^m)
+ */
+static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly,
+ unsigned int *roots)
+{
+ int n = 0, i, l0, l1, l2;
+ unsigned int u, v, r;
+
+ if (poly->c[0] && poly->c[1]) {
+
+ l0 = bch->a_log_tab[poly->c[0]];
+ l1 = bch->a_log_tab[poly->c[1]];
+ l2 = bch->a_log_tab[poly->c[2]];
+
+ /* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */
+ u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1));
+ /*
+ * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi):
+ * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) =
+ * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u)
+ * i.e. r and r+1 are roots iff Tr(u)=0
+ */
+ r = 0;
+ v = u;
+ while (v) {
+ i = deg(v);
+ r ^= bch->xi_tab[i];
+ v ^= (1 << i);
+ }
+ /* verify root */
+ if ((gf_sqr(bch, r)^r) == u) {
+ /* reverse z=a/bX transformation and compute log(1/r) */
+ roots[n++] = modulo(bch, 2*GF_N(bch)-l1-
+ bch->a_log_tab[r]+l2);
+ roots[n++] = modulo(bch, 2*GF_N(bch)-l1-
+ bch->a_log_tab[r^1]+l2);
+ }
+ }
+ return n;
+}
+
+/*
+ * compute roots of a degree 3 polynomial over GF(2^m)
+ */
+static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly,
+ unsigned int *roots)
+{
+ int i, n = 0;
+ unsigned int a, b, c, a2, b2, c2, e3, tmp[4];
+
+ if (poly->c[0]) {
+ /* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */
+ e3 = poly->c[3];
+ c2 = gf_div(bch, poly->c[0], e3);
+ b2 = gf_div(bch, poly->c[1], e3);
+ a2 = gf_div(bch, poly->c[2], e3);
+
+ /* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */
+ c = gf_mul(bch, a2, c2); /* c = a2c2 */
+ b = gf_mul(bch, a2, b2)^c2; /* b = a2b2 + c2 */
+ a = gf_sqr(bch, a2)^b2; /* a = a2^2 + b2 */
+
+ /* find the 4 roots of this affine polynomial */
+ if (find_affine4_roots(bch, a, b, c, tmp) == 4) {
+ /* remove a2 from final list of roots */
+ for (i = 0; i < 4; i++) {
+ if (tmp[i] != a2)
+ roots[n++] = a_ilog(bch, tmp[i]);
+ }
+ }
+ }
+ return n;
+}
+
+/*
+ * compute roots of a degree 4 polynomial over GF(2^m)
+ */
+static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly,
+ unsigned int *roots)
+{
+ int i, l, n = 0;
+ unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4;
+
+ if (poly->c[0] == 0)
+ return 0;
+
+ /* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */
+ e4 = poly->c[4];
+ d = gf_div(bch, poly->c[0], e4);
+ c = gf_div(bch, poly->c[1], e4);
+ b = gf_div(bch, poly->c[2], e4);
+ a = gf_div(bch, poly->c[3], e4);
+
+ /* use Y=1/X transformation to get an affine polynomial */
+ if (a) {
+ /* first, eliminate cX by using z=X+e with ae^2+c=0 */
+ if (c) {
+ /* compute e such that e^2 = c/a */
+ f = gf_div(bch, c, a);
+ l = a_log(bch, f);
+ l += (l & 1) ? GF_N(bch) : 0;
+ e = a_pow(bch, l/2);
+ /*
+ * use transformation z=X+e:
+ * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d
+ * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d
+ * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d
+ * z^4 + az^3 + b'z^2 + d'
+ */
+ d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d;
+ b = gf_mul(bch, a, e)^b;
+ }
+ /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */
+ if (d == 0)
+ /* assume all roots have multiplicity 1 */
+ return 0;
+
+ c2 = gf_inv(bch, d);
+ b2 = gf_div(bch, a, d);
+ a2 = gf_div(bch, b, d);
+ } else {
+ /* polynomial is already affine */
+ c2 = d;
+ b2 = c;
+ a2 = b;
+ }
+ /* find the 4 roots of this affine polynomial */
+ if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) {
+ for (i = 0; i < 4; i++) {
+ /* post-process roots (reverse transformations) */
+ f = a ? gf_inv(bch, roots[i]) : roots[i];
+ roots[i] = a_ilog(bch, f^e);
+ }
+ n = 4;
+ }
+ return n;
+}
+
+/*
+ * build monic, log-based representation of a polynomial
+ */
+static void gf_poly_logrep(struct bch_control *bch,
+ const struct gf_poly *a, int *rep)
+{
+ int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]);
+
+ /* represent 0 values with -1; warning, rep[d] is not set to 1 */
+ for (i = 0; i < d; i++)
+ rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1;
+}
+
+/*
+ * compute polynomial Euclidean division remainder in GF(2^m)[X]
+ */
+static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a,
+ const struct gf_poly *b, int *rep)
+{
+ int la, p, m;
+ unsigned int i, j, *c = a->c;
+ const unsigned int d = b->deg;
+
+ if (a->deg < d)
+ return;
+
+ /* reuse or compute log representation of denominator */
+ if (!rep) {
+ rep = bch->cache;
+ gf_poly_logrep(bch, b, rep);
+ }
+
+ for (j = a->deg; j >= d; j--) {
+ if (c[j]) {
+ la = a_log(bch, c[j]);
+ p = j-d;
+ for (i = 0; i < d; i++, p++) {
+ m = rep[i];
+ if (m >= 0)
+ c[p] ^= bch->a_pow_tab[mod_s(bch,
+ m+la)];
+ }
+ }
+ }
+ a->deg = d-1;
+ while (!c[a->deg] && a->deg)
+ a->deg--;
+}
+
+/*
+ * compute polynomial Euclidean division quotient in GF(2^m)[X]
+ */
+static void gf_poly_div(struct bch_control *bch, struct gf_poly *a,
+ const struct gf_poly *b, struct gf_poly *q)
+{
+ if (a->deg >= b->deg) {
+ q->deg = a->deg-b->deg;
+ /* compute a mod b (modifies a) */
+ gf_poly_mod(bch, a, b, NULL);
+ /* quotient is stored in upper part of polynomial a */
+ memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int));
+ } else {
+ q->deg = 0;
+ q->c[0] = 0;
+ }
+}
+
+/*
+ * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X]
+ */
+static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a,
+ struct gf_poly *b)
+{
+ struct gf_poly *tmp;
+
+ dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b));
+
+ if (a->deg < b->deg) {
+ tmp = b;
+ b = a;
+ a = tmp;
+ }
+
+ while (b->deg > 0) {
+ gf_poly_mod(bch, a, b, NULL);
+ tmp = b;
+ b = a;
+ a = tmp;
+ }
+
+ dbg("%s\n", gf_poly_str(a));
+
+ return a;
+}
+
+/*
+ * Given a polynomial f and an integer k, compute Tr(a^kX) mod f
+ * This is used in Berlekamp Trace algorithm for splitting polynomials
+ */
+static void compute_trace_bk_mod(struct bch_control *bch, int k,
+ const struct gf_poly *f, struct gf_poly *z,
+ struct gf_poly *out)
+{
+ const int m = GF_M(bch);
+ int i, j;
+
+ /* z contains z^2j mod f */
+ z->deg = 1;
+ z->c[0] = 0;
+ z->c[1] = bch->a_pow_tab[k];
+
+ out->deg = 0;
+ memset(out, 0, GF_POLY_SZ(f->deg));
+
+ /* compute f log representation only once */
+ gf_poly_logrep(bch, f, bch->cache);
+
+ for (i = 0; i < m; i++) {
+ /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */
+ for (j = z->deg; j >= 0; j--) {
+ out->c[j] ^= z->c[j];
+ z->c[2*j] = gf_sqr(bch, z->c[j]);
+ z->c[2*j+1] = 0;
+ }
+ if (z->deg > out->deg)
+ out->deg = z->deg;
+
+ if (i < m-1) {
+ z->deg *= 2;
+ /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */
+ gf_poly_mod(bch, z, f, bch->cache);
+ }
+ }
+ while (!out->c[out->deg] && out->deg)
+ out->deg--;
+
+ dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out));
+}
+
+/*
+ * factor a polynomial using Berlekamp Trace algorithm (BTA)
+ */
+static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f,
+ struct gf_poly **g, struct gf_poly **h)
+{
+ struct gf_poly *f2 = bch->poly_2t[0];
+ struct gf_poly *q = bch->poly_2t[1];
+ struct gf_poly *tk = bch->poly_2t[2];
+ struct gf_poly *z = bch->poly_2t[3];
+ struct gf_poly *gcd;
+
+ dbg("factoring %s...\n", gf_poly_str(f));
+
+ *g = f;
+ *h = NULL;
+
+ /* tk = Tr(a^k.X) mod f */
+ compute_trace_bk_mod(bch, k, f, z, tk);
+
+ if (tk->deg > 0) {
+ /* compute g = gcd(f, tk) (destructive operation) */
+ gf_poly_copy(f2, f);
+ gcd = gf_poly_gcd(bch, f2, tk);
+ if (gcd->deg < f->deg) {
+ /* compute h=f/gcd(f,tk); this will modify f and q */
+ gf_poly_div(bch, f, gcd, q);
+ /* store g and h in-place (clobbering f) */
+ *h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly;
+ gf_poly_copy(*g, gcd);
+ gf_poly_copy(*h, q);
+ }
+ }
+}
+
+/*
+ * find roots of a polynomial, using BTZ algorithm; see the beginning of this
+ * file for details
+ */
+static int find_poly_roots(struct bch_control *bch, unsigned int k,
+ struct gf_poly *poly, unsigned int *roots)
+{
+ int cnt;
+ struct gf_poly *f1, *f2;
+
+ switch (poly->deg) {
+ /* handle low degree polynomials with ad hoc techniques */
+ case 1:
+ cnt = find_poly_deg1_roots(bch, poly, roots);
+ break;
+ case 2:
+ cnt = find_poly_deg2_roots(bch, poly, roots);
+ break;
+ case 3:
+ cnt = find_poly_deg3_roots(bch, poly, roots);
+ break;
+ case 4:
+ cnt = find_poly_deg4_roots(bch, poly, roots);
+ break;
+ default:
+ /* factor polynomial using Berlekamp Trace Algorithm (BTA) */
+ cnt = 0;
+ if (poly->deg && (k <= GF_M(bch))) {
+ factor_polynomial(bch, k, poly, &f1, &f2);
+ if (f1)
+ cnt += find_poly_roots(bch, k+1, f1, roots);
+ if (f2)
+ cnt += find_poly_roots(bch, k+1, f2, roots+cnt);
+ }
+ break;
+ }
+ return cnt;
+}
+
+#if defined(USE_CHIEN_SEARCH)
+/*
+ * exhaustive root search (Chien) implementation - not used, included only for
+ * reference/comparison tests
+ */
+static int chien_search(struct bch_control *bch, unsigned int len,
+ struct gf_poly *p, unsigned int *roots)
+{
+ int m;
+ unsigned int i, j, syn, syn0, count = 0;
+ const unsigned int k = 8*len+bch->ecc_bits;
+
+ /* use a log-based representation of polynomial */
+ gf_poly_logrep(bch, p, bch->cache);
+ bch->cache[p->deg] = 0;
+ syn0 = gf_div(bch, p->c[0], p->c[p->deg]);
+
+ for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) {
+ /* compute elp(a^i) */
+ for (j = 1, syn = syn0; j <= p->deg; j++) {
+ m = bch->cache[j];
+ if (m >= 0)
+ syn ^= a_pow(bch, m+j*i);
+ }
+ if (syn == 0) {
+ roots[count++] = GF_N(bch)-i;
+ if (count == p->deg)
+ break;
+ }
+ }
+ return (count == p->deg) ? count : 0;
+}
+#define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc)
+#endif /* USE_CHIEN_SEARCH */
+
+/**
+ * decode_bch - decode received codeword and find bit error locations
+ * @bch: BCH control structure
+ * @data: received data, ignored if @calc_ecc is provided
+ * @len: data length in bytes, must always be provided
+ * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc
+ * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data
+ * @syn: hw computed syndrome data (if NULL, syndrome is calculated)
+ * @errloc: output array of error locations
+ *
+ * Returns:
+ * The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if
+ * invalid parameters were provided
+ *
+ * Depending on the available hw BCH support and the need to compute @calc_ecc
+ * separately (using encode_bch()), this function should be called with one of
+ * the following parameter configurations -
+ *
+ * by providing @data and @recv_ecc only:
+ * decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc)
+ *
+ * by providing @recv_ecc and @calc_ecc:
+ * decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc)
+ *
+ * by providing ecc = recv_ecc XOR calc_ecc:
+ * decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc)
+ *
+ * by providing syndrome results @syn:
+ * decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc)
+ *
+ * Once decode_bch() has successfully returned with a positive value, error
+ * locations returned in array @errloc should be interpreted as follows -
+ *
+ * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for
+ * data correction)
+ *
+ * if (errloc[n] < 8*len), then n-th error is located in data and can be
+ * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8);
+ *
+ * Note that this function does not perform any data correction by itself, it
+ * merely indicates error locations.
+ */
+int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
+ const uint8_t *recv_ecc, const uint8_t *calc_ecc,
+ const unsigned int *syn, unsigned int *errloc)
+{
+ const unsigned int ecc_words = BCH_ECC_WORDS(bch);
+ unsigned int nbits;
+ int i, err, nroots;
+ uint32_t sum;
+
+#ifdef DEBUG_BCH
+ printf("%s:%d syn %p\n", __FUNCTION__, __LINE__, syn);
+#endif
+ /* sanity check: make sure data length can be handled */
+ if (8*len > (bch->n-bch->ecc_bits))
+ return -EINVAL;
+
+ /* if caller does not provide syndromes, compute them */
+ if (!syn) {
+ if (!calc_ecc) {
+ /* compute received data ecc into an internal buffer */
+ if (!data || !recv_ecc)
+ return -EINVAL;
+ encode_bch(bch, data, len, NULL);
+ } else {
+ /* load provided calculated ecc */
+ load_ecc8(bch, bch->ecc_buf, calc_ecc);
+ }
+ /* load received ecc or assume it was XORed in calc_ecc */
+ if (recv_ecc) {
+ load_ecc8(bch, bch->ecc_buf2, recv_ecc);
+ /* XOR received and calculated ecc */
+ for (i = 0, sum = 0; i < (int)ecc_words; i++) {
+ bch->ecc_buf[i] ^= bch->ecc_buf2[i];
+ sum |= bch->ecc_buf[i];
+ }
+ if (!sum) {
+ /* no error found */
+#ifdef DEBUG_BCH
+ printf("%s:%d\n", __FUNCTION__, __LINE__);
+#endif
+ return 0;
+ }
+ }
+ compute_syndromes(bch, bch->ecc_buf, bch->syn);
+ syn = bch->syn;
+ }
+
+ err = compute_error_locator_polynomial(bch, syn);
+#ifdef DEBUG_BCH
+ printf("%s:%d err %d\n", __FUNCTION__, __LINE__, err);
+#endif
+ if (err > 0) {
+ nroots = find_poly_roots(bch, 1, bch->elp, errloc);
+ if (err != nroots) {
+#ifdef DEBUG_BCH
+ printf("%s:%d err %d nroots %d\n", __FUNCTION__, __LINE__, err, nroots);
+#endif
+ err = -1;
+ }
+ }
+ if (err > 0) {
+ /* post-process raw error locations for easier correction */
+ nbits = (len*8)+bch->ecc_bits;
+ for (i = 0; i < err; i++) {
+ if (errloc[i] >= nbits) {
+ err = -1;
+ break;
+ }
+ errloc[i] = nbits-1-errloc[i];
+ errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7));
+ }
+ }
+#ifdef DEBUG_BCH
+ if (err < 0)
+ printf("%s:%d err %d\n", __FUNCTION__, __LINE__, err);
+#endif
+ return (err >= 0) ? err : -EBADMSG;
+}
+// EXPORT_SYMBOL_GPL(decode_bch);
+
+/*
+ * generate Galois field lookup tables
+ */
+static int build_gf_tables(struct bch_control *bch, unsigned int poly)
+{
+ unsigned int i, x = 1;
+ const unsigned int k = 1 << deg(poly);
+
+ /* primitive polynomial must be of degree m */
+ if (k != (1u << GF_M(bch)))
+ return -1;
+
+ for (i = 0; i < GF_N(bch); i++) {
+ bch->a_pow_tab[i] = x;
+ bch->a_log_tab[x] = i;
+ if (i && (x == 1))
+ /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+ return -1;
+ x <<= 1;
+ if (x & k)
+ x ^= poly;
+ }
+ bch->a_pow_tab[GF_N(bch)] = 1;
+ bch->a_log_tab[0] = 0;
+
+ return 0;
+}
+
+/*
+ * compute generator polynomial remainder tables for fast encoding
+ */
+static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
+{
+ int i, j, b, d;
+ uint32_t data, hi, lo, *tab;
+ const int l = BCH_ECC_WORDS(bch);
+ const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
+ const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
+
+ memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
+
+ for (i = 0; i < 256; i++) {
+ /* p(X)=i is a small polynomial of weight <= 8 */
+ for (b = 0; b < 4; b++) {
+ /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
+ tab = bch->mod8_tab + (b*256+i)*l;
+ data = i << (8*b);
+ while (data) {
+ d = deg(data);
+ /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
+ data ^= g[0] >> (31-d);
+ for (j = 0; j < ecclen; j++) {
+ hi = (d < 31) ? g[j] << (d+1) : 0;
+ lo = (j+1 < plen) ?
+ g[j+1] >> (31-d) : 0;
+ tab[j] ^= hi|lo;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * build a base for factoring degree 2 polynomials
+ */
+static int build_deg2_base(struct bch_control *bch)
+{
+ const int m = GF_M(bch);
+ int i, j, r;
+ unsigned int sum, x, y, remaining, ak = 0, xi[m];
+
+ /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
+ for (i = 0; i < m; i++) {
+ for (j = 0, sum = 0; j < m; j++)
+ sum ^= a_pow(bch, i*(1 << j));
+
+ if (sum) {
+ ak = bch->a_pow_tab[i];
+ break;
+ }
+ }
+ /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
+ remaining = m;
+ memset(xi, 0, sizeof(xi));
+
+ for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
+ y = gf_sqr(bch, x)^x;
+ for (i = 0; i < 2; i++) {
+ r = a_log(bch, y);
+ if (y && (r < m) && !xi[r]) {
+ bch->xi_tab[r] = x;
+ xi[r] = 1;
+ remaining--;
+ dbg("x%d = %x\n", r, x);
+ break;
+ }
+ y ^= ak;
+ }
+ }
+ /* should not happen but check anyway */
+ return remaining ? -1 : 0;
+}
+
+static void *bch_alloc(size_t size, int *err)
+{
+ void *ptr;
+
+ ptr = kmalloc(size, GFP_KERNEL);
+ if (ptr == NULL)
+ *err = 1;
+ return ptr;
+}
+
+/*
+ * compute generator polynomial for given (m,t) parameters.
+ */
+static uint32_t *compute_generator_polynomial(struct bch_control *bch)
+{
+ const unsigned int m = GF_M(bch);
+ const unsigned int t = GF_T(bch);
+ int n, err = 0;
+ unsigned int i, j, nbits, r, word, *roots;
+ struct gf_poly *g;
+ uint32_t *genpoly;
+
+ g = bch_alloc(GF_POLY_SZ(m*t), &err);
+ roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
+ genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
+
+ if (err) {
+ kfree(genpoly);
+ genpoly = NULL;
+ goto finish;
+ }
+
+ /* enumerate all roots of g(X) */
+ memset(roots , 0, (bch->n+1)*sizeof(*roots));
+ for (i = 0; i < t; i++) {
+ for (j = 0, r = 2*i+1; j < m; j++) {
+ roots[r] = 1;
+ r = mod_s(bch, 2*r);
+ }
+ }
+ /* build generator polynomial g(X) */
+ g->deg = 0;
+ g->c[0] = 1;
+ for (i = 0; i < GF_N(bch); i++) {
+ if (roots[i]) {
+ /* multiply g(X) by (X+root) */
+ r = bch->a_pow_tab[i];
+ g->c[g->deg+1] = 1;
+ for (j = g->deg; j > 0; j--)
+ g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
+
+ g->c[0] = gf_mul(bch, g->c[0], r);
+ g->deg++;
+ }
+ }
+ /* store left-justified binary representation of g(X) */
+ n = g->deg+1;
+ i = 0;
+
+ while (n > 0) {
+ nbits = (n > 32) ? 32 : n;
+ for (j = 0, word = 0; j < nbits; j++) {
+ if (g->c[n-1-j])
+ word |= 1u << (31-j);
+ }
+ genpoly[i++] = word;
+ n -= nbits;
+ }
+ bch->ecc_bits = g->deg;
+
+finish:
+ kfree(g);
+ kfree(roots);
+
+ return genpoly;
+}
+
+/**
+ * init_bch - initialize a BCH encoder/decoder
+ * @m: Galois field order, should be in the range 5-15
+ * @t: maximum error correction capability, in bits
+ * @prim_poly: user-provided primitive polynomial (or 0 to use default)
+ *
+ * Returns:
+ * a newly allocated BCH control structure if successful, NULL otherwise
+ *
+ * This initialization can take some time, as lookup tables are built for fast
+ * encoding/decoding; make sure not to call this function from a time critical
+ * path. Usually, init_bch() should be called on module/driver init and
+ * free_bch() should be called to release memory on exit.
+ *
+ * You may provide your own primitive polynomial of degree @m in argument
+ * @prim_poly, or let init_bch() use its default polynomial.
+ *
+ * Once init_bch() has successfully returned a pointer to a newly allocated
+ * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
+ * the structure.
+ */
+struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
+{
+ int err = 0;
+ unsigned int i, words;
+ uint32_t *genpoly;
+ struct bch_control *bch = NULL;
+
+ const int min_m = 5;
+ const int max_m = 15;
+
+ /* default primitive polynomials */
+ static const unsigned int prim_poly_tab[] = {
+ 0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
+ 0x402b, 0x8003,
+ };
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+ if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
+ printk(KERN_ERR "bch encoder/decoder was configured to support "
+ "parameters m=%d, t=%d only!\n",
+ CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
+ goto fail;
+ }
+#endif
+ if ((m < min_m) || (m > max_m))
+ /*
+ * values of m greater than 15 are not currently supported;
+ * supporting m > 15 would require changing table base type
+ * (uint16_t) and a small patch in matrix transposition
+ */
+ goto fail;
+
+ /* sanity checks */
+ if ((t < 1) || (m*t >= ((1 << m)-1)))
+ /* invalid t value */
+ goto fail;
+
+ /* select a primitive polynomial for generating GF(2^m) */
+ if (prim_poly == 0)
+ prim_poly = prim_poly_tab[m-min_m];
+
+ bch = kzalloc(sizeof(*bch), GFP_KERNEL);
+ if (bch == NULL)
+ goto fail;
+
+ bch->m = m;
+ bch->t = t;
+ bch->n = (1 << m)-1;
+ words = DIV_ROUND_UP(m*t, 32);
+ bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
+ bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
+ bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
+ bch->mod8_tab = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
+ bch->ecc_buf = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
+ bch->ecc_buf2 = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
+ bch->xi_tab = bch_alloc(m*sizeof(*bch->xi_tab), &err);
+ bch->syn = bch_alloc(2*t*sizeof(*bch->syn), &err);
+ bch->cache = bch_alloc(2*t*sizeof(*bch->cache), &err);
+ bch->elp = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
+
+ for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+ bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
+
+ if (err)
+ goto fail;
+
+ err = build_gf_tables(bch, prim_poly);
+ if (err)
+ goto fail;
+
+ /* use generator polynomial for computing encoding tables */
+ genpoly = compute_generator_polynomial(bch);
+ if (genpoly == NULL)
+ goto fail;
+
+ build_mod8_tables(bch, genpoly);
+ kfree(genpoly);
+
+ err = build_deg2_base(bch);
+ if (err)
+ goto fail;
+
+ return bch;
+
+fail:
+ free_bch(bch);
+ return NULL;
+}
+// EXPORT_SYMBOL_GPL(init_bch);
+
+/**
+ * free_bch - free the BCH control structure
+ * @bch: BCH control structure to release
+ */
+void free_bch(struct bch_control *bch)
+{
+ unsigned int i;
+
+ if (bch) {
+ kfree(bch->a_pow_tab);
+ kfree(bch->a_log_tab);
+ kfree(bch->mod8_tab);
+ kfree(bch->ecc_buf);
+ kfree(bch->ecc_buf2);
+ kfree(bch->xi_tab);
+ kfree(bch->syn);
+ kfree(bch->cache);
+ kfree(bch->elp);
+
+ for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+ kfree(bch->poly_2t[i]);
+
+ kfree(bch);
+ }
+}
+// EXPORT_SYMBOL_GPL(free_bch);
+
+// MODULE_LICENSE("GPL");
+// MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
+// MODULE_DESCRIPTION("Binary BCH encoder/decoder");
diff --git a/mkconfig b/mkconfig
index 6ff533f339..ad9945e802 100755
--- a/mkconfig
+++ b/mkconfig
@@ -8,6 +8,8 @@
# (C) 2002-2010 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
#
+#set -x
+
APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output
TARGETS=""
@@ -139,6 +141,14 @@ fi
#
# Create board specific header file
#
+
+if [ -f config.h ]; then
+ mv config.h config.h.bak
+ cp config.h.bak config.h
+else
+ touch config.h.bak
+fi
+
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
@@ -160,4 +170,31 @@ cat << EOF >> config.h
#include <asm/config.h>
EOF
+#
+# Add TEXT_BASE from board config.mk in comment to config.h; this
+# causes config.h to change if the TEXT_BASE in board config.mk changes
+#
+config_mk=$SRCTREE/board
+if [ "$VENDOR" != "" ]; then
+ config_mk=$config_mk/$VENDOR
+fi
+if [ "$BOARD" != "" ]; then
+ config_mk=$config_mk/$BOARD
+fi
+
+if [ -d $config_mk -a -f $config_mk/config.mk ]; then
+ TEXT_BASE=`grep CONFIG_SYS_TEXT_BASE $config_mk/config.mk`
+fi
+if [ ! -z "$TEXT_BASE" ]; then
+ echo "/* $TEXT_BASE */" >> config.h
+else
+ rm config.h.bak
+fi
+
+cmp -s config.h config.h.bak && {
+ echo "same config.h file..."
+ rm config.h
+ mv config.h.bak config.h
+}
+
exit 0
diff --git a/tools/Makefile b/tools/Makefile
index 97f83f8431..2117752c08 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -69,6 +69,7 @@ BIN_FILES-$(CONFIG_INCA_IP) += inca-swap-bytes$(SFX)
BIN_FILES-y += mkimage$(SFX)
BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
+BIN_FILES-$(CONFIG_TOOL_SIGNGP) += sign-nand-image$(SFX)
# Source files which exist outside the tools directory
EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
@@ -83,6 +84,7 @@ OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
NOPED_OBJ_FILES-y += default_image.o
OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o
NOPED_OBJ_FILES-y += fit_image.o
+OBJ_FILES-$(CONFIG_TOOL_SIGNGP) += sign-nand-image.o
OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o
OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o
OBJ_FILES-$(CONFIG_INCA_IP) += inca-swap-bytes.o
@@ -204,6 +206,10 @@ $(obj)ncb$(SFX): $(obj)ncb.o
$(obj)ubsha1$(SFX): $(obj)os_support.o $(obj)sha1.o $(obj)ubsha1.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+$(obj)sign-nand-image$(SFX): $(obj)sign-nand-image.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
# Some of the tool objects need to be accessed from outside the tools directory
$(obj)%.o: $(SRCTREE)/common/%.c
$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
diff --git a/tools/sign-nand-image.c b/tools/sign-nand-image.c
new file mode 100644
index 0000000000..324ae227e4
--- /dev/null
+++ b/tools/sign-nand-image.c
@@ -0,0 +1,80 @@
+/*
+ * signGP.c
+ * Read the x-load.bin file and write out the x-load.bin.ift file.
+ * The signed image is the original pre-pended with the size of the image
+ * and the load address. If not entered on command line, file name is
+ * assumed to be x-load.bin in current directory and load address is
+ * 0x40200800. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <malloc.h>
+
+#define SIGNATURE (('S' << 24) | ('g' << 16) | ('n' << 8) | 'P')
+
+int main(int argc, char *argv[])
+{
+ int i;
+ size_t ret;
+ char ifname[FILENAME_MAX], ofname[FILENAME_MAX], ch;
+ FILE *ifile, *ofile;
+ unsigned long loadaddr, len;
+ struct stat sinfo;
+ unsigned long signature = SIGNATURE;
+
+ /* Default to x-load.bin and 0x40200800. */
+ strcpy(ifname, "x-load.bin");
+ loadaddr = 0x40200800;
+
+ if ((argc == 2) || (argc == 3))
+ strcpy(ifname, argv[1]);
+
+ if (argc == 3)
+ loadaddr = strtoul(argv[2], NULL, 16);
+
+ /* Form the output file name. */
+ strcpy(ofname, ifname);
+ strcat(ofname, ".ift");
+
+ /* Open the input file. */
+ ifile = fopen(ifname, "rb");
+ if (ifile == NULL) {
+ printf("Cannot open %s\n", ifname);
+ exit(0);
+ }
+ /* Get file length. */
+ stat(ifname, &sinfo);
+ len = sinfo.st_size;
+
+ /* Open the output file and write it. */
+ ofile = fopen(ofname, "wb");
+ if (ofile == NULL) {
+ printf("Cannot open %s\n", ofname);
+ fclose(ifile);
+ exit(0);
+ }
+ /* Pad 1 sector of zeroes.
+ * ch = 0x00;
+ * for (i=0; i<0x200; i++)
+ * fwrite(&ch, 1, 1, ofile); */
+
+ fwrite(&signature, 1, 4, ofile);
+ fwrite(&len, 1, 4, ofile);
+ fwrite(&loadaddr, 1, 4, ofile);
+ for (i = 0; i < len; i++) {
+ ret = fread(&ch, 1, 1, ifile);
+ if (ret != 1) {
+ fprintf(stderr, "fread didn't return 1!\n");
+ exit(-1);
+ }
+ fwrite(&ch, 1, 1, ofile);
+ }
+
+ fclose(ifile);
+ fclose(ofile);
+
+ return 0;
+}