]> git.sur5r.net Git - openocd/blobdiff - src/flash/davinci_nand.c
Merge branch 'master' of ssh://dbrownell@openocd.git.sourceforge.net/gitroot/openocd...
[openocd] / src / flash / davinci_nand.c
index 7500fc757b17eda5fde8cd71809fbf6753774056..b6210b8fdffc623468f37917538556dc1070e3b5 100644 (file)
@@ -28,7 +28,7 @@
 #include "config.h"
 #endif
 
-#include "nand.h"
+#include "arm_nandio.h"
 
 
 enum ecc {
@@ -40,22 +40,25 @@ enum ecc {
 struct davinci_nand {
        target_t        *target;
 
-       u8              chipsel;        /* chipselect 0..3 == CS2..CS5 */
-       u8              eccmode;
+       uint8_t         chipsel;        /* chipselect 0..3 == CS2..CS5 */
+       uint8_t         eccmode;
 
        /* Async EMIF controller base */
-       u32             aemif;
+       uint32_t                aemif;
 
        /* NAND chip addresses */
-       u32             data;           /* without CLE or ALE */
-       u32             cmd;            /* with CLE */
-       u32             addr;           /* with ALE */
+       uint32_t                data;           /* without CLE or ALE */
+       uint32_t                cmd;            /* with CLE */
+       uint32_t                addr;           /* with ALE */
+
+       /* write acceleration */
+       struct arm_nand_data    io;
 
        /* page i/o for the relevant flavor of hardware ECC */
-       int (*read_page)(struct nand_device_s *nand, u32 page,
-                       u8 *data, u32 data_size, u8 *oob, u32 oob_size);
-       int (*write_page)(struct nand_device_s *nand, u32 page,
-                       u8 *data, u32 data_size, u8 *oob, u32 oob_size);
+       int (*read_page)(struct nand_device_s *nand, uint32_t page,
+                       uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
+       int (*write_page)(struct nand_device_s *nand, uint32_t page,
+                       uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
 };
 
 #define NANDFCR                0x60            /* flash control register */
@@ -84,7 +87,7 @@ static int davinci_init(struct nand_device_s *nand)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       u32 nandfcr;
+       uint32_t nandfcr;
 
        if (!halted(target, "init"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -94,7 +97,7 @@ static int davinci_init(struct nand_device_s *nand)
         */
        target_read_u32(target, info->aemif + NANDFCR, &nandfcr);
        if (!(nandfcr & (1 << info->chipsel))) {
-               LOG_ERROR("chip address %08x not NAND-enabled?", info->data);
+               LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data);
                return ERROR_NAND_OPERATION_FAILED;
        }
 
@@ -114,7 +117,7 @@ static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       u32 nandfsr;
+       uint32_t nandfsr;
 
        /* NOTE: return code is zero/error, else success; not ERROR_* */
 
@@ -133,7 +136,7 @@ static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
        return 0;
 }
 
-static int davinci_command(struct nand_device_s *nand, u8 command)
+static int davinci_command(struct nand_device_s *nand, uint8_t command)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
@@ -145,7 +148,7 @@ static int davinci_command(struct nand_device_s *nand, u8 command)
        return ERROR_OK;
 }
 
-static int davinci_address(struct nand_device_s *nand, u8 address)
+static int davinci_address(struct nand_device_s *nand, uint8_t address)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
@@ -157,7 +160,7 @@ static int davinci_address(struct nand_device_s *nand, u8 address)
        return ERROR_OK;
 }
 
-static int davinci_write_data(struct nand_device_s *nand, u16 data)
+static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
@@ -181,15 +184,15 @@ static int davinci_read_data(struct nand_device_s *nand, void *data)
        return ERROR_OK;
 }
 
-/* REVISIT a bit of native code should let block I/O be MUCH faster */
+/* REVISIT a bit of native code should let block reads be MUCH faster */
 
 static int davinci_read_block_data(struct nand_device_s *nand,
-               u8 *data, int data_size)
+               uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       u32 nfdata = info->data;
-       u32 tmp;
+       uint32_t nfdata = info->data;
+       uint32_t tmp;
 
        if (!halted(target, "read_block"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -217,16 +220,23 @@ static int davinci_read_block_data(struct nand_device_s *nand,
 }
 
 static int davinci_write_block_data(struct nand_device_s *nand,
-               u8 *data, int data_size)
+               uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       u32 nfdata = info->data;
-       u32 tmp;
+       uint32_t nfdata = info->data;
+       uint32_t tmp;
+       int status;
 
        if (!halted(target, "write_block"))
                return ERROR_NAND_OPERATION_FAILED;
 
+       /* try the fast way first */
+       status = arm_nandwrite(&info->io, data, data_size);
+       if (status != ERROR_NAND_NO_BUFFER)
+               return status;
+
+       /* else do it slowly */
        while (data_size >= 4) {
                tmp = le_to_h_u32(data);
                target_write_u32(target, nfdata, tmp);
@@ -245,11 +255,11 @@ static int davinci_write_block_data(struct nand_device_s *nand,
        return ERROR_OK;
 }
 
-static int davinci_write_page(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       u8 *ooballoc = NULL;
+       uint8_t *ooballoc = NULL;
        int status;
 
        if (!nand->device)
@@ -285,13 +295,19 @@ static int davinci_write_page(struct nand_device_s *nand, u32 page,
                memset(oob, 0x0ff, oob_size);
        }
 
+       /* REVISIT avoid wasting SRAM:  unless nand->use_raw is set,
+        * use 512 byte chunks.  Read side support will often want
+        * to include oob_size ...
+        */
+       info->io.chunk_size = nand->page_size;
+
        status = info->write_page(nand, page, data, data_size, oob, oob_size);
        free(ooballoc);
        return status;
 }
 
-static int davinci_read_page(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_read_page(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
 
@@ -303,7 +319,7 @@ static int davinci_read_page(struct nand_device_s *nand, u32 page,
        return info->read_page(nand, page, data, data_size, oob, oob_size);
 }
 
-static void davinci_write_pagecmd(struct nand_device_s *nand, u8 cmd, u32 page)
+static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
@@ -327,11 +343,11 @@ static void davinci_write_pagecmd(struct nand_device_s *nand, u8 cmd, u32 page)
 }
 
 static int davinci_writepage_tail(struct nand_device_s *nand,
-               u8 *oob, u32 oob_size)
+               uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       u8 status;
+       uint8_t status;
 
        if (oob_size)
                davinci_write_block_data(nand, oob, oob_size);
@@ -358,15 +374,15 @@ static int davinci_writepage_tail(struct nand_device_s *nand,
 /*
  * All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
  */
-static int davinci_write_page_ecc1(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        unsigned oob_offset;
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       const u32 fcr_addr = info->aemif + NANDFCR;
-       const u32 ecc1_addr = info->aemif + NANDFECC + info->chipsel;
-       u32 fcr, ecc1;
+       const uint32_t fcr_addr = info->aemif + NANDFCR;
+       const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
+       uint32_t fcr, ecc1;
 
        /* Write contiguous ECC bytes starting at specified offset.
         * NOTE: Linux reserves twice as many bytes as we need; and
@@ -409,9 +425,9 @@ static int davinci_write_page_ecc1(struct nand_device_s *nand, u32 page,
                ecc1 = ~ecc1;
 
                /* save correct ECC code into oob data */
-               oob[oob_offset++] = (u8)(ecc1);
-               oob[oob_offset++] = (u8)(ecc1 >> 8);
-               oob[oob_offset++] = (u8)(ecc1 >> 16);
+               oob[oob_offset++] = (uint8_t)(ecc1);
+               oob[oob_offset++] = (uint8_t)(ecc1 >> 8);
+               oob[oob_offset++] = (uint8_t)(ecc1 >> 16);
 
        } while (data_size);
 
@@ -425,20 +441,20 @@ static int davinci_write_page_ecc1(struct nand_device_s *nand, u32 page,
  * is read first, so its ECC data can be used incrementally), but the
  * manufacturer bad block markers are safe.  Contrast:  old "infix" style.
  */
-static int davinci_write_page_ecc4(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
-       static const u8 ecc512[] = {
+       static const uint8_t ecc512[] = {
                0, 1, 2, 3, 4, /* 5== mfr badblock */
                6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15,
        };
-       static const u8 ecc2048[] = {
+       static const uint8_t ecc2048[] = {
                24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
                34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
                44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
                54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
        };
-       static const u8 ecc4096[] = {
+       static const uint8_t ecc4096[] = {
                 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,
                 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
                 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,
@@ -450,11 +466,11 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, u32 page,
        };
 
        struct davinci_nand *info = nand->controller_priv;
-       const u8 *l;
+       const uint8_t *l;
        target_t *target = info->target;
-       const u32 fcr_addr = info->aemif + NANDFCR;
-       const u32 ecc4_addr = info->aemif + NAND4BITECC;
-       u32 fcr, ecc4;
+       const uint32_t fcr_addr = info->aemif + NANDFCR;
+       const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
+       uint32_t fcr, ecc4;
 
        /* Use the same ECC layout Linux uses.  For small page chips
         * it's a bit cramped.
@@ -485,7 +501,7 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, u32 page,
        fcr |= (1 << 12) | (info->chipsel << 4);
 
        do {
-               u32 raw_ecc[4], *p;
+               uint32_t raw_ecc[4], *p;
                int i;
 
                /* start 4bit ecc on csX */
@@ -527,14 +543,14 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, u32 page,
  * older second stage loaders (ABL/U-Boot, etc) or other system software
  * (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
  */
-static int davinci_write_page_ecc4infix(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
        target_t *target = info->target;
-       const u32 fcr_addr = info->aemif + NANDFCR;
-       const u32 ecc4_addr = info->aemif + NAND4BITECC;
-       u32 fcr, ecc4;
+       const uint32_t fcr_addr = info->aemif + NANDFCR;
+       const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
+       uint32_t fcr, ecc4;
 
        davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
 
@@ -546,8 +562,8 @@ static int davinci_write_page_ecc4infix(struct nand_device_s *nand, u32 page,
        fcr |= (1 << 12) | (info->chipsel << 4);
 
        do {
-               u32 raw_ecc[4], *p;
-               u8 *l;
+               uint32_t raw_ecc[4], *p;
+               uint8_t *l;
                int i;
 
                /* start 4bit ecc on csX */
@@ -584,8 +600,8 @@ static int davinci_write_page_ecc4infix(struct nand_device_s *nand, u32 page,
        return davinci_writepage_tail(nand, NULL, 0);
 }
 
-static int davinci_read_page_ecc4infix(struct nand_device_s *nand, u32 page,
-               u8 *data, u32 data_size, u8 *oob, u32 oob_size)
+static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
 
@@ -622,7 +638,6 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
        unsigned long chip, aemif;
        enum ecc eccmode;
        int chipsel;
-       char *ep;
 
        /* arguments:
         *  - "davinci"
@@ -645,8 +660,8 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
                goto fail;
        }
 
-       chip = strtoul(argv[2], &ep, 0);
-       if (*ep || chip == 0 || chip == ULONG_MAX) {
+       COMMAND_PARSE_NUMBER(ulong, argv[2], chip);
+       if (chip == 0) {
                LOG_ERROR("Invalid NAND chip address %s", argv[2]);
                goto fail;
        }
@@ -662,8 +677,8 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
                goto fail;
        }
 
-       aemif = strtoul(argv[4], &ep, 0);
-       if (*ep || chip == 0 || chip == ULONG_MAX) {
+       COMMAND_PARSE_NUMBER(ulong, argv[4], aemif);
+       if (aemif == 0) {
                LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
                goto fail;
        }
@@ -676,11 +691,11 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
                        || aemif == 0x01e10000  /* dm335, dm355 */
                        || aemif == 0x01d10000  /* dm365 */
                        ) {
-               if (chip < 0x0200000 || chip >= 0x0a000000) {
+               if (chip < 0x02000000 || chip >= 0x0a000000) {
                        LOG_ERROR("NAND address %08lx out of range?", chip);
                        goto fail;
                }
-               chipsel = (chip - 0x02000000) >> 21;
+               chipsel = (chip - 0x02000000) >> 25;
        } else {
                LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif);
                goto fail;
@@ -700,6 +715,9 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
 
        nand->controller_priv = info;
 
+       info->io.target = target;
+       info->io.data = info->data;
+
        /* NOTE:  for now we don't do any error correction on read.
         * Nothing else in OpenOCD currently corrects read errors,
         * and in any case it's *writing* that we care most about.