- convert all files to unix line-ending
[fw/openocd] / src / flash / cfi.c
index cc5a69e1c81b2b4c9e6f0583bac6b55c31a36605..88e8e63db44a68d12e3f7a382e9cc5a58065072d 100644 (file)
@@ -43,6 +43,7 @@ int cfi_erase(struct flash_bank_s *bank, int first, int last);
 int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
 int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
 int cfi_probe(struct flash_bank_s *bank);
+int cfi_auto_probe(struct flash_bank_s *bank);
 int cfi_erase_check(struct flash_bank_s *bank);
 int cfi_protect_check(struct flash_bank_s *bank);
 int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
@@ -64,6 +65,7 @@ flash_driver_t cfi_flash =
        .protect = cfi_protect,
        .write = cfi_write,
        .probe = cfi_probe,
+       .auto_probe = cfi_auto_probe,
        .erase_check = cfi_erase_check,
        .protect_check = cfi_protect_check,
        .info = cfi_info
@@ -87,6 +89,7 @@ cfi_fixup_t cfi_jedec_fixups[] = {
        {CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL},
        {CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL},
        {CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL},
+       {CFI_MFR_SST, 0x2780, cfi_fixup_non_cfi, NULL},
        {CFI_MFR_ST, 0x00D5, cfi_fixup_non_cfi, NULL},
        {CFI_MFR_ST, 0x00D6, cfi_fixup_non_cfi, NULL},
        {CFI_MFR_AMD, 0x2223, cfi_fixup_non_cfi, NULL},
@@ -100,6 +103,7 @@ cfi_fixup_t cfi_0002_fixups[] = {
        {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {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_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
        {0, 0, NULL, NULL}
@@ -588,7 +592,8 @@ int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
 
 int cfi_register_commands(struct command_context_s *cmd_ctx)
 {
-       /*command_t *cfi_cmd = */register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
+       /*command_t *cfi_cmd = */
+       register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, "flash bank cfi <base> <size> <chip_width> <bus_width> <targetNum> [jedec_probe/x16_as_x8]");
        /*
        register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
                                         "print part id of cfi flash bank <num>");
@@ -612,15 +617,16 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
        if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH)
                || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH))
        {
-               ERROR("chip and bus width have to specified in byte");
+               ERROR("chip and bus width have to specified in bytes");
                return ERROR_FLASH_BANK_INVALID;
        }
 
        cfi_info = malloc(sizeof(cfi_flash_bank_t));
+       cfi_info->probed = 0;
        bank->driver_priv = cfi_info;
-  
-  cfi_info->write_algorithm       = NULL;
-  cfi_info->erase_check_algorithm = NULL;
+
+       cfi_info->write_algorithm = NULL;
+       cfi_info->erase_check_algorithm = NULL;
 
        cfi_info->x16_as_x8 = 0;
        cfi_info->jedec_probe = 0;
@@ -1015,14 +1021,14 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
        armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
        armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-  
+
        /* If we are setting up the write_algorith, we need target_code_src */
        /* if not we only need target_code_size.                                                                                                                */
        /*                                                                                                                                                                                                                                                                      */
        /* However, we don't want to create multiple code paths, so we                  */
        /* do the unecessary evaluation of target_code_src, which the                   */
        /* compiler will probably nicely optimize away if not needed                            */
-  
+
        /* prepare algorithm code for target endian */
        switch (bank->bus_width)
        {
@@ -1042,7 +1048,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
-  
+
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
@@ -1369,11 +1375,11 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
                }
 
                /* allocate working area */
-               if (target_alloc_working_area(target, 24 * 4,
-                       &cfi_info->write_algorithm) != ERROR_OK)
+               retval=target_alloc_working_area(target, 24 * 4,
+                               &cfi_info->write_algorithm);
+               if (retval != ERROR_OK)
                {
-                       WARNING("no working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+                       return retval;
                }
 
                /* write algorithm code to working area */
@@ -1639,11 +1645,6 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
        int i;
        int retval;
 
-       if (bank->target->state != TARGET_HALTED)
-       {
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
        if (offset + count > bank->size)
                return ERROR_FLASH_DST_OUT_OF_BANK;
 
@@ -1739,6 +1740,8 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
                                {
                                        INFO("Programming at %08x, count %08x bytes remaining", write_p, count);
                                }
+#if 0
+                               /* NB! this is broken for spansion! */
                                if ((count > bufferwsize) && !(write_p & buffermask))
                                {
                                        retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
@@ -1750,6 +1753,7 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
                                        count -= buffersize;
                                }
                                else
+#endif
                                {
                                        for (i = 0; i < bank->bus_width; i++)
                                                current_word[i] = 0;
@@ -1864,6 +1868,8 @@ int cfi_probe(struct flash_bank_s *bank)
        u32 unlock1 = 0x555;
        u32 unlock2 = 0x2aa;
 
+       cfi_info->probed = 0;
+
        /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses,
         * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa
         */
@@ -2071,10 +2077,20 @@ int cfi_probe(struct flash_bank_s *bank)
                        }
                }
        }
+       
+       cfi_info->probed = 1;
 
        return ERROR_OK;
 }
 
+int cfi_auto_probe(struct flash_bank_s *bank)
+{
+       cfi_flash_bank_t *cfi_info = bank->driver_priv;
+       if (cfi_info->probed)
+               return ERROR_OK;
+       return cfi_probe(bank);
+}
+
 int cfi_erase_check(struct flash_bank_s *bank)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;