4-bit ECC support for Marvell Kirkwood SOC
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 12 May 2009 17:29:16 +0000 (17:29 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Tue, 12 May 2009 17:29:16 +0000 (17:29 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@1768 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/flash/Makefile.am
src/flash/nand.c
src/flash/nand.h
src/flash/nand_ecc_kw.c [new file with mode: 0644]
src/target/board/sheevaplug.cfg

index 7895edc85af55127ad43c7749f7f539c4efb06ad..e5b76cb61b24352d8a1e957027281eff43636808 100644 (file)
@@ -7,7 +7,7 @@ METASOURCES = AUTO
 noinst_LTLIBRARIES = libflash.la
 libflash_la_SOURCES = \
        flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c \
 noinst_LTLIBRARIES = libflash.la
 libflash_la_SOURCES = \
        flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c \
-       str7x.c str9x.c aduc702x.c nand.c nand_ecc.c \
+       str7x.c str9x.c aduc702x.c nand.c nand_ecc.c nand_ecc_kw.c \
        lpc3180_nand_controller.c stellaris.c str9xpec.c stm32x.c tms470.c \
        ecos.c orion_nand.c s3c24xx_nand.c s3c2410_nand.c s3c2412_nand.c \
        s3c2440_nand.c s3c2443_nand.c lpc288x.c ocl.c mflash.c pic32mx.c avrf.c
        lpc3180_nand_controller.c stellaris.c str9xpec.c stm32x.c tms470.c \
        ecos.c orion_nand.c s3c24xx_nand.c s3c2410_nand.c s3c2412_nand.c \
        s3c2440_nand.c s3c2443_nand.c lpc288x.c ocl.c mflash.c pic32mx.c avrf.c
index 8efed037c6073153fea0a4edf8ab0ee8340b8fbe..057feb7d94b750aeead179ae067102bf9d10c459 100644 (file)
@@ -1332,6 +1332,8 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
                                        oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
                                else if (!strcmp(args[i], "oob_softecc"))
                                        oob_format |= NAND_OOB_SW_ECC;
                                        oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
                                else if (!strcmp(args[i], "oob_softecc"))
                                        oob_format |= NAND_OOB_SW_ECC;
+                               else if (!strcmp(args[i], "oob_softecc_kw"))
+                                       oob_format |= NAND_OOB_SW_ECC_KW;
                                else
                                {
                                        command_print(cmd_ctx, "unknown option: %s", args[i]);
                                else
                                {
                                        command_print(cmd_ctx, "unknown option: %s", args[i]);
@@ -1355,7 +1357,7 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
                        page = malloc(p->page_size);
                }
 
                        page = malloc(p->page_size);
                }
 
-               if (oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC))
+               if (oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
                {
                        if (p->page_size == 512) {
                                oob_size = 16;
                {
                        if (p->page_size == 512) {
                                oob_size = 16;
@@ -1401,6 +1403,21 @@ static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cm
                                        oob[eccpos[j++]] = ecc[1];
                                        oob[eccpos[j++]] = ecc[2];
                                }
                                        oob[eccpos[j++]] = ecc[1];
                                        oob[eccpos[j++]] = ecc[2];
                                }
+                       } else if (oob_format & NAND_OOB_SW_ECC_KW)
+                       {
+                               /*
+                                * In this case eccpos is not used as
+                                * the ECC data is always stored contigously
+                                * at the end of the OOB area.  It consists
+                                * of 10 bytes per 512-byte data block.
+                                */
+                               u32 i;
+                               u8 *ecc = oob + oob_size - page_size/512 * 10;
+                               memset(oob, 0xff, oob_size);
+                               for (i = 0; i < page_size; i += 512) {
+                                       nand_calculate_ecc_kw(p, page+i, ecc);
+                                       ecc += 10;
+                               }
                        }
                        else if (NULL != oob)
                        {
                        }
                        else if (NULL != oob)
                        {
index bd9554c344c4e8ac027189858c9a08792866d588..b3c6b6b566debc523877f95b58c23b54df7a4f94 100644 (file)
@@ -200,6 +200,7 @@ enum oob_formats
        NAND_OOB_ONLY = 0x2,    /* only OOB data */
        NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ 
        NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
        NAND_OOB_ONLY = 0x2,    /* only OOB data */
        NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ 
        NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
+       NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */
        NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
        NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
 };
        NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
        NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
 };
@@ -210,6 +211,7 @@ extern int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data,
 extern int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
 extern int nand_read_status(struct nand_device_s *device, u8 *status);
 extern int nand_calculate_ecc(struct nand_device_s *device, const u8 *dat, u8 *ecc_code);
 extern int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
 extern int nand_read_status(struct nand_device_s *device, u8 *status);
 extern int nand_calculate_ecc(struct nand_device_s *device, const u8 *dat, u8 *ecc_code);
+extern int nand_calculate_ecc_kw(struct nand_device_s *device, const u8 *dat, u8 *ecc_code);
 
 extern int nand_register_commands(struct command_context_s *cmd_ctx);
 extern int nand_init(struct command_context_s *cmd_ctx);
 
 extern int nand_register_commands(struct command_context_s *cmd_ctx);
 extern int nand_init(struct command_context_s *cmd_ctx);
diff --git a/src/flash/nand_ecc_kw.c b/src/flash/nand_ecc_kw.c
new file mode 100644 (file)
index 0000000..ecc7adc
--- /dev/null
@@ -0,0 +1,174 @@
+/*\r
+ * Reed-Solomon ECC handling for the Marvell Kirkwood SOC\r
+ * Copyright (C) 2009 Marvell Semiconductor, Inc.\r
+ *\r
+ * Authors: Lennert Buytenhek <buytenh@wantstofly.org>\r
+ *          Nicolas Pitre <nico@cam.org>\r
+ *\r
+ * This file is free software; you can redistribute it and/or modify it\r
+ * under the terms of the GNU General Public License as published by the\r
+ * Free Software Foundation; either version 2 or (at your option) any\r
+ * later version.\r
+ *\r
+ * This file is distributed in the hope that it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
+ * for more details.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include <sys/types.h>\r
+#include "nand.h"\r
+\r
+\r
+/*****************************************************************************\r
+ * Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1.\r
+ *\r
+ * For multiplication, a discrete log/exponent table is used, with\r
+ * primitive element x (F is a primitive field, so x is primitive).\r
+ */\r
+#define MODPOLY                0x409           /* x^10 + x^3 + 1 in binary */\r
+\r
+/*\r
+ * Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in\r
+ * GF(2^10) mod x^10 + x^3 + 1 such that b = x ^ a.  There's two\r
+ * identical copies of this array back-to-back so that we can save\r
+ * the mod 1023 operation when doing a GF multiplication.\r
+ */\r
+static uint16_t gf_exp[1023 + 1023];\r
+\r
+/*\r
+ * Maps a polynomial b in GF(2^10) mod x^10 + x^3 + 1 to an index\r
+ * a = gf_log[b] in [0..1022] such that b = x ^ a.\r
+ */\r
+static uint16_t gf_log[1024];\r
+\r
+static void gf_build_log_exp_table(void)\r
+{\r
+       int i;\r
+       int p_i;\r
+\r
+       /*\r
+        * p_i = x ^ i\r
+        *\r
+        * Initialise to 1 for i = 0.\r
+        */\r
+       p_i = 1;\r
+\r
+       for (i = 0; i < 1023; i++) {\r
+               gf_exp[i] = p_i;\r
+               gf_exp[i + 1023] = p_i;\r
+               gf_log[p_i] = i;\r
+\r
+               /*\r
+                * p_i = p_i * x\r
+                */\r
+               p_i <<= 1;\r
+               if (p_i & (1 << 10))\r
+                       p_i ^= MODPOLY;\r
+       }\r
+}\r
+\r
+\r
+/*****************************************************************************\r
+ * Reed-Solomon code\r
+ *\r
+ * This implements a (1023,1015) Reed-Solomon ECC code over GF(2^10)\r
+ * mod x^10 + x^3 + 1, shortened to (520,512).  The ECC data consists\r
+ * of 8 10-bit symbols, or 10 8-bit bytes.\r
+ *\r
+ * Given 512 bytes of data, computes 10 bytes of ECC.\r
+ *\r
+ * This is done by converting the 512 bytes to 512 10-bit symbols\r
+ * (elements of F), interpreting those symbols as a polynomial in F[X]\r
+ * by taking symbol 0 as the coefficient of X^8 and symbol 511 as the\r
+ * coefficient of X^519, and calculating the residue of that polynomial\r
+ * divided by the generator polynomial, which gives us the 8 ECC symbols\r
+ * as the remainder.  Finally, we convert the 8 10-bit ECC symbols to 10\r
+ * 8-bit bytes.\r
+ *\r
+ * The generator polynomial is hardcoded, as that is faster, but it\r
+ * can be computed by taking the primitive element a = x (in F), and\r
+ * constructing a polynomial in F[X] with roots a, a^2, a^3, ..., a^8\r
+ * by multiplying the minimal polynomials for those roots (which are\r
+ * just 'x - a^i' for each i).\r
+ *\r
+ * Note: due to unfortunate circumstances, the bootrom in the Kirkwood SOC\r
+ * expects the ECC to be computed backward, i.e. from the last byte down\r
+ * to the first one.\r
+ */\r
+int nand_calculate_ecc_kw(struct nand_device_s *device, const u8 *data, u8 *ecc)\r
+{\r
+       unsigned int r7, r6, r5, r4, r3, r2, r1, r0;\r
+       int i;\r
+       static int tables_initialized = 0;\r
+\r
+       if (!tables_initialized) {\r
+               gf_build_log_exp_table();\r
+               tables_initialized = 1;\r
+       }\r
+\r
+       /*\r
+        * Load bytes 504..511 of the data into r.\r
+        */\r
+       r0 = data[504];\r
+       r1 = data[505];\r
+       r2 = data[506];\r
+       r3 = data[507];\r
+       r4 = data[508];\r
+       r5 = data[509];\r
+       r6 = data[510];\r
+       r7 = data[511];\r
+\r
+\r
+       /*\r
+        * Shift bytes 503..0 (in that order) into r0, followed\r
+        * by eight zero bytes, while reducing the polynomial by the\r
+        * generator polynomial in every step.\r
+        */\r
+       for (i = 503; i >= -8; i--) {\r
+               unsigned int d;\r
+\r
+               d = 0;\r
+               if (i >= 0)\r
+                       d = data[i];\r
+\r
+               if (r7) {\r
+                       u16 *t = gf_exp + gf_log[r7];\r
+\r
+                       r7 = r6 ^ t[0x21c];\r
+                       r6 = r5 ^ t[0x181];\r
+                       r5 = r4 ^ t[0x18e];\r
+                       r4 = r3 ^ t[0x25f];\r
+                       r3 = r2 ^ t[0x197];\r
+                       r2 = r1 ^ t[0x193];\r
+                       r1 = r0 ^ t[0x237];\r
+                       r0 = d  ^ t[0x024];\r
+               } else {\r
+                       r7 = r6;\r
+                       r6 = r5;\r
+                       r5 = r4;\r
+                       r4 = r3;\r
+                       r3 = r2;\r
+                       r2 = r1;\r
+                       r1 = r0;\r
+                       r0 = d;\r
+               }\r
+       }\r
+\r
+       ecc[0] = r0;\r
+       ecc[1] = (r0 >> 8) | (r1 << 2);\r
+       ecc[2] = (r1 >> 6) | (r2 << 4);\r
+       ecc[3] = (r2 >> 4) | (r3 << 6);\r
+       ecc[4] = (r3 >> 2);\r
+       ecc[5] = r4;\r
+       ecc[6] = (r4 >> 8) | (r5 << 2);\r
+       ecc[7] = (r5 >> 6) | (r6 << 4);\r
+       ecc[8] = (r6 >> 4) | (r7 << 6);\r
+       ecc[9] = (r7 >> 2);\r
+\r
+       return 0;\r
+}\r
index 64e259678624b05225db7c40facb0a70f24c7cf3..276d6f2462023acf97acbf5a289c19806105399b 100644 (file)
@@ -99,7 +99,7 @@ proc sheevaplug_reflash_uboot { } {
        sheevaplug_init
        nand probe 0
        nand erase 0 0 4
        sheevaplug_init
        nand probe 0
        nand erase 0 0 4
-       nand write 0 uboot.bin 0 oob_softecc
+       nand write 0 uboot.bin 0 oob_softecc_kw
        resume
 
 }
        resume
 
 }
@@ -108,7 +108,7 @@ proc sheevaplug_load_uboot { } {
 
        # load u-Boot into RAM and execute it
        sheevaplug_init
 
        # load u-Boot into RAM and execute it
        sheevaplug_init
-       load_image /tmp/uboot.elf
+       load_image uboot.elf
        verify_image uboot.elf
        resume 0x00600000
 
        verify_image uboot.elf
        resume 0x00600000
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)