add FLASH_BANK_COMMAND_HANDLER macro
[openocd.git] / src / flash / cfi.c
index 529890740cac8d893d14273d8aaecbe52ff305a6..b448a300b9b72dbd4916fea240c460d66d62596f 100644 (file)
 #include "binarybuffer.h"
 
 
-static int cfi_register_commands(struct command_context_s *cmd_ctx);
-static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-static int cfi_erase(struct flash_bank_s *bank, int first, int last);
-static int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
-static int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
-static int cfi_probe(struct flash_bank_s *bank);
-static int cfi_auto_probe(struct flash_bank_s *bank);
-static int cfi_protect_check(struct flash_bank_s *bank);
-static int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-//static int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
 #define CFI_MAX_BUS_WIDTH      4
 #define CFI_MAX_CHIP_WIDTH     4
 
 /* defines internal maximum size for code fragment in cfi_intel_write_block() */
 #define CFI_MAX_INTEL_CODESIZE 256
 
-flash_driver_t cfi_flash =
-{
-       .name = "cfi",
-       .register_commands = cfi_register_commands,
-       .flash_bank_command = cfi_flash_bank_command,
-       .erase = cfi_erase,
-       .protect = cfi_protect,
-       .write = cfi_write,
-       .probe = cfi_probe,
-       .auto_probe = cfi_auto_probe,
-       .erase_check = default_flash_blank_check,
-       .protect_check = cfi_protect_check,
-       .info = cfi_info
-};
-
 static cfi_unlock_addresses_t cfi_unlock_addresses[] =
 {
        [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
@@ -74,7 +47,7 @@ static void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
 static void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
 
 /* fixup after reading cmdset 0002 primary query table */
-static cfi_fixup_t cfi_0002_fixups[] = {
+static const cfi_fixup_t cfi_0002_fixups[] = {
        {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {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]},
@@ -90,14 +63,14 @@ static cfi_fixup_t cfi_0002_fixups[] = {
 };
 
 /* fixup after reading cmdset 0001 primary query table */
-static cfi_fixup_t cfi_0001_fixups[] = {
+static const cfi_fixup_t cfi_0001_fixups[] = {
        {0, 0, NULL, NULL}
 };
 
-static void cfi_fixup(flash_bank_t *bank, cfi_fixup_t *fixups)
+static void cfi_fixup(flash_bank_t *bank, const cfi_fixup_t *fixups)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       cfi_fixup_t *f;
+       const cfi_fixup_t *f;
 
        for (f = fixups; f->fixup; f++)
        {
@@ -114,7 +87,7 @@ static __inline__ uint32_t flash_address(flash_bank_t *bank, int sector, uint32_
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
 
-       if (cfi_info->x16_as_x8) offset*=2;
+       if (cfi_info->x16_as_x8) offset *= 2;
 
        /* while the sector list isn't built, only accesses to sector 0 work */
        if (sector == 0)
@@ -212,9 +185,9 @@ static uint16_t cfi_query_u16(flash_bank_t *bank, int sector, uint32_t offset)
        if (cfi_info->x16_as_x8)
        {
                uint8_t i;
-               for(i=0;i<2;i++)
-                       target_read_memory(target, flash_address(bank, sector, offset+i), bank->bus_width, 1,
-                               &data[i*bank->bus_width] );
+               for (i = 0;i < 2;i++)
+                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
+                               &data[i*bank->bus_width]);
        }
        else
                target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
@@ -234,9 +207,9 @@ static uint32_t cfi_query_u32(flash_bank_t *bank, int sector, uint32_t offset)
        if (cfi_info->x16_as_x8)
        {
                uint8_t i;
-               for(i=0;i<4;i++)
-                       target_read_memory(target, flash_address(bank, sector, offset+i), bank->bus_width, 1,
-                               &data[i*bank->bus_width] );
+               for (i = 0;i < 4;i++)
+                       target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1,
+                               &data[i*bank->bus_width]);
        }
        else
                target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
@@ -378,9 +351,9 @@ static int cfi_read_intel_pri_ext(flash_bank_t *bank)
        pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
        pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
 
-       LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", 
-                 pri_ext->feature_support, 
-                 pri_ext->suspend_cmd_support, 
+       LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x",
+                 pri_ext->feature_support,
+                 pri_ext->suspend_cmd_support,
                  pri_ext->blk_status_reg_mask);
 
        pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
@@ -641,8 +614,12 @@ static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
                return ERROR_FLASH_BANK_INVALID;
        }
 
-       if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH)
-               || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH))
+       uint16_t chip_width, bus_width;
+       COMMAND_PARSE_NUMBER(u16, args[3], bus_width);
+       COMMAND_PARSE_NUMBER(u16, args[4], chip_width);
+
+       if ((chip_width > CFI_MAX_CHIP_WIDTH)
+                       || (bus_width > CFI_MAX_BUS_WIDTH))
        {
                LOG_ERROR("chip and bus width have to specified in bytes");
                return ERROR_FLASH_BANK_INVALID;
@@ -1011,10 +988,10 @@ static void cfi_add_byte(struct flash_bank_s *bank, uint8_t *word, uint8_t byte)
 static void cfi_fix_code_endian(target_t *target, uint8_t *dest, const uint32_t *src, uint32_t count)
 {
        uint32_t i;
-       for (i=0; i< count; i++)
+       for (i = 0; i< count; i++)
        {
                target_buffer_set_u32(target, dest, *src);
-               dest+=4;
+               dest += 4;
                src++;
        }
 }
@@ -1125,11 +1102,11 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
        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                            */
+       /* 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)
@@ -1154,7 +1131,7 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
-               if ( target_code_size > sizeof(target_code) )
+               if (target_code_size > sizeof(target_code))
                {
                        LOG_WARNING("Internal error - target code buffer to small. Increase CFI_MAX_INTEL_CODESIZE and recompile.");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -1206,7 +1183,7 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
        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_INFO("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size);
 
        /* Programming main loop */
        while (count > 0)
@@ -1227,7 +1204,7 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
                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_INFO("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,
@@ -1384,6 +1361,31 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
                0xeafffffe      /* b    81ac <sp_16_done>              */
                };
 
+               static const uint32_t word_16_code_dq7only[] = {
+                               /* <sp_16_code>:                       */
+               0xe0d050b2,     /* ldrh r5, [r0], #2                   */
+               0xe1c890b0,     /* strh r9, [r8]                       */
+               0xe1cab0b0,     /* strh r11, [r10]                              */
+               0xe1c830b0,     /* strh r3, [r8]                                */
+               0xe1c150b0,     /* strh r5, [r1]                       */
+               0xe1a00000,     /* nop                  (mov r0,r0)    */
+                               /*                                     */
+                               /* <sp_16_busy>:                       */
+               0xe1d160b0,     /* ldrh r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe2177080,     /* ands r7, #0x80                      */
+               0x1afffffb,     /* bne  8168 <sp_16_busy>              */
+                               /*                                     */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
+               0x0a000001,     /* beq  81ac <sp_16_done>              */
+               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
+               0xeafffff0,     /* b    8158 <sp_16_code>              */
+                               /*                                     */
+                               /* 000081ac <sp_16_done>:              */
+               0xeafffffe      /* b    81ac <sp_16_done>              */
+               };
+
                static const uint32_t word_8_code[] = {
                                /* 000081b0 <sp_16_code_end>:          */
                0xe4d05001,     /* ldrb r5, [r0], #1                   */
@@ -1422,37 +1424,49 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
        armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
        armv4_5_info.core_state = ARMV4_5_STATE_ARM;
 
+       int target_code_size;
+       const uint32_t *target_code_src;
+
+       switch (bank->bus_width)
+       {
+       case 1 :
+               target_code_src = word_8_code;
+               target_code_size = sizeof(word_8_code);
+               break;
+       case 2 :
+               /* Check for DQ5 support */
+               if( cfi_info->status_poll_mask & (1 << 5) )
+               {
+                       target_code_src = word_16_code;
+                       target_code_size = sizeof(word_16_code);
+               }
+               else
+               {
+                       /* No DQ5 support. Use DQ7 DATA# polling only. */
+                       target_code_src = word_16_code_dq7only;
+                       target_code_size = sizeof(word_16_code_dq7only);
+               }
+               break;
+       case 4 :
+               target_code_src = word_32_code;
+               target_code_size = sizeof(word_32_code);
+               break;
+       default:
+               LOG_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)
        {
                uint8_t *target_code;
-               int target_code_size;
-               const uint32_t *src;
 
                /* convert bus-width dependent algorithm code to correct endiannes */
-               switch (bank->bus_width)
-               {
-               case 1:
-                       src = word_8_code;
-                       target_code_size = sizeof(word_8_code);
-                       break;
-               case 2:
-                       src = word_16_code;
-                       target_code_size = sizeof(word_16_code);
-                       break;
-               case 4:
-                       src = word_32_code;
-                       target_code_size = sizeof(word_32_code);
-                       break;
-               default:
-                       LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
                target_code = malloc(target_code_size);
-               cfi_fix_code_endian(target, target_code, src, target_code_size / 4);
+               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
 
                /* allocate working area */
-               retval=target_alloc_working_area(target, target_code_size,
+               retval = target_alloc_working_area(target, target_code_size,
                                &cfi_info->write_algorithm);
                if (retval != ERROR_OK)
                {
@@ -1515,7 +1529,7 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
 
                retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
                                                     cfi_info->write_algorithm->address,
-                                                    cfi_info->write_algorithm->address + ((24 * 4) - 4),
+                                                    cfi_info->write_algorithm->address + ((target_code_size) - 4),
                                                     10000, &armv4_5_info);
 
                status = buf_get_u32(reg_params[5].value, 0, 32);
@@ -1532,7 +1546,7 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
                count -= thisrun_count;
        }
 
-       target_free_working_area(target, source);
+       target_free_all_working_areas(target);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
@@ -1597,7 +1611,7 @@ static int cfi_intel_write_words(struct flash_bank_s *bank, uint8_t *word, uint3
        /* Check for valid range */
        if (address & buffermask)
        {
-               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary", 
+               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32 " not aligned to 2^%d boundary",
                          bank->base, address, cfi_info->max_buf_write_size);
                return ERROR_FLASH_OPERATION_FAILED;
        }
@@ -1883,7 +1897,7 @@ int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint3
        write_p = address & ~(bank->bus_width - 1);
        if ((align = address - write_p) != 0)
        {
-               LOG_INFO("Fixup %d unaligned head bytes", align );
+               LOG_INFO("Fixup %d unaligned head bytes", align);
 
                for (i = 0; i < bank->bus_width; i++)
                        current_word[i] = 0;
@@ -1987,7 +2001,7 @@ int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint3
                                                buffer += buffersize;
                                                write_p += buffersize;
                                                count -= buffersize;
-                                               fallback=0;
+                                               fallback = 0;
                                        }
                                }
                                /* try the slow way? */
@@ -2029,7 +2043,7 @@ int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint3
        /* handle unaligned tail bytes */
        if (count > 0)
        {
-               LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count );
+               LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
 
                copy_p = write_p;
                for (i = 0; i < bank->bus_width; i++)
@@ -2106,6 +2120,45 @@ static void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param)
        pri_ext->_unlock2 = unlock_addresses->unlock2;
 }
 
+
+static int cfi_query_string(struct flash_bank_s *bank, int address)
+{
+       cfi_flash_bank_t *cfi_info = bank->driver_priv;
+       target_t *target = bank->target;
+       int retval;
+       uint8_t command[8];
+
+       cfi_command(bank, 0x98, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
+       cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
+       cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
+
+       LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
+
+       if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not probe bank: no QRY");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       return ERROR_OK;
+}
+
 static int cfi_probe(struct flash_bank_s *bank)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
@@ -2172,7 +2225,7 @@ static int cfi_probe(struct flash_bank_s *bank)
                {
                        return retval;
                }
-               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x02), &cfi_info->device_id)) != ERROR_OK)
+               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x01), &cfi_info->device_id)) != ERROR_OK)
                {
                        return retval;
                }
@@ -2199,6 +2252,8 @@ static int cfi_probe(struct flash_bank_s *bank)
         */
        if (cfi_info->not_cfi == 0)
        {
+               int retval;
+
                /* enter CFI query mode
                 * according to JEDEC Standard No. 68.01,
                 * a single bus sequence with address = 0x55, data = 0x98 should put
@@ -2206,33 +2261,21 @@ static int cfi_probe(struct flash_bank_s *bank)
                 *
                 * SST flashes clearly violate this, and we will consider them incompatbile for now
                 */
-               cfi_command(bank, 0x98, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
-               cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
-               cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
 
-               LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
-
-               if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+               retval = cfi_query_string(bank, 0x55);
+               if (retval != ERROR_OK)
                {
-                       cfi_command(bank, 0xf0, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       cfi_command(bank, 0xff, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       LOG_ERROR("Could not probe bank: no QRY");
-                       return ERROR_FLASH_BANK_INVALID;
+                       /*
+                        * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should
+                        * be harmless enough:
+                        *
+                        * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html
+                        */
+                       LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY.");
+                       retval = cfi_query_string(bank, 0x555);
                }
+               if (retval != ERROR_OK)
+                       return retval;
 
                cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
                cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
@@ -2266,7 +2309,7 @@ static int cfi_probe(struct flash_bank_s *bank)
                        (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
                        (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
 
-               cfi_info->dev_size = 1<<cfi_query_u8(bank, 0, 0x27);
+               cfi_info->dev_size = 1 << cfi_query_u8(bank, 0, 0x27);
                cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
                cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
                cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
@@ -2279,9 +2322,9 @@ static int cfi_probe(struct flash_bank_s *bank)
                        for (i = 0; i < cfi_info->num_erase_regions; i++)
                        {
                                cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
-                               LOG_DEBUG("erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "", 
-                                         i, 
-                                         (cfi_info->erase_region_info[i] & 0xffff) + 1, 
+                               LOG_DEBUG("erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "",
+                                         i,
+                                         (cfi_info->erase_region_info[i] & 0xffff) + 1,
                                          (cfi_info->erase_region_info[i] >> 16) * 256);
                        }
                }
@@ -2383,9 +2426,10 @@ static int cfi_probe(struct flash_bank_s *bank)
                                sector++;
                        }
                }
-               if (offset != cfi_info->dev_size)
+               if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width))
                {
-                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", cfi_info->dev_size, offset);
+                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
+                               (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset);
                }
        }
 
@@ -2584,3 +2628,17 @@ static int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
 
        return ERROR_OK;
 }
+
+flash_driver_t cfi_flash = {
+               .name = "cfi",
+               .register_commands = &cfi_register_commands,
+               .flash_bank_command = &cfi_flash_bank_command,
+               .erase = &cfi_erase,
+               .protect = &cfi_protect,
+               .write = &cfi_write,
+               .probe = &cfi_probe,
+               .auto_probe = &cfi_auto_probe,
+               .erase_check = &default_flash_blank_check,
+               .protect_check = &cfi_protect_check,
+               .info = &cfi_info,
+       };

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)