]> git.sur5r.net Git - openocd/blobdiff - src/flash/nor/cfi.c
flash: require unique flash bank name
[openocd] / src / flash / nor / cfi.c
index 4dad7b6fe8d210701683bf13cb9dca7ca3256a18..2235c85ce39f16e83eae9fac580952b0b2cef78f 100644 (file)
@@ -3,6 +3,7 @@
  *   Dominic.Rath@gmx.de                                                   *
  *   Copyright (C) 2009 Michael Schwingen                                  *
  *   michael@schwingen.org                                                 *
+ *   Copyright (C) 2010 Ã˜yvind Harboe <oyvind.harboe@zylin.com>            *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -56,6 +57,7 @@ static const struct cfi_fixup cfi_0002_fixups[] = {
        {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
+   {CFI_MFR_FUJITSU, 0x22ea, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
@@ -103,7 +105,6 @@ static __inline__ uint32_t flash_address(struct flash_bank *bank, int sector, ui
                }
                return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
        }
-
 }
 
 static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
@@ -231,6 +232,35 @@ static uint32_t cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offs
                                data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
 }
 
+static int cfi_reset(struct flash_bank *bank)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+       int retval = ERROR_OK;
+
+       if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       if (cfi_info->manufacturer == 0x20 &&
+                       (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E))
+       {
+               /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state
+                * so we send an extra 0xF0 reset to fix the bug */
+               if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00))) != ERROR_OK)
+               {
+                       return retval;
+               }
+       }
+
+       return retval;
+}
+
 static void cfi_intel_clear_status_register(struct flash_bank *bank)
 {
        struct target *target = bank->target;
@@ -334,11 +364,7 @@ static int cfi_read_intel_pri_ext(struct flash_bank *bank)
 
        if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
        {
-               if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+               if ((retval = cfi_reset(bank)) != ERROR_OK)
                {
                        return retval;
                }
@@ -598,12 +624,8 @@ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
                return ERROR_FLASH_BANK_INVALID;
        }
 
-       uint16_t chip_width, bus_width;
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], bus_width);
-       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[4], chip_width);
-
-       if ((chip_width > CFI_MAX_CHIP_WIDTH)
-                       || (bus_width > CFI_MAX_BUS_WIDTH))
+       if ((bank->chip_width > CFI_MAX_CHIP_WIDTH)
+                       || (bank->bus_width > CFI_MAX_BUS_WIDTH))
        {
                LOG_ERROR("chip and bus width have to specified in bytes");
                return ERROR_FLASH_BANK_INVALID;
@@ -855,6 +877,17 @@ static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int la
         */
        if ((!set) && (!(pri_ext->feature_support & 0x20)))
        {
+               /* FIX!!! this code path is broken!!!
+                *
+                * The correct approach is:
+                *
+                * 1. read out current protection status
+                *
+                * 2. override read out protection status w/unprotected.
+                *
+                * 3. re-protect what should be protected.
+                *
+                */
                for (i = 0; i < bank->num_sectors; i++)
                {
                        if (bank->sectors[i].is_protected == 1)
@@ -891,6 +924,7 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
 
        if ((first < 0) || (last < first) || (last >= bank->num_sectors))
        {
+               LOG_ERROR("Invalid sector range");
                return ERROR_FLASH_SECTOR_INVALID;
        }
 
@@ -901,14 +935,12 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
        {
                case 1:
                case 3:
-                       cfi_intel_protect(bank, set, first, last);
+                       return cfi_intel_protect(bank, set, first, last);
                        break;
                default:
                        LOG_ERROR("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
-                       break;
+                       return ERROR_FAIL;
        }
-
-       return ERROR_OK;
 }
 
 /* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
@@ -1120,7 +1152,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
        /* Get a workspace buffer for the data to flash starting with 32k size.
           Half size until buffer would be smaller 256 Bytem then fail back */
        /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
        {
                buffer_size /= 2;
                if (buffer_size <= 256)
@@ -1145,7 +1177,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
        busy_pattern_val  = cfi_command_val(bank, 0x80);
        error_pattern_val = cfi_command_val(bank, 0x7e);
 
-       LOG_INFO("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
+       LOG_DEBUG("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
 
        /* Programming main loop */
        while (count > 0)
@@ -1166,7 +1198,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint3
                buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
                buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
 
-               LOG_INFO("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
+               LOG_DEBUG("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32 , thisrun_count, address);
 
                /* Execute algorithm, assume breakpoint for last instruction */
                retval = target_run_algorithm(target, 0, NULL, 7, reg_params,
@@ -1448,7 +1480,7 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, ui
        }
        /* the following code still assumes target code is fixed 24*4 bytes */
 
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
        {
                buffer_size /= 2;
                if (buffer_size <= 256)
@@ -1970,11 +2002,7 @@ static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
        }
 
        /* return to read array mode, so we can read from flash again for padding */
-       if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
-       {
-               return retval;
-       }
-       if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+       if ((retval = cfi_reset(bank)) != ERROR_OK)
        {
                return retval;
        }
@@ -2008,11 +2036,7 @@ static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
        }
 
        /* return to read array mode */
-       if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
-       {
-               return retval;
-       }
-       return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0));
+       return cfi_reset(bank);
 }
 
 static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *bank, void *param)
@@ -2076,11 +2100,7 @@ static int cfi_query_string(struct flash_bank *bank, int address)
 
        if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
        {
-               if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+               if ((retval = cfi_reset(bank)) != ERROR_OK)
                {
                        return retval;
                }
@@ -2161,11 +2181,7 @@ static int cfi_probe(struct flash_bank *bank)
 
        LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id);
        /* switch back to read array mode */
-       if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00))) != ERROR_OK)
-       {
-               return retval;
-       }
-       if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x00))) != ERROR_OK)
+       if ((retval = cfi_reset(bank)) != ERROR_OK)
        {
                return retval;
        }
@@ -2282,11 +2298,7 @@ static int cfi_probe(struct flash_bank *bank)
                /* return to read array mode
                 * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
                 */
-               if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
-               {
-                       return retval;
-               }
-               if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
+               if ((retval = cfi_reset(bank)) != ERROR_OK)
                {
                        return retval;
                }
@@ -2370,7 +2382,6 @@ static int cfi_auto_probe(struct flash_bank *bank)
        return cfi_probe(bank);
 }
 
-
 static int cfi_intel_protect_check(struct flash_bank *bank)
 {
        int retval;