flash/<various>.c: remove useless declarations
[openocd.git] / src / flash / cfi.c
index 4afc58be184d8776e0c780de88404e688494fd7b..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++)
        {
@@ -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;
@@ -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)
@@ -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,34 +1424,46 @@ 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,
@@ -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]);
@@ -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;
@@ -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);
@@ -2585,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)