Change return value on error.
[fw/openocd] / src / flash / nand / davinci.c
index 0152b4d93787cff8ee7dd3b09045ed37d514936e..e12fc46104692063c59aa70a1d150bb9f1a28a17 100644 (file)
@@ -28,8 +28,9 @@
 #include "config.h"
 #endif
 
+#include "imp.h"
 #include "arm_io.h"
-
+#include <target/target.h>
 
 enum ecc {
        HWECC1,         /* all controllers support 1-bit ECC */
@@ -38,8 +39,6 @@ enum ecc {
 };
 
 struct davinci_nand {
-       struct target   *target;
-
        uint8_t         chipsel;        /* chipselect 0..3 == CS2..CS5 */
        uint8_t         eccmode;
 
@@ -81,7 +80,7 @@ static int halted(struct target *target, const char *label)
 static int davinci_init(struct nand_device *nand)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        uint32_t nandfcr;
 
        if (!halted(target, "init"))
@@ -111,7 +110,7 @@ static int davinci_reset(struct nand_device *nand)
 static int davinci_nand_ready(struct nand_device *nand, int timeout)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        uint32_t nandfsr;
 
        /* NOTE: return code is zero/error, else success; not ERROR_* */
@@ -134,7 +133,7 @@ static int davinci_nand_ready(struct nand_device *nand, int timeout)
 static int davinci_command(struct nand_device *nand, uint8_t command)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
 
        if (!halted(target, "command"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -146,7 +145,7 @@ static int davinci_command(struct nand_device *nand, uint8_t command)
 static int davinci_address(struct nand_device *nand, uint8_t address)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
 
        if (!halted(target, "address"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -158,7 +157,7 @@ static int davinci_address(struct nand_device *nand, uint8_t address)
 static int davinci_write_data(struct nand_device *nand, uint16_t data)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
 
        if (!halted(target, "write_data"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -170,7 +169,7 @@ static int davinci_write_data(struct nand_device *nand, uint16_t data)
 static int davinci_read_data(struct nand_device *nand, void *data)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
 
        if (!halted(target, "read_data"))
                return ERROR_NAND_OPERATION_FAILED;
@@ -185,7 +184,7 @@ static int davinci_read_block_data(struct nand_device *nand,
                uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        uint32_t nfdata = info->data;
        uint32_t tmp;
 
@@ -218,7 +217,7 @@ static int davinci_write_block_data(struct nand_device *nand,
                uint8_t *data, int data_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        uint32_t nfdata = info->data;
        uint32_t tmp;
        int status;
@@ -259,12 +258,12 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
 
        if (!nand->device)
                return ERROR_NAND_DEVICE_NOT_PROBED;
-       if (!halted(info->target, "write_page"))
+       if (!halted(nand->target, "write_page"))
                return ERROR_NAND_OPERATION_FAILED;
 
        /* Always write both data and OOB ... we are not "raw" I/O! */
        if (!data) {
-               LOG_ERROR("Missing NAND data; try 'nand raw_access enable'\n");
+               LOG_ERROR("Missing NAND data; try 'nand raw_access enable'");
                return ERROR_NAND_OPERATION_FAILED;
        }
 
@@ -308,7 +307,7 @@ static int davinci_read_page(struct nand_device *nand, uint32_t page,
 
        if (!nand->device)
                return ERROR_NAND_DEVICE_NOT_PROBED;
-       if (!halted(info->target, "read_page"))
+       if (!halted(nand->target, "read_page"))
                return ERROR_NAND_OPERATION_FAILED;
 
        return info->read_page(nand, page, data, data_size, oob, oob_size);
@@ -317,7 +316,7 @@ static int davinci_read_page(struct nand_device *nand, 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;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        int page3 = nand->address_cycles - (nand->page_size == 512);
 
        /* write command ({page,otp}x{read,program} */
@@ -337,11 +336,32 @@ static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_
                target_write_u8(target, info->addr, page >> 24);
 }
 
+static int davinci_seek_column(struct nand_device *nand, uint16_t column)
+{
+       struct davinci_nand *info = nand->controller_priv;
+       struct target *target = nand->target;
+
+       /* Random read, we must have issued a page read already */
+       target_write_u8(target, info->cmd, NAND_CMD_RNDOUT);
+
+       target_write_u8(target, info->addr, column);
+
+       if (nand->page_size > 512) {
+               target_write_u8(target, info->addr, column >> 8);
+               target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART);
+       }
+
+       if (!davinci_nand_ready(nand, 100))
+               return ERROR_NAND_OPERATION_TIMEOUT;
+
+       return ERROR_OK;
+}
+
 static int davinci_writepage_tail(struct nand_device *nand,
                uint8_t *oob, uint32_t oob_size)
 {
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        uint8_t status;
 
        if (oob_size)
@@ -374,7 +394,7 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
 {
        unsigned oob_offset;
        struct davinci_nand *info = nand->controller_priv;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
        const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
        uint32_t fcr, ecc1;
@@ -462,7 +482,7 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
 
        struct davinci_nand *info = nand->controller_priv;
        const uint8_t *l;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
        const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
        uint32_t fcr, ecc4;
@@ -542,7 +562,7 @@ 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;
-       struct target *target = info->target;
+       struct target *target = nand->target;
        const uint32_t fcr_addr = info->aemif + NANDFCR;
        const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
        uint32_t fcr, ecc4;
@@ -598,6 +618,10 @@ static int davinci_write_page_ecc4infix(struct nand_device *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)
 {
+       int read_size;
+       int want_col, at_col;
+       int ret;
+
        davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
 
        /* large page devices need a start command */
@@ -609,25 +633,49 @@ static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
 
        /* NOTE:  not bothering to compute and use ECC data for now */
 
-       do {
-               /* write 512 bytes */
-               davinci_read_block_data(nand, data, 512);
-               data += 512;
-               data_size -= 512;
-
-               /* read this "out-of-band" data -- infix */
-               davinci_read_block_data(nand, oob, 16);
-               oob += 16;
-               oob_size -= 16;
-       } while (data_size);
-
+       want_col = 0;
+       at_col = 0;
+       while ((data && data_size) || (oob && oob_size)) {
+
+               if (data && data_size) {
+                       if (want_col != at_col) {
+                               /* Reads are slow, so seek past them when we can */
+                               ret  = davinci_seek_column(nand, want_col);
+                               if (ret != ERROR_OK)
+                                       return ret;
+                               at_col = want_col;
+                       }
+                       /* read 512 bytes or data_size, whichever is smaller*/
+                       read_size = data_size > 512 ? 512 : data_size;
+                       davinci_read_block_data(nand, data, read_size);
+                       data += read_size;
+                       data_size -= read_size;
+                       at_col += read_size;
+               }
+               want_col += 512;
+
+               if (oob && oob_size) {
+                       if (want_col != at_col) {
+                               ret  = davinci_seek_column(nand, want_col);
+                               if (ret != ERROR_OK)
+                                       return ret;
+                               at_col = want_col;
+                       }
+                       /* read this "out-of-band" data -- infix */
+                       read_size = oob_size > 16 ? 16 : oob_size;
+                       davinci_read_block_data(nand, oob, read_size);
+                       oob += read_size;
+                       oob_size -= read_size;
+                       at_col += read_size;
+               }
+               want_col += 16;
+       }
        return ERROR_OK;
 }
 
 NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
 {
        struct davinci_nand *info;
-       struct target *target;
        unsigned long chip, aemif;
        enum ecc eccmode;
        int chipsel;
@@ -641,16 +689,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
         * Plus someday, optionally, ALE and CLE masks.
         */
        if (CMD_ARGC < 5) {
-               LOG_ERROR("parameters: %s target "
-                               "chip_addr hwecc_mode aemif_addr",
-                               CMD_ARGV[0]);
-               goto fail;
-       }
-
-       target = get_target(CMD_ARGV[1]);
-       if (!target) {
-               LOG_ERROR("invalid target %s", CMD_ARGV[1]);
-               goto fail;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
@@ -698,7 +737,6 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
        if (info == NULL)
                goto fail;
 
-       info->target = target;
        info->eccmode = eccmode;
        info->chipsel = chipsel;
        info->aemif = aemif;
@@ -708,7 +746,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
 
        nand->controller_priv = info;
 
-       info->io.target = target;
+       info->io.target = nand->target;
        info->io.data = info->data;
        info->io.op = ARM_NAND_NONE;
 
@@ -742,6 +780,7 @@ fail:
 
 struct nand_flash_controller davinci_nand_controller = {
        .name                   = "davinci",
+       .usage                  = "chip_addr hwecc_mode aemif_addr",
        .nand_device_command    = davinci_nand_device_command,
        .init                   = davinci_init,
        .reset                  = davinci_reset,