#include "target.h" less wildly
[fw/openocd] / src / flash / davinci_nand.c
index 7ccd080f9092ecb09a1a82d293625ac8e0f3b885..413bcda4683f9d85e53e140ba51aa944d1e1fede 100644 (file)
@@ -28,7 +28,7 @@
 #include "config.h"
 #endif
 
-#include "nand.h"
+#include "arm_nandio.h"
 
 
 enum ecc {
@@ -38,7 +38,7 @@ enum ecc {
 };
 
 struct davinci_nand {
-       target_t        *target;
+       struct target   *target;
 
        uint8_t         chipsel;        /* chipselect 0..3 == CS2..CS5 */
        uint8_t         eccmode;
@@ -51,10 +51,13 @@ struct davinci_nand {
        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, uint32_t page,
+       int (*read_page)(struct nand_device *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,
+       int (*write_page)(struct nand_device *nand, uint32_t page,
                        uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
 };
 
@@ -66,7 +69,7 @@ struct davinci_nand {
 #define NANDERRADDR    0xd0            /* 4-bit ECC err addr, 1st of 2 */
 #define NANDERRVAL     0xd8            /* 4-bit ECC err value, 1st of 2 */
 
-static int halted(target_t *target, const char *label)
+static int halted(struct target *target, const char *label)
 {
        if (target->state == TARGET_HALTED)
                return true;
@@ -75,15 +78,15 @@ static int halted(target_t *target, const char *label)
        return false;
 }
 
-static int davinci_register_commands(struct command_context_s *cmd_ctx)
+static int davinci_register_commands(struct command_context *cmd_ctx)
 {
        return ERROR_OK;
 }
 
-static int davinci_init(struct nand_device_s *nand)
+static int davinci_init(struct nand_device *nand)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        uint32_t nandfcr;
 
        if (!halted(target, "init"))
@@ -105,15 +108,15 @@ static int davinci_init(struct nand_device_s *nand)
        return ERROR_OK;
 }
 
-static int davinci_reset(struct nand_device_s *nand)
+static int davinci_reset(struct nand_device *nand)
 {
        return ERROR_OK;
 }
 
-static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
+static int davinci_nand_ready(struct nand_device *nand, int timeout)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        uint32_t nandfsr;
 
        /* NOTE: return code is zero/error, else success; not ERROR_* */
@@ -133,10 +136,10 @@ static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
        return 0;
 }
 
-static int davinci_command(struct nand_device_s *nand, uint8_t command)
+static int davinci_command(struct nand_device *nand, uint8_t command)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
 
        if (!halted(target, "command"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -145,10 +148,10 @@ static int davinci_command(struct nand_device_s *nand, uint8_t command)
        return ERROR_OK;
 }
 
-static int davinci_address(struct nand_device_s *nand, uint8_t address)
+static int davinci_address(struct nand_device *nand, uint8_t address)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
 
        if (!halted(target, "address"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -157,10 +160,10 @@ static int davinci_address(struct nand_device_s *nand, uint8_t address)
        return ERROR_OK;
 }
 
-static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
+static int davinci_write_data(struct nand_device *nand, uint16_t data)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
 
        if (!halted(target, "write_data"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -169,10 +172,10 @@ static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
        return ERROR_OK;
 }
 
-static int davinci_read_data(struct nand_device_s *nand, void *data)
+static int davinci_read_data(struct nand_device *nand, void *data)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
 
        if (!halted(target, "read_data"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -181,13 +184,13 @@ 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,
+static int davinci_read_block_data(struct nand_device *nand,
                uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        uint32_t nfdata = info->data;
        uint32_t tmp;
 
@@ -216,17 +219,24 @@ static int davinci_read_block_data(struct nand_device_s *nand,
        return ERROR_OK;
 }
 
-static int davinci_write_block_data(struct nand_device_s *nand,
+static int davinci_write_block_data(struct nand_device *nand,
                uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        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,7 +255,7 @@ static int davinci_write_block_data(struct nand_device_s *nand,
        return ERROR_OK;
 }
 
-static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
+static int davinci_write_page(struct nand_device *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;
@@ -285,12 +295,18 @@ static int davinci_write_page(struct nand_device_s *nand, uint32_t 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, uint32_t page,
+static int davinci_read_page(struct nand_device *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,10 +319,10 @@ static int davinci_read_page(struct nand_device_s *nand, uint32_t page,
        return info->read_page(nand, page, data, data_size, oob, oob_size);
 }
 
-static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
+static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        int page3 = nand->address_cycles - (nand->page_size == 512);
 
        /* write command ({page,otp}x{read,program} */
@@ -326,11 +342,11 @@ static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint3
                target_write_u8(target, info->addr, page >> 24);
 }
 
-static int davinci_writepage_tail(struct nand_device_s *nand,
+static int davinci_writepage_tail(struct nand_device *nand,
                uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       target_t *target = info->target;
+       struct target *target = info->target;
        uint8_t status;
 
        if (oob_size)
@@ -358,14 +374,14 @@ 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, uint32_t page,
+static int davinci_write_page_ecc1(struct nand_device *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;
+       struct target *target = info->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
-       const uint32_t ecc1_addr = info->aemif + NANDFECC + info->chipsel;
+       const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
        uint32_t fcr, ecc1;
 
        /* Write contiguous ECC bytes starting at specified offset.
@@ -425,7 +441,7 @@ static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t 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, uint32_t page,
+static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
                uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
 {
        static const uint8_t ecc512[] = {
@@ -451,7 +467,7 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
 
        struct davinci_nand *info = nand->controller_priv;
        const uint8_t *l;
-       target_t *target = info->target;
+       struct target *target = info->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
        const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
        uint32_t fcr, ecc4;
@@ -527,11 +543,11 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t 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, uint32_t page,
+static int davinci_write_page_ecc4infix(struct nand_device *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;
+       struct target *target = info->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
        const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
        uint32_t fcr, ecc4;
@@ -584,7 +600,7 @@ static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t pag
        return davinci_writepage_tail(nand, NULL, 0);
 }
 
-static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
+static int davinci_read_page_ecc4infix(struct nand_device *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);
@@ -613,16 +629,13 @@ static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page
        return ERROR_OK;
 }
 
-static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
-               char *cmd, char **argv, int argc,
-               struct nand_device_s *nand)
+NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
 {
        struct davinci_nand *info;
-       target_t *target;
+       struct target *target;
        unsigned long chip, aemif;
        enum ecc eccmode;
        int chipsel;
-       char *ep;
 
        /* arguments:
         *  - "davinci"
@@ -635,36 +648,36 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
        if (argc < 5) {
                LOG_ERROR("parameters: %s target "
                                "chip_addr hwecc_mode aemif_addr",
-                               argv[0]);
+                               args[0]);
                goto fail;
        }
 
-       target = get_target(argv[1]);
+       target = get_target(args[1]);
        if (!target) {
-               LOG_ERROR("invalid target %s", argv[1]);
+               LOG_ERROR("invalid target %s", args[1]);
                goto fail;
        }
 
-       chip = strtoul(argv[2], &ep, 0);
-       if (*ep || chip == 0 || chip == ULONG_MAX) {
-               LOG_ERROR("Invalid NAND chip address %s", argv[2]);
+       COMMAND_PARSE_NUMBER(ulong, args[2], chip);
+       if (chip == 0) {
+               LOG_ERROR("Invalid NAND chip address %s", args[2]);
                goto fail;
        }
 
-       if (strcmp(argv[3], "hwecc1") == 0)
+       if (strcmp(args[3], "hwecc1") == 0)
                eccmode = HWECC1;
-       else if (strcmp(argv[3], "hwecc4") == 0)
+       else if (strcmp(args[3], "hwecc4") == 0)
                eccmode = HWECC4;
-       else if (strcmp(argv[3], "hwecc4_infix") == 0)
+       else if (strcmp(args[3], "hwecc4_infix") == 0)
                eccmode = HWECC4_INFIX;
        else {
-               LOG_ERROR("Invalid ecc mode %s", argv[3]);
+               LOG_ERROR("Invalid ecc mode %s", args[3]);
                goto fail;
        }
 
-       aemif = strtoul(argv[4], &ep, 0);
-       if (*ep || chip == 0 || chip == ULONG_MAX) {
-               LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
+       COMMAND_PARSE_NUMBER(ulong, args[4], aemif);
+       if (aemif == 0) {
+               LOG_ERROR("Invalid AEMIF controller address %s", args[4]);
                goto fail;
        }
 
@@ -675,12 +688,12 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
        if (aemif == 0x01e00000                 /* dm6446, dm357 */
                        || 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 +713,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.
@@ -728,7 +744,7 @@ fail:
        return ERROR_NAND_OPERATION_FAILED;
 }
 
-nand_flash_controller_t davinci_nand_controller = {
+struct nand_flash_controller davinci_nand_controller = {
        .name                   = "davinci",
        .nand_device_command    = davinci_nand_device_command,
        .register_commands      = davinci_register_commands,