Added support for i.MX35 NAND Flash Controller (v2)
authorErik Ahlén <erik.ahlen@avalonenterprise.com>
Wed, 14 Dec 2011 09:10:29 +0000 (10:10 +0100)
committerSpencer Oliver <spen@spen-soft.co.uk>
Fri, 23 Dec 2011 09:40:44 +0000 (09:40 +0000)
Change-Id: I7237ec29792b6a7ee690751fa7e6cba0846d5aa8
Signed-off-by: Erik Ahlén <erik.ahlen@avalonenterprise.com>
Reviewed-on: http://openocd.zylin.com/271
Tested-by: jenkins
Reviewed-by: Mathias Küster <kesmtp@freenet.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/flash/nand/mx2.c
src/flash/nand/mx2.h

index 4393e2dd6d75aff562cb754425b6addb5a40f730..a4e6eb1a1e86cba9ff1a38419fd10a36d99b7a1c 100644 (file)
 #include "mx2.h"
 #include <target/target.h>
 
+#define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \
+                                       mxc_nf_info->mxc_version == MXC_VERSION_MX31)
+#define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX35)
+
 /* This permits to print (in LOG_INFO) how much bytes
  * has been written after a page read or write.
  * This is useful when OpenOCD is used with a graphical
@@ -63,6 +67,7 @@ static const char get_status_register_err_msg[] = "can't get NAND status";
 static uint32_t in_sram_address;
 static unsigned char sign_of_sequental_byte_read;
 
+static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr);
 static int initialize_nf_controller(struct nand_device *nand);
 static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value);
 static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value);
@@ -94,12 +99,19 @@ NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command)
        /*
         * check board type
         */
-       if (strcmp(CMD_ARGV[2], "mx27") == 0)
+       if (strcmp(CMD_ARGV[2], "mx27") == 0) {
+               mxc_nf_info->mxc_version = MXC_VERSION_MX27;
                mxc_nf_info->mxc_base_addr = 0xD8000000;
-       else if (strcmp(CMD_ARGV[2], "mx31") == 0)
+               mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
+       } else if (strcmp(CMD_ARGV[2], "mx31") == 0) {
+               mxc_nf_info->mxc_version = MXC_VERSION_MX31;
                mxc_nf_info->mxc_base_addr = 0xB8000000;
-       else if (strcmp(CMD_ARGV[2], "mx35") == 0)
+               mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
+       } else if (strcmp(CMD_ARGV[2], "mx35") == 0) {
+               mxc_nf_info->mxc_version = MXC_VERSION_MX35;
                mxc_nf_info->mxc_base_addr = 0xBB000000;
+               mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
+       }
 
        /*
         * check hwecc requirements
@@ -192,7 +204,10 @@ static int mxc_init(struct nand_device *nand)
 
        int validate_target_result;
        uint16_t buffsize_register_content;
-       uint32_t pcsr_register_content;
+       uint32_t sreg_content;
+       uint32_t SREG = MX2_FMCR;
+       uint32_t SEL_16BIT = MX2_FMCR_NF_16BIT_SEL;
+       uint32_t SEL_FMS = MX2_FMCR_NF_FMS;
        int retval;
        uint16_t nand_status_content;
        /*
@@ -202,19 +217,30 @@ static int mxc_init(struct nand_device *nand)
        if (validate_target_result != ERROR_OK)
                return validate_target_result;
 
-       target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content);
-       mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
+       if (nfc_is_v1()) {
+               target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content);
+               mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
+       } else
+               mxc_nf_info->flags.one_kb_sram = 0;
+
+       if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) {
+               SREG = MX3_PCSR;
+               SEL_16BIT = MX3_PCSR_NF_16BIT_SEL;
+               SEL_FMS = MX3_PCSR_NF_FMS;
+       } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) {
+               SREG = MX35_RCSR;
+               SEL_16BIT = MX35_RCSR_NF_16BIT_SEL;
+               SEL_FMS = MX35_RCSR_NF_FMS;
+       }
 
-       target_read_u32(target, MXC_FMCR, &pcsr_register_content);
+       target_read_u32(target, SREG, &sreg_content);
        if (!nand->bus_width) {
                /* bus_width not yet defined. Read it from MXC_FMCR */
-               nand->bus_width =
-                       (pcsr_register_content & MXC_FMCR_NF_16BIT_SEL) ? 16 : 8;
+               nand->bus_width = (sreg_content & SEL_16BIT) ? 16 : 8;
        } else {
                /* bus_width forced in soft. Sync it to MXC_FMCR */
-               pcsr_register_content |=
-                       ((nand->bus_width == 16) ? MXC_FMCR_NF_16BIT_SEL : 0x00000000);
-               target_write_u32(target, MXC_FMCR, pcsr_register_content);
+               sreg_content |= ((nand->bus_width == 16) ? SEL_16BIT : 0x00000000);
+               target_write_u32(target, SREG, sreg_content);
        }
        if (nand->bus_width == 16)
                LOG_DEBUG("MXC_NF : bus is 16-bit width");
@@ -222,11 +248,10 @@ static int mxc_init(struct nand_device *nand)
                LOG_DEBUG("MXC_NF : bus is 8-bit width");
 
        if (!nand->page_size) {
-               nand->page_size = (pcsr_register_content & MXC_FMCR_NF_FMS) ? 2048 : 512;
+               nand->page_size = (sreg_content & SEL_FMS) ? 2048 : 512;
        } else {
-               pcsr_register_content |=
-                       ((nand->page_size == 2048) ? MXC_FMCR_NF_FMS : 0x00000000);
-               target_write_u32(target, MXC_FMCR, pcsr_register_content);
+               sreg_content |= ((nand->page_size == 2048) ? SEL_FMS : 0x00000000);
+               target_write_u32(target, SREG, sreg_content);
        }
        if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
                LOG_ERROR("NAND controller have only 1 kb SRAM, so "
@@ -235,6 +260,9 @@ static int mxc_init(struct nand_device *nand)
                LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048");
        }
 
+       if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K)
+               LOG_ERROR("MXC driver does not have support for 4k pagesize.");
+
        initialize_nf_controller(nand);
 
        retval = ERROR_OK;
@@ -322,7 +350,10 @@ static int mxc_command(struct nand_device *nand, uint8_t command)
                /* set read point for data_read() and read_block_data() to
                 * spare area in SRAM buffer
                 */
-               in_sram_address = MXC_NF_SPARE_BUFFER0;
+               if (nfc_is_v1())
+                       in_sram_address = MXC_NF_V1_SPARE_BUFFER0;
+               else
+                       in_sram_address = MXC_NF_V2_SPARE_BUFFER0;
                break;
        case NAND_CMD_READ1:
                command = NAND_CMD_READ0;
@@ -431,7 +462,9 @@ static int mxc_write_page(struct nand_device *nand, uint32_t page,
        int retval;
        uint16_t nand_status_content;
        uint16_t swap1, swap2, new_swap1;
+       uint8_t bufs;
        int poll_result;
+
        if (data_size % 2) {
                LOG_ERROR(data_block_size_err_msg, data_size);
                return ERROR_NAND_OPERATION_FAILED;
@@ -444,6 +477,7 @@ static int mxc_write_page(struct nand_device *nand, uint32_t page,
                LOG_ERROR("nothing to program");
                return ERROR_NAND_OPERATION_FAILED;
        }
+
        /*
         * validate target state
         */
@@ -471,7 +505,18 @@ static int mxc_write_page(struct nand_device *nand, uint32_t page,
                        LOG_DEBUG("part of spare block will be overrided "
                                  "by hardware ECC generator");
                }
-               target_write_buffer(target, MXC_NF_SPARE_BUFFER0, oob_size,     oob);
+               if (nfc_is_v1())
+                       target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
+               else {
+                       uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
+                       while (oob_size > 0) {
+                               uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
+                               target_write_buffer(target, addr, len, oob);
+                               addr = align_address_v2(nand, addr + len);
+                               oob += len;
+                               oob_size -= len;
+                       }
+               }
        }
 
        if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
@@ -485,35 +530,27 @@ static int mxc_write_page(struct nand_device *nand, uint32_t page,
                new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
                swap2 = (swap1 << 8) | (swap2 & 0xFF);
                target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
-               target_write_u16(target, MXC_NF_SPARE_BUFFER3 + 4, swap2);
+               if (nfc_is_v1())
+                       target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3, swap2);
+               else
+                       target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2);
        }
 
        /*
         * start data input operation (set MXC_NF_BIT_OP_DONE==0)
         */
-       target_write_u16(target, MXC_NF_BUFADDR, 0);
-       target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
-       poll_result = poll_for_complete_op(nand, "data input");
-       if (poll_result != ERROR_OK)
-               return poll_result;
-
-       target_write_u16(target, MXC_NF_BUFADDR, 1);
-       target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
-       poll_result = poll_for_complete_op(nand, "data input");
-       if (poll_result != ERROR_OK)
-               return poll_result;
-
-       target_write_u16(target, MXC_NF_BUFADDR, 2);
-       target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
-       poll_result = poll_for_complete_op(nand, "data input");
-       if (poll_result != ERROR_OK)
-               return poll_result;
+       if (nfc_is_v1() && nand->page_size > 512)
+               bufs = 4;
+       else
+               bufs = 1;
 
-       target_write_u16(target, MXC_NF_BUFADDR, 3);
-       target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
-       poll_result = poll_for_complete_op(nand, "data input");
-       if (poll_result != ERROR_OK)
-               return poll_result;
+       for (uint8_t i = 0 ; i < bufs ; ++i) {
+               target_write_u16(target, MXC_NF_BUFADDR, i);
+               target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
+               poll_result = poll_for_complete_op(nand, "data input");
+               if (poll_result != ERROR_OK)
+                       return poll_result;
+       }
 
        retval |= mxc_command(nand, NAND_CMD_PAGEPROG);
        if (retval != ERROR_OK)
@@ -552,6 +589,7 @@ static int mxc_read_page(struct nand_device *nand, uint32_t page,
        struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
        struct target *target = nand->target;
        int retval;
+       uint8_t bufs;
        uint16_t swap1, swap2, new_swap1;
 
        if (data_size % 2) {
@@ -586,50 +624,52 @@ static int mxc_read_page(struct nand_device *nand, uint32_t page,
        retval = mxc_command(nand, NAND_CMD_READSTART);
        if (retval != ERROR_OK) return retval;
 
-       target_write_u16(target, MXC_NF_BUFADDR, 0);
-       mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
-       retval = do_data_output(nand);
-       if (retval != ERROR_OK) {
-               LOG_ERROR("MXC_NF : Error reading page 0");
-               return retval;
-       }
-       /* Test nand page size to know how much MAIN_BUFFER must be written */
-       target_write_u16(target, MXC_NF_BUFADDR, 1);
-       mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
-       retval = do_data_output(nand);
-       if (retval != ERROR_OK) {
-               LOG_ERROR("MXC_NF : Error reading page 1");
-               return retval;
-       }
-       target_write_u16(target, MXC_NF_BUFADDR, 2);
-       mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
-       retval = do_data_output(nand);
-       if (retval != ERROR_OK) {
-               LOG_ERROR("MXC_NF : Error reading page 2");
-               return retval;
-       }
-       target_write_u16(target, MXC_NF_BUFADDR, 3);
-       mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
-       retval = do_data_output(nand);
-       if (retval != ERROR_OK) {
-               LOG_ERROR("MXC_NF : Error reading page 3");
-               return retval;
+       if (nfc_is_v1() && nand->page_size > 512)
+               bufs = 4;
+       else
+               bufs = 1;
+
+       for (uint8_t i = 0 ; i < bufs ; ++i) {
+               target_write_u16(target, MXC_NF_BUFADDR, i);
+               mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
+               retval = do_data_output(nand);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("MXC_NF : Error reading page %d", i);
+                       return retval;
+               }
        }
 
        if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
+               uint32_t SPARE_BUFFER3;
                /* BI-swap -  work-around of mxc NFC for NAND device with page == 2k */
                target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
-               target_read_u16(target, MXC_NF_SPARE_BUFFER3 + 4, &swap2);
+               if (nfc_is_v1())
+                       SPARE_BUFFER3 = MXC_NF_V1_SPARE_BUFFER3;
+               else
+                       SPARE_BUFFER3 = MXC_NF_V2_SPARE_BUFFER3;
+               target_read_u16(target, SPARE_BUFFER3, &swap2);
                new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
                swap2 = (swap1 << 8) | (swap2 & 0xFF);
                target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
-               target_write_u16(target, MXC_NF_SPARE_BUFFER3 + 4, swap2);
+               target_write_u16(target, SPARE_BUFFER3, swap2);
        }
 
        if (data)
                target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
-       if (oob)
-               target_read_buffer(target, MXC_NF_SPARE_BUFFER0, oob_size, oob);
+       if (oob) {
+               if (nfc_is_v1())
+                       target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
+               else {
+                       uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
+                       while (oob_size > 0) {
+                               uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
+                               target_read_buffer(target, addr, len, oob);
+                               addr = align_address_v2(nand, addr + len);
+                               oob += len;
+                               oob_size -= len;
+                       }
+               }
+       }
 
 #ifdef _MXC_PRINT_STAT
        if (data_size > 0) {
@@ -642,17 +682,31 @@ static int mxc_read_page(struct nand_device *nand, uint32_t page,
        return ERROR_OK;
 }
 
+static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr)
+{
+       struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
+       uint32_t ret = addr;
+       if (addr > MXC_NF_V2_SPARE_BUFFER0 &&
+          (addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN) {
+               ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN;
+       } else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size))
+               ret = MXC_NF_V2_SPARE_BUFFER0;
+       return ret;
+}
+
 static int initialize_nf_controller(struct nand_device *nand)
 {
        struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
        struct target *target = nand->target;
-       uint16_t work_mode;
+       uint16_t work_mode = 0;
        uint16_t temp;
        /*
         * resets NAND flash controller in zero time ? I dont know.
         */
        target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN);
-       work_mode = MXC_NF_BIT_INT_DIS; /* disable interrupt */
+       if (mxc_nf_info->mxc_version == MXC_VERSION_MX27)
+               work_mode = MXC_NF_BIT_INT_DIS; /* disable interrupt */
+
        if (target->endianness == TARGET_BIG_ENDIAN) {
                LOG_DEBUG("MXC_NF : work in Big Endian mode");
                work_mode |= MXC_NF_BIT_BE_EN;
@@ -665,7 +719,15 @@ static int initialize_nf_controller(struct nand_device *nand)
        } else {
                LOG_DEBUG("MXC_NF : work without ECC mode");
        }
+       if (nfc_is_v2()) {
+               if (nand->page_size) {
+                       uint16_t pages_per_block = nand->erase_size / nand->page_size;
+                       work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6);
+               }
+               work_mode |= MXC_NF_BIT_ECC_4BIT;
+       }
        target_write_u16(target, MXC_NF_CFG1, work_mode);
+
        /*
         * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
         */
@@ -679,11 +741,23 @@ static int initialize_nf_controller(struct nand_device *nand)
        /*
         * unlock NAND flash for write
         */
+       if (nfc_is_v1()) {
+               target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000);
+               target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF);
+       } else {
+               target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000);
+               target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000);
+               target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000);
+               target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000);
+               target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF);
+               target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF);
+               target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF);
+               target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF);
+       }
        target_write_u16(target, MXC_NF_FWP, 4);
-       target_write_u16(target, MXC_NF_LOCKSTART, 0x0000);
-       target_write_u16(target, MXC_NF_LOCKEND, 0xFFFF);
+
        /*
-        * 0x0000 means that first SRAM buffer @0xD800_0000 will be used
+        * 0x0000 means that first SRAM buffer @base_addr will be used
         */
        target_write_u16(target, MXC_NF_BUFADDR, 0x0000);
        /*
@@ -706,13 +780,17 @@ static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *val
        if (sign_of_sequental_byte_read == 0)
                even_byte = 0;
 
-       if (in_sram_address > MXC_NF_LAST_BUFFER_ADDR) {
+       if (in_sram_address >
+               (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
                LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
                *value = 0;
                sign_of_sequental_byte_read = 0;
                even_byte = 0;
                return ERROR_NAND_OPERATION_FAILED;
        } else {
+               if (nfc_is_v2())
+                       in_sram_address = align_address_v2(nand, in_sram_address);
+
                target_read_u16(target, in_sram_address, &temp);
                if (even_byte) {
                        *value = temp >> 8;
@@ -732,11 +810,15 @@ static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t
        struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
        struct target *target = nand->target;
 
-       if (in_sram_address > MXC_NF_LAST_BUFFER_ADDR) {
+       if (in_sram_address >
+               (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
                LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
                *value = 0;
                return ERROR_NAND_OPERATION_FAILED;
        } else {
+               if (nfc_is_v2())
+                       in_sram_address = align_address_v2(nand, in_sram_address);
+
                target_read_u16(target, in_sram_address, value);
                in_sram_address += 2;
        }
@@ -745,18 +827,7 @@ static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t
 
 static int poll_for_complete_op(struct nand_device *nand, const char *text)
 {
-       struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
-       struct target *target = nand->target;
-       uint16_t poll_complete_status;
-
-       for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) {
-               target_read_u16(target, MXC_NF_CFG2, &poll_complete_status);
-               if (poll_complete_status & MXC_NF_BIT_OP_DONE)
-                       break;
-
-               usleep(10);
-       }
-       if (!(poll_complete_status & MXC_NF_BIT_OP_DONE)) {
+       if (mxc_nand_ready(nand, 1000) == -1) {
                LOG_ERROR("%s sending timeout", text);
                return ERROR_NAND_OPERATION_FAILED;
        }
@@ -783,12 +854,62 @@ static int validate_target_state(struct nand_device *nand)
        return ERROR_OK;
 }
 
+int ecc_status_v1(struct nand_device *nand)
+{
+       struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
+       struct target *target = nand->target;
+       uint16_t ecc_status;
+
+       target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
+       switch (ecc_status & 0x000c) {
+       case 1 << 2:
+               LOG_INFO("main area read with 1 (correctable) error");
+               break;
+       case 2 << 2:
+               LOG_INFO("main area read with more than 1 (incorrectable) error");
+               return ERROR_NAND_OPERATION_FAILED;
+               break;
+       }
+       switch (ecc_status & 0x0003) {
+       case 1:
+               LOG_INFO("spare area read with 1 (correctable) error");
+               break;
+       case 2:
+               LOG_INFO("main area read with more than 1 (incorrectable) error");
+               return ERROR_NAND_OPERATION_FAILED;
+               break;
+       }
+       return ERROR_OK;
+}
+
+int ecc_status_v2(struct nand_device *nand)
+{
+       struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
+       struct target *target = nand->target;
+       uint16_t ecc_status;
+       uint8_t no_subpages;
+       uint8_t err;
+
+       no_subpages = nand->page_size >> 9;
+
+       target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
+       do {
+               err = ecc_status & 0xF;
+               if (err > 4) {
+                       LOG_INFO("UnCorrectable RS-ECC Error");
+                       return ERROR_NAND_OPERATION_FAILED;
+               } else if (err > 0)
+                       LOG_INFO("%d Symbol Correctable RS-ECC Error", err);
+               ecc_status >>= 4;
+       } while (--no_subpages);
+       return ERROR_OK;
+}
+
 static int do_data_output(struct nand_device *nand)
 {
        struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
        struct target *target = nand->target;
        int poll_result;
-       uint16_t ecc_status;
        switch (mxc_nf_info->fin) {
        case MXC_NF_FIN_DATAOUT:
                /*
@@ -803,27 +924,15 @@ static int do_data_output(struct nand_device *nand)
                /*
                 * ECC stuff
                 */
-               if ((mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE) &&
+               if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE &&
                        mxc_nf_info->flags.hw_ecc_enabled) {
-                       target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
-                       switch (ecc_status & 0x000c) {
-                       case 1 << 2:
-                               LOG_INFO("main area readed with 1 (correctable) error");
-                               break;
-                       case 2 << 2:
-                               LOG_INFO("main area readed with more than 1 (incorrectable) error");
-                               return ERROR_NAND_OPERATION_FAILED;
-                                       break;
-                       }
-                       switch (ecc_status & 0x0003) {
-                       case 1:
-                               LOG_INFO("spare area readed with 1 (correctable) error");
-                               break;
-                       case 2:
-                               LOG_INFO("main area readed with more than 1 (incorrectable) error");
-                               return ERROR_NAND_OPERATION_FAILED;
-                               break;
-                       }
+                       int ecc_status;
+                       if (nfc_is_v1())
+                               ecc_status = ecc_status_v1(nand);
+                       else
+                               ecc_status = ecc_status_v2(nand);
+                       if (ecc_status != ERROR_OK)
+                               return ecc_status;
                }
                break;
        case MXC_NF_FIN_NONE:
index 77854b953b7b8973878f09fb5604ce7e2b427d6b..45d9ecb87b3dc08349801535a7f857052796adaf 100644 (file)
  * Many thanks to Ben Dooks for writing s3c24xx driver.
  */
 
-#define                MXC_NF_BUFSIZ                           (mxc_nf_info->mxc_base_addr + 0xe00)
-#define                MXC_NF_BUFADDR                          (mxc_nf_info->mxc_base_addr + 0xe04)
-#define                MXC_NF_FADDR                            (mxc_nf_info->mxc_base_addr + 0xe06)
-#define                MXC_NF_FCMD                                     (mxc_nf_info->mxc_base_addr + 0xe08)
-#define                MXC_NF_BUFCFG                           (mxc_nf_info->mxc_base_addr + 0xe0a)
-#define                MXC_NF_ECCSTATUS                        (mxc_nf_info->mxc_base_addr + 0xe0c)
-#define                MXC_NF_ECCMAINPOS                       (mxc_nf_info->mxc_base_addr + 0xe0e)
-#define                MXC_NF_ECCSPAREPOS                      (mxc_nf_info->mxc_base_addr + 0xe10)
-#define                MXC_NF_FWP                                      (mxc_nf_info->mxc_base_addr + 0xe12)
-#define                MXC_NF_LOCKSTART                        (mxc_nf_info->mxc_base_addr + 0xe14)
-#define                MXC_NF_LOCKEND                          (mxc_nf_info->mxc_base_addr + 0xe16)
-#define                MXC_NF_FWPSTATUS                        (mxc_nf_info->mxc_base_addr + 0xe18)
+#define                MXC_NF_BUFSIZ                           (mxc_nf_info->mxc_regs_addr + 0x00)
+#define                MXC_NF_BUFADDR                          (mxc_nf_info->mxc_regs_addr + 0x04)
+#define                MXC_NF_FADDR                            (mxc_nf_info->mxc_regs_addr + 0x06)
+#define                MXC_NF_FCMD                                     (mxc_nf_info->mxc_regs_addr + 0x08)
+#define                MXC_NF_BUFCFG                           (mxc_nf_info->mxc_regs_addr + 0x0a)
+#define                MXC_NF_ECCSTATUS                        (mxc_nf_info->mxc_regs_addr + 0x0c)
+#define                MXC_NF_ECCMAINPOS                       (mxc_nf_info->mxc_regs_addr + 0x0e)
+#define                MXC_NF_ECCSPAREPOS                      (mxc_nf_info->mxc_regs_addr + 0x10)
+#define                MXC_NF_FWP                                      (mxc_nf_info->mxc_regs_addr + 0x12)
+#define                MXC_NF_V1_UNLOCKSTART           (mxc_nf_info->mxc_regs_addr + 0x14)
+#define                MXC_NF_V1_UNLOCKEND                     (mxc_nf_info->mxc_regs_addr + 0x16)
+#define                MXC_NF_V2_UNLOCKSTART0          (mxc_nf_info->mxc_regs_addr + 0x20)
+#define                MXC_NF_V2_UNLOCKSTART1          (mxc_nf_info->mxc_regs_addr + 0x24)
+#define                MXC_NF_V2_UNLOCKSTART2          (mxc_nf_info->mxc_regs_addr + 0x28)
+#define                MXC_NF_V2_UNLOCKSTART3          (mxc_nf_info->mxc_regs_addr + 0x2c)
+#define                MXC_NF_V2_UNLOCKEND0            (mxc_nf_info->mxc_regs_addr + 0x22)
+#define                MXC_NF_V2_UNLOCKEND1            (mxc_nf_info->mxc_regs_addr + 0x26)
+#define                MXC_NF_V2_UNLOCKEND2            (mxc_nf_info->mxc_regs_addr + 0x2a)
+#define                MXC_NF_V2_UNLOCKEND3            (mxc_nf_info->mxc_regs_addr + 0x2e)
+#define                MXC_NF_FWPSTATUS                        (mxc_nf_info->mxc_regs_addr + 0x18)
  /*
   * all bits not marked as self-clearing bit
   */
-#define                MXC_NF_CFG1                                     (mxc_nf_info->mxc_base_addr + 0xe1a)
-#define                MXC_NF_CFG2                                     (mxc_nf_info->mxc_base_addr + 0xe1c)
+#define                MXC_NF_CFG1                                     (mxc_nf_info->mxc_regs_addr + 0x1a)
+#define                MXC_NF_CFG2                                     (mxc_nf_info->mxc_regs_addr + 0x1c)
 
 #define                MXC_NF_MAIN_BUFFER0                     (mxc_nf_info->mxc_base_addr + 0x0000)
 #define                MXC_NF_MAIN_BUFFER1                     (mxc_nf_info->mxc_base_addr + 0x0200)
 #define                MXC_NF_MAIN_BUFFER2                     (mxc_nf_info->mxc_base_addr + 0x0400)
 #define                MXC_NF_MAIN_BUFFER3                     (mxc_nf_info->mxc_base_addr + 0x0600)
-#define                MXC_NF_SPARE_BUFFER0            (mxc_nf_info->mxc_base_addr + 0x0800)
-#define                MXC_NF_SPARE_BUFFER1            (mxc_nf_info->mxc_base_addr + 0x0810)
-#define                MXC_NF_SPARE_BUFFER2            (mxc_nf_info->mxc_base_addr + 0x0820)
-#define                MXC_NF_SPARE_BUFFER3            (mxc_nf_info->mxc_base_addr + 0x0830)
+#define                MXC_NF_V1_SPARE_BUFFER0         (mxc_nf_info->mxc_base_addr + 0x0800)
+#define                MXC_NF_V1_SPARE_BUFFER1         (mxc_nf_info->mxc_base_addr + 0x0810)
+#define                MXC_NF_V1_SPARE_BUFFER2         (mxc_nf_info->mxc_base_addr + 0x0820)
+#define                MXC_NF_V1_SPARE_BUFFER3         (mxc_nf_info->mxc_base_addr + 0x0830)
+#define                MXC_NF_V2_MAIN_BUFFER4          (mxc_nf_info->mxc_base_addr + 0x0800)
+#define                MXC_NF_V2_MAIN_BUFFER5          (mxc_nf_info->mxc_base_addr + 0x0a00)
+#define                MXC_NF_V2_MAIN_BUFFER6          (mxc_nf_info->mxc_base_addr + 0x0c00)
+#define                MXC_NF_V2_MAIN_BUFFER7          (mxc_nf_info->mxc_base_addr + 0x0e00)
+#define                MXC_NF_V2_SPARE_BUFFER0         (mxc_nf_info->mxc_base_addr + 0x1000)
+#define                MXC_NF_V2_SPARE_BUFFER1         (mxc_nf_info->mxc_base_addr + 0x1040)
+#define                MXC_NF_V2_SPARE_BUFFER2         (mxc_nf_info->mxc_base_addr + 0x1080)
+#define                MXC_NF_V2_SPARE_BUFFER3         (mxc_nf_info->mxc_base_addr + 0x10c0)
+#define                MXC_NF_V2_SPARE_BUFFER4         (mxc_nf_info->mxc_base_addr + 0x1100)
+#define                MXC_NF_V2_SPARE_BUFFER5         (mxc_nf_info->mxc_base_addr + 0x1140)
+#define                MXC_NF_V2_SPARE_BUFFER6         (mxc_nf_info->mxc_base_addr + 0x1180)
+#define                MXC_NF_V2_SPARE_BUFFER7         (mxc_nf_info->mxc_base_addr + 0x11c0)
 #define                MXC_NF_MAIN_BUFFER_LEN          512
 #define                MXC_NF_SPARE_BUFFER_LEN         16
-#define                MXC_NF_LAST_BUFFER_ADDR         ((MXC_NF_SPARE_BUFFER3) + \
+#define                MXC_NF_SPARE_BUFFER_MAX         64
+#define                MXC_NF_V1_LAST_BUFFADDR         ((MXC_NF_V1_SPARE_BUFFER3) + \
+       MXC_NF_SPARE_BUFFER_LEN - 2)
+#define                MXC_NF_V2_LAST_BUFFADDR         ((MXC_NF_V2_SPARE_BUFFER7) + \
        MXC_NF_SPARE_BUFFER_LEN - 2)
 
 /* bits in MXC_NF_CFG1 register */
+#define                MXC_NF_BIT_ECC_4BIT                     (1<<0)
 #define                MXC_NF_BIT_SPARE_ONLY_EN        (1<<2)
 #define                MXC_NF_BIT_ECC_EN                       (1<<3)
 #define                MXC_NF_BIT_INT_DIS                      (1<<4)
 #define                MXC_NF_BIT_BE_EN                        (1<<5)
 #define                MXC_NF_BIT_RESET_EN                     (1<<6)
 #define                MXC_NF_BIT_FORCE_CE                     (1<<7)
+#define                MXC_NF_V2_CFG1_PPB(x)           (((x) & 0x3) << 9)
 
 /* bits in MXC_NF_CFG2 register */
 
 
 #define                MXC_CCM_CGR2                            0x53f80028
 #define                MXC_GPR                                         0x43fac008
-/*#define              MXC_PCSR                                        0x53f8000c*/
-#define                MXC_FMCR                                        0x10027814
-#define                MXC_FMCR_NF_16BIT_SEL           (1<<4)
-#define                MXC_FMCR_NF_FMS                         (1<<5)
+#define                MX2_FMCR                                        0x10027814
+#define                MX2_FMCR_NF_16BIT_SEL           (1<<4)
+#define                MX2_FMCR_NF_FMS                         (1<<5)
+#define                MX3_PCSR                                        0x53f8000c
+#define                MX3_PCSR_NF_16BIT_SEL           (1<<31)
+#define                MX3_PCSR_NF_FMS                         (1<<30)
+#define                MX35_RCSR                                       0x53f80018
+#define                MX35_RCSR_NF_16BIT_SEL          (1<<14)
+#define                MX35_RCSR_NF_FMS                        (1<<8)
+#define                MX35_RCSR_NF_4K                         (1<<9)
+
+enum mxc_version {
+       MXC_VERSION_UKWN = 0,
+       MXC_VERSION_MX27 = 1,
+       MXC_VERSION_MX31 = 2,
+       MXC_VERSION_MX35 = 4
+};
 
 enum mxc_dataout_type {
        MXC_NF_DATAOUT_PAGE = 1,
@@ -111,7 +149,9 @@ struct mxc_nf_flags {
 };
 
 struct mxc_nf_controller {
+       enum mxc_version mxc_version;
        uint32_t mxc_base_addr;
+       uint32_t mxc_regs_addr;
        enum mxc_dataout_type optype;
        enum mxc_nf_finalize_action fin;
        struct mxc_nf_flags flags;

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)