From e1bbb64ec2ca8ddf1dec91ae1e08ef96ee53639a Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Tue, 11 Jan 2011 17:31:17 +0100 Subject: fixed issue with submodules --- uart-loader | 1 - uart-loader/lib/Makefile | 46 +++++ uart-loader/lib/_udivsi3.S | 77 +++++++++ uart-loader/lib/_umodsi3.S | 88 ++++++++++ uart-loader/lib/board.c | 242 ++++++++++++++++++++++++++ uart-loader/lib/div0.c | 30 ++++ uart-loader/lib/ecc_256.c | 329 +++++++++++++++++++++++++++++++++++ uart-loader/lib/ecc_512.c | 420 +++++++++++++++++++++++++++++++++++++++++++++ uart-loader/lib/printf.c | 304 ++++++++++++++++++++++++++++++++ 9 files changed, 1536 insertions(+), 1 deletion(-) delete mode 160000 uart-loader create mode 100644 uart-loader/lib/Makefile create mode 100644 uart-loader/lib/_udivsi3.S create mode 100644 uart-loader/lib/_umodsi3.S create mode 100644 uart-loader/lib/board.c create mode 100644 uart-loader/lib/div0.c create mode 100644 uart-loader/lib/ecc_256.c create mode 100644 uart-loader/lib/ecc_512.c create mode 100644 uart-loader/lib/printf.c (limited to 'uart-loader/lib') diff --git a/uart-loader b/uart-loader deleted file mode 160000 index eb8b047..0000000 --- a/uart-loader +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eb8b047c29a2027fbdd841cd1289fa27ddb22d72 diff --git a/uart-loader/lib/Makefile b/uart-loader/lib/Makefile new file mode 100644 index 0000000..341cd54 --- /dev/null +++ b/uart-loader/lib/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2004 Texas Instruments +# +# (C) Copyright 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 = lib$(ARCH).a + +AOBJS = _udivsi3.o _umodsi3.o + +COBJS = board.o ecc_256.o ecc_512.o printf.o div0.o + +OBJS = $(AOBJS) $(COBJS) + +$(LIB): .depend $(OBJS) + $(AR) crv $@ $(OBJS) + +######################################################################### + +.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c) + $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/uart-loader/lib/_udivsi3.S b/uart-loader/lib/_udivsi3.S new file mode 100644 index 0000000..2cdcd48 --- /dev/null +++ b/uart-loader/lib/_udivsi3.S @@ -0,0 +1,77 @@ +/* # 1 "libgcc1.S" */ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +/* ip .req r12 */ +/* sp .req r13 */ +/* lr .req r14 */ +/* pc .req r15 */ + .text + .globl __udivsi3 + .type __udivsi3 ,function + .align 0 + __udivsi3 : + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + cmp dividend, divisor + bcc Lgot_result +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + subcs dividend, dividend, divisor + orrcs result, result, curbit + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs result, result, curbit, lsr #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs result, result, curbit, lsr #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs result, result, curbit, lsr #3 + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 +Lgot_result: + mov r0, result + mov pc, lr +Ldiv0: + str lr, [sp, #-4]! + bl __div0 (PLT) + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc} + .size __udivsi3 , . - __udivsi3 +/* # 235 "libgcc1.S" */ +/* # 320 "libgcc1.S" */ +/* # 421 "libgcc1.S" */ +/* # 433 "libgcc1.S" */ +/* # 456 "libgcc1.S" */ +/* # 500 "libgcc1.S" */ +/* # 580 "libgcc1.S" */ diff --git a/uart-loader/lib/_umodsi3.S b/uart-loader/lib/_umodsi3.S new file mode 100644 index 0000000..e4aebe8 --- /dev/null +++ b/uart-loader/lib/_umodsi3.S @@ -0,0 +1,88 @@ +/* # 1 "libgcc1.S" */ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) +/* # 145 "libgcc1.S" */ +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +/* ip .req r12 */ +/* sp .req r13 */ +/* lr .req r14 */ +/* pc .req r15 */ + .text + .globl __umodsi3 + .type __umodsi3 ,function + .align 0 + __umodsi3 : + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + movcc pc, lr +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc Loop1 +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc Lbignum +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + subcs dividend, dividend, divisor + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs overdone, overdone, curbit, ror #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs overdone, overdone, curbit, ror #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs overdone, overdone, curbit, ror #3 + mov ip, curbit + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne Loop3 + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + ands overdone, overdone, #0xe0000000 + moveq pc, lr @ No fixups needed + tst overdone, ip, ror #3 + addne dividend, dividend, divisor, lsr #3 + tst overdone, ip, ror #2 + addne dividend, dividend, divisor, lsr #2 + tst overdone, ip, ror #1 + addne dividend, dividend, divisor, lsr #1 + mov pc, lr +Ldiv0: + str lr, [sp, #-4]! + bl __div0 (PLT) + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc} + .size __umodsi3 , . - __umodsi3 +/* # 320 "libgcc1.S" */ +/* # 421 "libgcc1.S" */ +/* # 433 "libgcc1.S" */ +/* # 456 "libgcc1.S" */ +/* # 500 "libgcc1.S" */ +/* # 580 "libgcc1.S" */ diff --git a/uart-loader/lib/board.c b/uart-loader/lib/board.c new file mode 100644 index 0000000..535f7eb --- /dev/null +++ b/uart-loader/lib/board.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2005 Texas Instruments. + * + * (C) Copyright 2004 + * Jian Zhang, Texas Instruments, jzhang@ti.com. + * + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * 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 +#include +#include +#include + +#ifdef CFG_PRINTF +int print_info(void) +{ + printf ("\n\nTexas Instruments X-Loader 1.41 (" + __DATE__ " - " __TIME__ ")\n"); + return 0; +} +#endif +typedef int (init_fnc_t) (void); + +init_fnc_t *init_sequence[] = { + cpu_init, /* basic cpu dependent setup */ + board_init, /* basic board dependent setup */ +#ifdef CFG_PRINTF + serial_init, /* serial communications setup */ + print_info, +#endif + nand_init, /* board specific nand init */ + NULL, +}; + +#ifdef CFG_CMD_FAT +extern char * strcpy(char * dest,const char *src); +#else +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + return tmp; +} +#endif + +#ifdef CONFIG_MMC +int mmc_read_bootloader(int dev, int part) +{ + long size; + unsigned long offset = CFG_LOADADDR; + block_dev_desc_t *dev_desc = NULL; + unsigned char ret = 0; + + ret = mmc_init(dev); + if (ret != 0){ + printf("\n MMC init failed \n"); + return -1; + } + + if (part) { /* FAT Read for extenal SD card */ + dev_desc = mmc_get_dev(dev); + size = file_fat_read("u-boot.bin", (unsigned char *)offset, 0); + if (size == -1) + return -1; + } else { /* RAW read for EMMC */ + ret = mmc_read(dev, 0x400, (unsigned char *)offset, 0x60000); + if (ret != 1) + return -1; + } + + return 0; +} +#endif + +extern int do_load_serial_bin(ulong offset, int baudrate); +extern int do_comand_line(void); + +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + +void start_armboot (void) +{ + init_fnc_t **init_fnc_ptr; + int i; + uchar *buf; + char boot_dev_name[8]; + u32 boot_device = 0; + + for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { + if ((*init_fnc_ptr)() != 0) { + hang (); + } + } +#ifdef START_LOADB_DOWNLOAD + strcpy(boot_dev_name, "UART"); + do_load_serial_bin (CFG_LOADADDR, 115200); + do_comand_line(); +#else // START_LOADB_DOWNLOAD + /* Read boot device from saved scratch pad */ + boot_device = __raw_readl(0x480029c0) & 0xff; + buf = (uchar*) CFG_LOADADDR; + + switch(boot_device) { + case 0x03: + strcpy(boot_dev_name, "ONENAND"); +#if defined(CFG_ONENAND) + for (i = ONENAND_START_BLOCK; i < ONENAND_END_BLOCK; i++) { + if (!onenand_read_block(buf, i)) + buf += ONENAND_BLOCK_SIZE; + else + goto error; + } +#endif + break; + case 0x02: + default: + strcpy(boot_dev_name, "NAND"); +#if defined(CFG_NAND) + for (i = NAND_UBOOT_START; i < NAND_UBOOT_END; + i+= NAND_BLOCK_SIZE) { + if (!nand_read_block(buf, i)) + buf += NAND_BLOCK_SIZE; /* advance buf ptr */ + } +#endif + break; + case 0x05: + strcpy(boot_dev_name, "EMMC"); +#if defined(CONFIG_MMC) + if (mmc_read_bootloader(1, 0) != 0) + goto error; +#else + goto error; +#endif + break; + case 0x06: + strcpy(boot_dev_name, "MMC/SD1"); +#if defined(CONFIG_MMC) && defined(CFG_CMD_FAT) + if (mmc_read_bootloader(0, 1) != 0) + goto error; +#else + goto error; +#endif + break; + }; +#endif // START_LOADB_DOWNLOAD + /* go run U-Boot and never return */ +// printf("Address of serial_printf = %08x\n", &serial_printf); + printf("Starting OS Bootloader from %s ...\n", boot_dev_name); + ((init_fnc_t *)CFG_LOADADDR)(); + + /* should never come here */ +#if defined(CFG_ONENAND) || defined(CONFIG_MMC) +error: +#endif + printf("Could not load or run bootloader!\n"); + hang(); +} + +#if 0 +#include + + +/******************************************************* + * Routine: delay + * Description: spinning delay to use before udelay works + ******************************************************/ +static inline void delay(unsigned long loops) +{ + __asm__ volatile ("1:\n" "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0"(loops)); +} +static inline void udelay(unsigned long us) +{ + delay(us * 200); /* approximate */ +} + +#define __raw_readl(a) (*(volatile unsigned int *)(a)) +#define __raw_writel(v,a) (*(volatile unsigned int *)(a) = (v)) +#define __raw_readw(a) (*(volatile unsigned short *)(a)) +#define __raw_writew(v,a) (*(volatile unsigned short *)(a) = (v)) + +#define MUX_VAL(OFFSET,VALUE)\ +__raw_writew((VALUE), OMAP34XX_CTRL_BASE + (OFFSET)); + +#define CP(x) (CONTROL_PADCONF_##x) + +void hang (void) +{ + /* call board specific hang function */ + board_hang(); + + /* if board_hang() returns, hange here */ + printf("X-Loader hangs\n"); + + for(;;) { + MUX_VAL(CP(GPMC_nCS6), (IEN | PTD | EN | M4)) /*GPT_PWM11/GPIO57*/ + udelay(500*1000); + MUX_VAL(CP(GPMC_nCS6), (IEN | PTU | EN | M4)) /*GPT_PWM11/GPIO57*/ + udelay(500*1000); + } +} + +#else + +void hang (void) +{ + /* call board specific hang function */ + board_hang(); + + /* if board_hang() returns, hange here */ + printf("X-Loader hangs\n"); + + for(;;) + ; +} + +#endif diff --git a/uart-loader/lib/div0.c b/uart-loader/lib/div0.c new file mode 100644 index 0000000..6267bf1 --- /dev/null +++ b/uart-loader/lib/div0.c @@ -0,0 +1,30 @@ +/* + * (C) Copyright 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 + */ + +/* Replacement (=dummy) for GNU/Linux division-by zero handler */ +void __div0 (void) +{ + extern void hang (void); + + hang(); +} diff --git a/uart-loader/lib/ecc_256.c b/uart-loader/lib/ecc_256.c new file mode 100644 index 0000000..92c310f --- /dev/null +++ b/uart-loader/lib/ecc_256.c @@ -0,0 +1,329 @@ +/* + * (C) Copyright 2000 Texas Instruments + * + * This file os based on the following u-boot file: + * common/cmd_nand.c + * + * 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 + +#ifndef CFG_SW_ECC_512 + +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + + +#ifdef NAND_LEGACY +/* + * Creates non-inverted ECC code from line parity + */ +static void nand_trans_result(u_char reg2, u_char reg3, + u_char *ecc_code) +{ + u_char a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[0] = tmp1; + ecc_code[1] = tmp2; +} + +/* + * Calculate 3 byte ECC code for 256 byte block + */ +/* ECC Calculation is different between NAND and NAND Legacy code + * in U-Boot. If NAND_LEGACY is enabled in u-boot it should be + * enabled in the config file in x-loader also + */ +void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) +{ + u_char idx, reg1, reg3; + int j; + + /* Initialize variables */ + reg1 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; + + /* Build up column parity */ + for(j = 0; j < 256; j++) { + + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[dat[j]]; + reg1 ^= idx; + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (u_char) j; + + } + } + + /* Create non-inverted ECC code from line parity */ + nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code); + + /* Calculate final ECC code */ + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; + ecc_code[2] = ((~reg1) << 2) | 0x03; +} + +/* + * Detect and correct a 1 bit error for 256 byte block + */ +int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + u_char a, b, c, d1, d2, d3, add, bit, i; + + /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; + + if ((d1 | d2 | d3) == 0) { + /* No errors */ + return 0; + } + else { + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; + + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; + add = 0; + a = 0x80; + for (i=0; i<4; i++) { + if (d1 & c) + add |= a; + c >>= 2; + a >>= 1; + } + c = 0x80; + for (i=0; i<4; i++) { + if (d2 & c) + add |= a; + c >>= 2; + a >>= 1; + } + bit = 0; + b = 0x04; + c = 0x80; + for (i=0; i<3; i++) { + if (d3 & c) + bit |= b; + c >>= 2; + b >>= 1; + } + b = 0x01; + a = dat[add]; + a ^= (b << bit); + dat[add] = a; + return 1; + } + else { + i = 0; + while (d1) { + if (d1 & 0x01) + ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 0x01) + ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 0x01) + ++i; + d3 >>= 1; + } + if (i == 1) { + /* ECC Code Error Correction */ + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + else { + /* Uncorrectable Error */ + return -1; + } + } + } + + /* Should never happen */ + return -1; +} +#else /* not NAND_LEGACY */ +void nand_calculate_ecc(const u_char *dat, u_char *ecc_code) +{ + uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; + int i; + + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; + + /* Build up column parity */ + for(i = 0; i < 256; i++) { + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[*dat++]; + reg1 ^= (idx & 0x3f); + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (uint8_t) i; + reg2 ^= ~((uint8_t) i); + } + } + + /* Create non-inverted ECC code from line parity */ + tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ + tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ + tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ + tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ + tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ + tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ + tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ + tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ + + tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ + tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ + tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ + tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ + tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ + tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ + tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ + tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + + /* Calculate final ECC code */ + ecc_code[0] = ~tmp1; + ecc_code[1] = ~tmp2; + ecc_code[2] = ((~reg1) << 2) | 0x03; +} + +static inline int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + +/* + * nand_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd: MTD block structure + * @dat: raw data read from the chip + * @read_ecc: ECC from the chip + * @calc_ecc: the ECC calculated from raw data + * + * Detect and correct a 1 bit error for 256 byte block + */ +int nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + uint8_t s0, s1, s2; + + s0 = calc_ecc[0] ^ read_ecc[0]; + s1 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; + + if ((s0 | s1 | s2) == 0) + return 0; + +/* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + + uint32_t byteoffs, bitnum; + + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; + + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; + } + + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -1; +} +#endif /* NAND_LEGACY */ +#endif /* ! CFG_SW_ECC_512 */ diff --git a/uart-loader/lib/ecc_512.c b/uart-loader/lib/ecc_512.c new file mode 100644 index 0000000..29647c6 --- /dev/null +++ b/uart-loader/lib/ecc_512.c @@ -0,0 +1,420 @@ +/* + * (C) Copyright 2000 Texas Instruments + * + * This file os based on the following u-boot file: + * common/cmd_nand.c + * + * 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 + +#ifdef CFG_SW_ECC_512 + +/* + * invparity is a 256 byte table that contains the odd parity + * for each byte. So if the number of bits in a byte is even, + * the array element is 1, and when the number of bits is odd + * the array eleemnt is 0. + */ +static const char invparity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +/* + * bitsperbyte contains the number of bits per byte + * this is only used for testing and repairing parity + * (a precalculated value slightly improves performance) + */ +static const char bitsperbyte[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +/* + * addressbits is a lookup table to filter out the bits from the xor-ed + * ecc data that identify the faulty location. + * this is only used for repairing parity + * see the comments in nand_correct_data for more details + */ +static const char addressbits[256] = { + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f +}; + +/* + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte + * block + * @mtd: MTD block structure + * @buf: input buffer with raw data + * @code: output buffer with ECC + */ +void nand_calculate_ecc(const u_char *buf, u_char *code) +{ + int i; + const uint32_t *bp = (uint32_t *)buf; + /* 256 or 512 bytes/ecc */ + int eccsize = 512; + const uint32_t eccsize_mult = eccsize >> 8; + uint32_t cur; /* current value in buffer */ + /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ + uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; + uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; + uint32_t rp17 = 0; + uint32_t par; /* the cumulative parity for all data */ + uint32_t tmppar; /* the cumulative parity for this iteration; + for rp12, rp14 and rp16 at the end of the + loop */ + par = 0; + rp4 = 0; + rp6 = 0; + rp8 = 0; + rp10 = 0; + rp12 = 0; + rp14 = 0; + rp16 = 0; + + /* + * The loop is unrolled a number of times; + * This avoids if statements to decide on which rp value to update + * Also we process the data by longwords. + * Note: passing unaligned data might give a performance penalty. + * It is assumed that the buffers are aligned. + * tmppar is the cumulative sum of this iteration. + * needed for calculating rp12, rp14, rp16 and par + * also used as a performance improvement for rp6, rp8 and rp10 + */ + for (i = 0; i < eccsize_mult << 2; i++) { + cur = *bp++; + tmppar = cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= tmppar; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp8 ^= tmppar; + + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp10 ^= tmppar; + + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp8 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp8 ^= cur; + + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp6 ^= cur; + cur = *bp++; + tmppar ^= cur; + rp4 ^= cur; + cur = *bp++; + tmppar ^= cur; + + par ^= tmppar; + if ((i & 0x1) == 0) + rp12 ^= tmppar; + if ((i & 0x2) == 0) + rp14 ^= tmppar; + if (eccsize_mult == 2 && (i & 0x4) == 0) + rp16 ^= tmppar; + } + + /* + * handle the fact that we use longword operations + * we'll bring rp4..rp14..rp16 back to single byte entities by + * shifting and xoring first fold the upper and lower 16 bits, + * then the upper and lower 8 bits. + */ + rp4 ^= (rp4 >> 16); + rp4 ^= (rp4 >> 8); + rp4 &= 0xff; + rp6 ^= (rp6 >> 16); + rp6 ^= (rp6 >> 8); + rp6 &= 0xff; + rp8 ^= (rp8 >> 16); + rp8 ^= (rp8 >> 8); + rp8 &= 0xff; + rp10 ^= (rp10 >> 16); + rp10 ^= (rp10 >> 8); + rp10 &= 0xff; + rp12 ^= (rp12 >> 16); + rp12 ^= (rp12 >> 8); + rp12 &= 0xff; + rp14 ^= (rp14 >> 16); + rp14 ^= (rp14 >> 8); + rp14 &= 0xff; + if (eccsize_mult == 2) { + rp16 ^= (rp16 >> 16); + rp16 ^= (rp16 >> 8); + rp16 &= 0xff; + } + + /* + * we also need to calculate the row parity for rp0..rp3 + * This is present in par, because par is now + * rp3 rp3 rp2 rp2 in little endian and + * rp2 rp2 rp3 rp3 in big endian + * as well as + * rp1 rp0 rp1 rp0 in little endian and + * rp0 rp1 rp0 rp1 in big endian + * First calculate rp2 and rp3 + */ + rp3 = (par >> 16); + rp3 ^= (rp3 >> 8); + rp3 &= 0xff; + rp2 = par & 0xffff; + rp2 ^= (rp2 >> 8); + rp2 &= 0xff; + + /* reduce par to 16 bits then calculate rp1 and rp0 */ + par ^= (par >> 16); + rp1 = (par >> 8) & 0xff; + rp0 = (par & 0xff); + + /* finally reduce par to 8 bits */ + par ^= (par >> 8); + par &= 0xff; + + /* + * and calculate rp5..rp15..rp17 + * note that par = rp4 ^ rp5 and due to the commutative property + * of the ^ operator we can say: + * rp5 = (par ^ rp4); + * The & 0xff seems superfluous, but benchmarking learned that + * leaving it out gives slightly worse results. No idea why, probably + * it has to do with the way the pipeline in pentium is organized. + */ + rp5 = (par ^ rp4) & 0xff; + rp7 = (par ^ rp6) & 0xff; + rp9 = (par ^ rp8) & 0xff; + rp11 = (par ^ rp10) & 0xff; + rp13 = (par ^ rp12) & 0xff; + rp15 = (par ^ rp14) & 0xff; + if (eccsize_mult == 2) + rp17 = (par ^ rp16) & 0xff; + + /* + * Finally calculate the ecc bits. + * Again here it might seem that there are performance optimisations + * possible, but benchmarks showed that on the system this is developed + * the code below is the fastest + */ + code[1] = + (invparity[rp7] << 7) | + (invparity[rp6] << 6) | + (invparity[rp5] << 5) | + (invparity[rp4] << 4) | + (invparity[rp3] << 3) | + (invparity[rp2] << 2) | + (invparity[rp1] << 1) | + (invparity[rp0]); + code[0] = + (invparity[rp15] << 7) | + (invparity[rp14] << 6) | + (invparity[rp13] << 5) | + (invparity[rp12] << 4) | + (invparity[rp11] << 3) | + (invparity[rp10] << 2) | + (invparity[rp9] << 1) | + (invparity[rp8]); + if (eccsize_mult == 1) + code[2] = + (invparity[par & 0xf0] << 7) | + (invparity[par & 0x0f] << 6) | + (invparity[par & 0xcc] << 5) | + (invparity[par & 0x33] << 4) | + (invparity[par & 0xaa] << 3) | + (invparity[par & 0x55] << 2) | + 3; + else + code[2] = + (invparity[par & 0xf0] << 7) | + (invparity[par & 0x0f] << 6) | + (invparity[par & 0xcc] << 5) | + (invparity[par & 0x33] << 4) | + (invparity[par & 0xaa] << 3) | + (invparity[par & 0x55] << 2) | + (invparity[rp17] << 1) | + (invparity[rp16] << 0); +} + +/** + * nand_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 a 1 bit error for 256/512 byte block + */ +int nand_correct_data(unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc) +{ + unsigned char b0, b1, b2; + uint32_t byte_addr; + unsigned char bit_addr; + /* 256 or 512 bytes/ecc */ + int eccsize = 512; + const uint32_t eccsize_mult = eccsize >> 8; + /* + * b0 to b2 indicate which bit is faulty (if any) + * we might need the xor result more than once, + * so keep them in a local var + */ + b0 = read_ecc[1] ^ calc_ecc[1]; + b1 = read_ecc[0] ^ calc_ecc[0]; + b2 = read_ecc[2] ^ calc_ecc[2]; + + /* check if there are any bitfaults */ + + /* repeated if statements are slightly more efficient than switch ... */ + /* ordered in order of likelihood */ + + if ((b0 | b1 | b2) == 0) + return 0; /* no error */ + + if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && + (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && + ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) || + (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) { + /* single bit error */ + /* + * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty + * byte, cp 5/3/1 indicate the faulty bit. + * A lookup table (called addressbits) is used to filter + * the bits from the byte they are in. + * A marginal optimisation is possible by having three + * different lookup tables. + * One as we have now (for b0), one for b2 + * (that would avoid the >> 1), and one for b1 (with all values + * << 4). However it was felt that introducing two more tables + * hardly justify the gain. + * + * The b2 shift is there to get rid of the lowest two bits. + * We could also do addressbits[b2] >> 1 but for the + * performace it does not make any difference + */ + if (eccsize_mult == 1) + byte_addr = (addressbits[b1] << 4) + addressbits[b0]; + else + byte_addr = (addressbits[b2 & 0x3] << 8) + + (addressbits[b1] << 4) + addressbits[b0]; + bit_addr = addressbits[b2 >> 2]; + /* flip the bit */ + buf[byte_addr] ^= (1 << bit_addr); + return 1; + + } + /* count nr of bits; use table lookup, faster than calculating it */ + if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) + return 1; /* error in ecc data; no action needed */ + + return -1; +} +#endif /* CFG_SW_ECC_512 */ diff --git a/uart-loader/lib/printf.c b/uart-loader/lib/printf.c new file mode 100644 index 0000000..91d22fc --- /dev/null +++ b/uart-loader/lib/printf.c @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2004 Texas Instruments + * + * Based on the following file: + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include + +#ifdef CFG_PRINTF + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + + +static int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +void serial_printf (const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[CFG_PBSIZE]; + + va_start (args, fmt); + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsprintf (printbuffer, fmt, args); + va_end (args); + + /* Print the string */ + serial_puts (printbuffer); +} +#endif -- cgit v1.1