]> git.sur5r.net Git - openocd/blobdiff - src/flash/nand/core.c
NAND/CORE: Comment use of alive_sleep()
[openocd] / src / flash / nand / core.c
index 46f545469daef649b86dee61de409271754d5248..88a16cc6ab71e264e5da82b3f35cc0328e2cb6ea 100644 (file)
@@ -24,8 +24,6 @@
 #include "config.h"
 #endif
 
-#include <flash/nand.h>
-#include <flash/common.h>
 #include "imp.h"
 
 /* configured NAND devices and NAND Flash command handler */
@@ -58,74 +56,74 @@ static struct nand_info nand_flash_ids[] =
        {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
        {"NAND 2MiB 5V 8-bit",          0x64, 256, 2, 0x1000, 0},
        {"NAND 4MiB 5V 8-bit",          0x6b, 512, 4, 0x2000, 0},
-       {"NAND 1MiB 3,3V 8-bit",        0xe8, 256, 1, 0x1000, 0},
-       {"NAND 1MiB 3,3V 8-bit",        0xec, 256, 1, 0x1000, 0},
-       {"NAND 2MiB 3,3V 8-bit",        0xea, 256, 2, 0x1000, 0},
-       {"NAND 4MiB 3,3V 8-bit",        0xd5, 512, 4, 0x2000, 0},
-       {"NAND 4MiB 3,3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
-       {"NAND 4MiB 3,3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
-       {"NAND 8MiB 3,3V 8-bit",        0xd6, 512, 8, 0x2000, 0},
-
-       {"NAND 8MiB 1,8V 8-bit",        0x39, 512, 8, 0x2000, 0},
-       {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
-       {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-       {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+       {"NAND 1MiB 3.3V 8-bit",        0xe8, 256, 1, 0x1000, 0},
+       {"NAND 1MiB 3.3V 8-bit",        0xec, 256, 1, 0x1000, 0},
+       {"NAND 2MiB 3.3V 8-bit",        0xea, 256, 2, 0x1000, 0},
+       {"NAND 4MiB 3.3V 8-bit",        0xd5, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3.3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3.3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
+       {"NAND 8MiB 3.3V 8-bit",        0xd6, 512, 8, 0x2000, 0},
+
+       {"NAND 8MiB 1.8V 8-bit",        0x39, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 3.3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 1.8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+       {"NAND 8MiB 3.3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
        /* end "museum" IDs */
 
-       {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
-       {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
-       {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-
-       {"NAND 32MiB 1,8V 8-bit",       0x35, 512, 32, 0x4000, 0},
-       {"NAND 32MiB 3,3V 8-bit",       0x75, 512, 32, 0x4000, 0},
-       {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-
-       {"NAND 64MiB 1,8V 8-bit",       0x36, 512, 64, 0x4000, 0},
-       {"NAND 64MiB 3,3V 8-bit",       0x76, 512, 64, 0x4000, 0},
-       {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-
-       {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
-       {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},
-       {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
-       {"NAND 128MiB 1,8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 128MiB 1,8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-       {"NAND 128MiB 3,3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-
-       {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},
-
-       {"NAND 64MiB 1,8V 8-bit",       0xA2, 0,  64, 0, LP_OPTIONS},
-       {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, LP_OPTIONS},
-       {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},
-       {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},
-
-       {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},
-       {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, LP_OPTIONS},
-       {"NAND 128MiB 1,8V 16-bit",     0xB1, 0, 128, 0, LP_OPTIONS16},
-       {"NAND 128MiB 3,3V 16-bit",     0xC1, 0, 128, 0, LP_OPTIONS16},
-
-       {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},
-       {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, LP_OPTIONS},
-       {"NAND 256MiB 1,8V 16-bit",     0xBA, 0, 256, 0, LP_OPTIONS16},
-       {"NAND 256MiB 3,3V 16-bit",     0xCA, 0, 256, 0, LP_OPTIONS16},
-
-       {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, LP_OPTIONS},
-       {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, LP_OPTIONS},
-       {"NAND 512MiB 1,8V 16-bit",     0xBC, 0, 512, 0, LP_OPTIONS16},
-       {"NAND 512MiB 3,3V 16-bit",     0xCC, 0, 512, 0, LP_OPTIONS16},
-
-       {"NAND 1GiB 1,8V 8-bit",        0xA3, 0, 1024, 0, LP_OPTIONS},
-       {"NAND 1GiB 3,3V 8-bit",        0xD3, 0, 1024, 0, LP_OPTIONS},
-       {"NAND 1GiB 1,8V 16-bit",       0xB3, 0, 1024, 0, LP_OPTIONS16},
-       {"NAND 1GiB 3,3V 16-bit",       0xC3, 0, 1024, 0, LP_OPTIONS16},
-
-       {"NAND 2GiB 1,8V 8-bit",        0xA5, 0, 2048, 0, LP_OPTIONS},
-       {"NAND 2GiB 3,3V 8-bit",        0xD5, 0, 2048, 0, LP_OPTIONS},
-       {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, LP_OPTIONS16},
-       {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, LP_OPTIONS16},
+       {"NAND 16MiB 1.8V 8-bit",       0x33, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 3.3V 8-bit",       0x73, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 1.8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 16MiB 3.3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 32MiB 1.8V 8-bit",       0x35, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 3.3V 8-bit",       0x75, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 1.8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 32MiB 3.3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 64MiB 1.8V 8-bit",       0x36, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 3.3V 8-bit",       0x76, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 1.8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 64MiB 3.3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 128MiB 1.8V 8-bit",      0x78, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1.8V 8-bit",      0x39, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 3.3V 8-bit",      0x79, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1.8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 1.8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3.3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3.3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+       {"NAND 256MiB 3.3V 8-bit",      0x71, 512, 256, 0x4000, 0},
+
+       {"NAND 64MiB 1.8V 8-bit",       0xA2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 3.3V 8-bit",       0xF2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 1.8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},
+       {"NAND 64MiB 3.3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},
+
+       {"NAND 128MiB 1.8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},
+       {"NAND 128MiB 3.3V 8-bit",      0xF1, 0, 128, 0, LP_OPTIONS},
+       {"NAND 128MiB 1.8V 16-bit",     0xB1, 0, 128, 0, LP_OPTIONS16},
+       {"NAND 128MiB 3.3V 16-bit",     0xC1, 0, 128, 0, LP_OPTIONS16},
+
+       {"NAND 256MiB 1.8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},
+       {"NAND 256MiB 3.3V 8-bit",      0xDA, 0, 256, 0, LP_OPTIONS},
+       {"NAND 256MiB 1.8V 16-bit",     0xBA, 0, 256, 0, LP_OPTIONS16},
+       {"NAND 256MiB 3.3V 16-bit",     0xCA, 0, 256, 0, LP_OPTIONS16},
+
+       {"NAND 512MiB 1.8V 8-bit",      0xAC, 0, 512, 0, LP_OPTIONS},
+       {"NAND 512MiB 3.3V 8-bit",      0xDC, 0, 512, 0, LP_OPTIONS},
+       {"NAND 512MiB 1.8V 16-bit",     0xBC, 0, 512, 0, LP_OPTIONS16},
+       {"NAND 512MiB 3.3V 16-bit",     0xCC, 0, 512, 0, LP_OPTIONS16},
+
+       {"NAND 1GiB 1.8V 8-bit",        0xA3, 0, 1024, 0, LP_OPTIONS},
+       {"NAND 1GiB 3.3V 8-bit",        0xD3, 0, 1024, 0, LP_OPTIONS},
+       {"NAND 1GiB 1.8V 16-bit",       0xB3, 0, 1024, 0, LP_OPTIONS16},
+       {"NAND 1GiB 3.3V 16-bit",       0xC3, 0, 1024, 0, LP_OPTIONS16},
+
+       {"NAND 2GiB 1.8V 8-bit",        0xA5, 0, 2048, 0, LP_OPTIONS},
+       {"NAND 2GiB 3.3V 8-bit",        0xD5, 0, 2048, 0, LP_OPTIONS},
+       {"NAND 2GiB 1.8V 16-bit",       0xB5, 0, 2048, 0, LP_OPTIONS16},
+       {"NAND 2GiB 3.3V 16-bit",       0xC5, 0, 2048, 0, LP_OPTIONS16},
 
        {NULL, 0, 0, 0, 0, 0 }
 };
@@ -162,7 +160,14 @@ static struct nand_ecclayout nand_oob_8 = {
 };
 #endif
 
-struct nand_device *get_nand_device_by_name(const char *name)
+/**
+ * Returns the flash bank specified by @a name, which matches the
+ * driver name and a suffix (option) specify the driver-specific
+ * bank number. The suffix consists of the '.' and the driver-specific
+ * bank number: when two davinci banks are defined, then 'davinci.1' refers
+ * to the second (e.g. DM355EVM).
+ */
+static struct nand_device *get_nand_device_by_name(const char *name)
 {
        unsigned requested = get_flash_name_index(name);
        unsigned found = 0;
@@ -217,9 +222,11 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
 
 int nand_build_bbt(struct nand_device *nand, int first, int last)
 {
-       uint32_t page = 0x0;
+       uint32_t page;
        int i;
+       int pages_per_block = (nand->erase_size / nand->page_size);
        uint8_t oob[6];
+       int ret;
 
        if ((first < 0) || (first >= nand->num_blocks))
                first = 0;
@@ -227,9 +234,12 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
        if ((last >= nand->num_blocks) || (last == -1))
                last = nand->num_blocks - 1;
 
-       for (i = first; i < last; i++)
+       page = first * pages_per_block;
+       for (i = first; i <= last; i++)
        {
-               nand_read_page(nand, page, NULL, 0, oob, 6);
+               ret = nand_read_page(nand, page, NULL, 0, oob, 6);
+               if (ret != ERROR_OK)
+                       return ret;
 
                if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
                        || (((nand->page_size == 512) && (oob[5] != 0xff)) ||
@@ -243,7 +253,7 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
                        nand->blocks[i].is_bad = 0;
                }
 
-               page += (nand->erase_size / nand->page_size);
+               page += pages_per_block;
        }
 
        return ERROR_OK;
@@ -523,7 +533,7 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
        if (!nand->device)
                return ERROR_NAND_DEVICE_NOT_PROBED;
 
-       if ((first_block < 0) || (last_block > nand->num_blocks))
+       if ((first_block < 0) || (last_block >= nand->num_blocks))
                return ERROR_INVALID_ARGUMENTS;
 
        /* make sure we know if a block is bad before erasing it */
@@ -677,7 +687,9 @@ static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t
 }
 #endif
 
-int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+int nand_write_page(struct nand_device *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size,
+               uint8_t *oob, uint32_t oob_size)
 {
        uint32_t block;
 
@@ -764,17 +776,38 @@ int nand_page_command(struct nand_device *nand, uint32_t page,
                if (!nand->controller->nand_ready(nand, 100))
                        return ERROR_NAND_OPERATION_TIMEOUT;
        } else {
+               /* nand_poll_read() cannot be used during nand read */
                alive_sleep(1);
        }
 
        return ERROR_OK;
 }
 
+int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
+{
+       int retval = ERROR_NAND_NO_BUFFER;
+
+       if (nand->controller->read_block_data != NULL)
+               retval = (nand->controller->read_block_data)(nand, data, size);
+
+       if (ERROR_NAND_NO_BUFFER == retval) {
+               uint32_t i;
+               int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1;
+
+               retval = ERROR_OK;
+               for (i = 0; retval == ERROR_OK && i < size; i += incr) {
+                       retval = nand->controller->read_data(nand, data);
+                       data += incr;
+               }
+       }
+
+       return retval;
+}
+
 int nand_read_page_raw(struct nand_device *nand, uint32_t page,
                uint8_t *data, uint32_t data_size,
                uint8_t *oob, uint32_t oob_size)
 {
-       uint32_t i;
        int retval;
 
        retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
@@ -782,116 +815,49 @@ int nand_read_page_raw(struct nand_device *nand, uint32_t page,
                return retval;
 
        if (data)
-       {
-               if (nand->controller->read_block_data != NULL)
-                       (nand->controller->read_block_data)(nand, data, data_size);
-               else
-               {
-                       for (i = 0; i < data_size;)
-                       {
-                               if (nand->device->options & NAND_BUSWIDTH_16)
-                               {
-                                       nand->controller->read_data(nand, data);
-                                       data += 2;
-                                       i += 2;
-                               }
-                               else
-                               {
-                                       nand->controller->read_data(nand, data);
-                                       data += 1;
-                                       i += 1;
-                               }
-                       }
-               }
-       }
+               nand_read_data_page(nand, data, data_size);
 
        if (oob)
-       {
-               if (nand->controller->read_block_data != NULL)
-                       (nand->controller->read_block_data)(nand, oob, oob_size);
-               else
-               {
-                       for (i = 0; i < oob_size;)
-                       {
-                               if (nand->device->options & NAND_BUSWIDTH_16)
-                               {
-                                       nand->controller->read_data(nand, oob);
-                                       oob += 2;
-                                       i += 2;
-                               }
-                               else
-                               {
-                                       nand->controller->read_data(nand, oob);
-                                       oob += 1;
-                                       i += 1;
-                               }
-                       }
-               }
-       }
+               nand_read_data_page(nand, oob, oob_size);
 
        return ERROR_OK;
 }
 
-int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
+int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
 {
-       uint32_t i;
-       int retval;
-       uint8_t status;
+       int retval = ERROR_NAND_NO_BUFFER;
 
-       retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
-       if (ERROR_OK != retval)
-               return retval;
+       if (nand->controller->write_block_data != NULL)
+               retval = (nand->controller->write_block_data)(nand, data, size);
 
-       if (data)
-       {
-               if (nand->controller->write_block_data != NULL)
-                       (nand->controller->write_block_data)(nand, data, data_size);
-               else
-               {
-                       for (i = 0; i < data_size;)
-                       {
-                               if (nand->device->options & NAND_BUSWIDTH_16)
-                               {
-                                       uint16_t data_buf = le_to_h_u16(data);
-                                       nand->controller->write_data(nand, data_buf);
-                                       data += 2;
-                                       i += 2;
-                               }
-                               else
-                               {
-                                       nand->controller->write_data(nand, *data);
-                                       data += 1;
-                                       i += 1;
-                               }
-                       }
-               }
-       }
+       if (ERROR_NAND_NO_BUFFER == retval) {
+               bool is16bit = nand->device->options & NAND_BUSWIDTH_16;
+               uint32_t incr = is16bit ? 2 : 1;
+               uint16_t write_data;
+               uint32_t i;
 
-       if (oob)
-       {
-               if (nand->controller->write_block_data != NULL)
-                       (nand->controller->write_block_data)(nand, oob, oob_size);
-               else
-               {
-                       for (i = 0; i < oob_size;)
-                       {
-                               if (nand->device->options & NAND_BUSWIDTH_16)
-                               {
-                                       uint16_t oob_buf = le_to_h_u16(data);
-                                       nand->controller->write_data(nand, oob_buf);
-                                       oob += 2;
-                                       i += 2;
-                               }
-                               else
-                               {
-                                       nand->controller->write_data(nand, *oob);
-                                       oob += 1;
-                                       i += 1;
-                               }
-                       }
+               for (i = 0; i < size; i += incr) {
+                       if (is16bit)
+                               write_data = le_to_h_u16(data);
+                       else
+                               write_data = *data;
+
+                       retval = nand->controller->write_data(nand, write_data);
+                       if (ERROR_OK != retval)
+                               break;
+
+                       data += incr;
                }
        }
 
+       return retval;
+}
+
+int nand_write_finish(struct nand_device *nand)
+{
+       int retval;
+       uint8_t status;
+
        nand->controller->command(nand, NAND_CMD_PAGEPROG);
 
        retval = nand->controller->nand_ready ?
@@ -900,18 +866,47 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data,
        if (!retval)
                return ERROR_NAND_OPERATION_TIMEOUT;
 
-       if ((retval = nand_read_status(nand, &status)) != ERROR_OK)
-       {
+       retval = nand_read_status(nand, &status);
+       if (ERROR_OK != retval) {
                LOG_ERROR("couldn't read status");
                return ERROR_NAND_OPERATION_FAILED;
        }
 
-       if (status & NAND_STATUS_FAIL)
-       {
-               LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status);
+       if (status & NAND_STATUS_FAIL) {
+               LOG_ERROR("write operation didn't pass, status: 0x%2.2x",
+                               status);
                return ERROR_NAND_OPERATION_FAILED;
        }
 
        return ERROR_OK;
 }
 
+int nand_write_page_raw(struct nand_device *nand, uint32_t page,
+               uint8_t *data, uint32_t data_size,
+               uint8_t *oob, uint32_t oob_size)
+{
+       int retval;
+
+       retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (data) {
+               retval = nand_write_data_page(nand, data, data_size);
+               if (ERROR_OK != retval) {
+                       LOG_ERROR("Unable to write data to NAND device");
+                       return retval;
+               }
+       }
+
+       if (oob) {
+               retval = nand_write_data_page(nand, oob, oob_size);
+               if (ERROR_OK != retval) {
+                       LOG_ERROR("Unable to write OOB data to NAND device");
+                       return retval;
+               }
+       }
+
+       return nand_write_finish(nand);
+}
+