- fixed arm926 cp15 command bug (thanks to Vincent Palatin for this patch)
[openocd.git] / src / flash / cfi.c
index a90093f4288a6bdac05792d52bae53326c151b00..b8b7eb5409d176839c8d3c2423e41fae4324b87a 100644 (file)
@@ -88,6 +88,12 @@ void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
        int i;
        
+       /* clear whole buffer, to ensure bits that exceed the bus_width
+        * are set to zero
+        */
+       for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
+               cmd_buf[i] = 0;
+
        if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
        {
                for (i = bank->bus_width; i > 0; i--)
@@ -206,10 +212,17 @@ u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
                DEBUG("status: 0x%x", status);
                usleep(1000);
        }
-       
-       DEBUG("status: 0x%x", status);
 
-       if (status != 0x80)
+       /* mask out bit 0 (reserved) */
+       status = status & 0xfe;
+
+       DEBUG("status: 0x%x", status);
+       
+       if ((status & 0x80) != 0x80)
+       {
+               ERROR("timeout while waiting for WSM to become ready");
+       }
+       else if (status != 0x80)
        {
                ERROR("status register: 0x%x", status);
                if (status & 0x2)
@@ -316,7 +329,7 @@ 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, NULL);
        /*      
        register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
                                         "print part id of cfi flash bank <num>");
@@ -349,9 +362,11 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
        cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
        if (!cfi_info->target)
        {
-               ERROR("no target '%i' configured", args[5]);
+               ERROR("no target '%s' configured", args[5]);
                exit(-1);
        }
+       
+       cfi_info->write_algorithm = NULL;
 
        /* bank wasn't probed yet */
        cfi_info->qry[0] = -1;
@@ -362,7 +377,6 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
 int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
        target_t *target = cfi_info->target;
        u8 command[8];
        int i;
@@ -432,8 +446,12 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
        cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
        target_t *target = cfi_info->target;
        u8 command[8];
+       int retry = 0;
        int i;
        
+       /* if the device supports neither legacy lock/unlock (bit 3) nor
+        * instant individual block locking (bit 5).
+        */
        if (!(pri_ext->feature_support & 0x28))
                return ERROR_FLASH_OPERATION_FAILED;
        
@@ -442,21 +460,53 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
        for (i = first; i <= last; i++)
        {
                cfi_command(bank, 0x60, command);
+               DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
                target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
                if (set)
                {
                        cfi_command(bank, 0x01, command);
+                       DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
                        target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
                        bank->sectors[i].is_protected = 1;
                }
                else
                {
                        cfi_command(bank, 0xd0, command);
+                       DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
                        target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
                        bank->sectors[i].is_protected = 0;
                }
-               
-               cfi_intel_wait_status_busy(bank, 100);
+
+               /* instant individual block locking doesn't require reading of the status register */
+               if (!(pri_ext->feature_support & 0x20))
+               {
+                       /* Clear lock bits operation may take up to 1.4s */
+                       cfi_intel_wait_status_busy(bank, 1400);
+               }
+               else
+               {
+                       u8 block_status;
+                       /* read block lock bit, to verify status */
+                       cfi_command(bank, 0x90, command);
+                       target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
+                       block_status = cfi_get_u8(bank, i, 0x2);
+                       
+                       if ((block_status & 0x1) != set)
+                       {
+                               ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status);
+                               cfi_command(bank, 0x70, command);
+                               target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
+                               cfi_intel_wait_status_busy(bank, 10);
+                               
+                               if (retry > 10)
+                                       return ERROR_FLASH_OPERATION_FAILED;
+                               else
+                               {
+                                       i--;
+                                       retry++;        
+                               }
+                       }               
+               }
        }
        
        /* if the device doesn't support individual block lock bits set/clear,
@@ -542,29 +592,40 @@ void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte)
 int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
        target_t *target = cfi_info->target;
-       reg_param_t reg_params[5];
+       reg_param_t reg_params[7];
        armv4_5_algorithm_t armv4_5_info;
        working_area_t *source;
        u32 buffer_size = 32768;
        u8 write_command[CFI_MAX_BUS_WIDTH];
-       int i;
+       u8 busy_pattern[CFI_MAX_BUS_WIDTH];
+       u8 error_pattern[CFI_MAX_BUS_WIDTH];
        int retval;
        
+       /* algorithm register usage:
+        * r0: source address (in RAM)
+        * r1: target address (in Flash)
+        * r2: count
+        * r3: flash write command
+        * r4: status byte (returned to host)
+        * r5: busy test pattern
+        * r6: error test pattern
+        */
+        
        u32 word_32_code[] = {
                0xe4904004,   /* loop:  ldr r4, [r0], #4 */
                0xe5813000,   /*                str r3, [r1] */
                0xe5814000,   /*                str r4, [r1] */
-               0xe5914000,   /* busy   ldr r4, [r1] */
-               0xe3140080,   /*                tst r4, #0x80 */
-               0x0afffffc,   /*                beq busy */
-               0xe314007f,   /*                tst r4, #0x7f */
+               0xe5914000,   /* busy:  ldr r4, [r1] */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
                0x1a000003,   /*                bne done */
                0xe2522001,   /*                subs r2, r2, #1 */
                0x0a000001,   /*                beq done */
                0xe2811004,   /*                add r1, r1 #4 */
-               0xeafffff3,   /*                b loop */
+               0xeafffff2,   /*                b loop */
                0xeafffffe,   /* done:  b -2 */
        };
        
@@ -573,14 +634,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                0xe1c130b0,   /*                strh r3, [r1] */
                0xe1c140b0,   /*                strh r4, [r1] */
                0xe1d140b0,   /* busy   ldrh r4, [r1] */
-               0xe3140080,   /*                tst r4, #0x80 */
-               0x0afffffc,   /*                beq busy */
-               0xe314007f,   /*                tst r4, #0x7f */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
                0x1a000003,   /*                bne done */
                0xe2522001,   /*                subs r2, r2, #1 */
                0x0a000001,   /*                beq done */
                0xe2811002,   /*                add r1, r1 #2 */
-               0xeafffff3,   /*                b loop */
+               0xeafffff2,   /*                b loop */
                0xeafffffe,   /* done:  b -2 */
        };
        
@@ -589,14 +651,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                0xe5c13000,   /*                strb r3, [r1] */
                0xe5c14000,   /*                strb r4, [r1] */
                0xe5d14000,   /* busy   ldrb r4, [r1] */
-               0xe3140080,   /*                tst r4, #0x80 */
-               0x0afffffc,   /*                beq busy */
-               0xe314007f,   /*                tst r4, #0x7f */
+               0xe0047005,   /*                and r7, r4, r5 */
+               0xe1570005,   /*                cmp r7, r5 */
+               0x1afffffb,   /*                bne busy */
+               0xe1140006,   /*                tst r4, r6 */
                0x1a000003,   /*                bne done */
                0xe2522001,   /*                subs r2, r2, #1 */
                0x0a000001,   /*                beq done */
                0xe2811001,   /*                add r1, r1 #1 */
-               0xeafffff3,   /*                b loop */
+               0xeafffff2,   /*                b loop */
                0xeafffffe,   /* done:  b -2 */
        };
        
@@ -609,7 +672,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
-               if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK)
+               if (target_alloc_working_area(target, 4 * 14, &cfi_info->write_algorithm) != ERROR_OK)
                {
                        WARNING("no working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -618,15 +681,15 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                /* write algorithm code to working area */
                if (bank->bus_width == 1)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code);
+                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code);
                }
                else if (bank->bus_width == 2)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code);
+                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code);
                }       
                else if (bank->bus_width == 4)
                {
-                       target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code);
+                       target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code);
                }
                else
                {
@@ -653,6 +716,12 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
        init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
        init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
        init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
+       init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
+
+       cfi_command(bank, 0x40, write_command);
+       cfi_command(bank, 0x80, busy_pattern);
+       cfi_command(bank, 0x7e, error_pattern);
 
        while (count > 0)
        {
@@ -663,16 +732,17 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                buf_set_u32(reg_params[0].value, 0, 32, source->address);
                buf_set_u32(reg_params[1].value, 0, 32, address);
                buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
-               cfi_command(bank, 0x40, write_command);
-               buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
+               buf_set_u32(reg_params[3].value, 0, 32, target_buffer_get_u32(target, write_command));
+               buf_set_u32(reg_params[5].value, 0, 32, target_buffer_get_u32(target, busy_pattern));
+               buf_set_u32(reg_params[6].value, 0, 32, target_buffer_get_u32(target, error_pattern));
        
-               if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (12 * 4), 10000, &armv4_5_info)) != ERROR_OK)
+               if ((retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (13 * 4), 10000, &armv4_5_info)) != ERROR_OK)
                {
                        cfi_intel_clear_status_register(bank);
                        return ERROR_FLASH_OPERATION_FAILED;
                }
        
-               if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80)
+               if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern))
                {
                        /* read status register (outputs debug inforation) */
                        cfi_intel_wait_status_busy(bank, 100);
@@ -685,19 +755,22 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                count -= thisrun_count;
        }
        
+       target_free_working_area(target, source);
+       
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
        destroy_reg_param(&reg_params[3]);
        destroy_reg_param(&reg_params[4]);
-
+       destroy_reg_param(&reg_params[5]);
+       destroy_reg_param(&reg_params[6]);
+       
        return ERROR_OK;
 }
 
 int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
        target_t *target = cfi_info->target;
        u8 command[8];
        
@@ -722,7 +795,6 @@ int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
 int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       target_t *target = cfi_info->target;
        
        switch(cfi_info->pri_id)
        {
@@ -808,6 +880,7 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
                        break;
                default:
                        ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+      retval = ERROR_FLASH_OPERATION_FAILED;
                        break;
        }
        if (retval != ERROR_OK)
@@ -882,6 +955,8 @@ int cfi_probe(struct flash_bank_s *bank)
        cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
        cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
        
+       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);
@@ -928,9 +1003,9 @@ int cfi_probe(struct flash_bank_s *bank)
        cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
        cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
        
-       DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
+       DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
        
-       if (1 << cfi_info->dev_size != bank->size)
+       if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size)
        {
                WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
        }
@@ -959,7 +1034,7 @@ int cfi_probe(struct flash_bank_s *bank)
                        for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
                        {
                                bank->sectors[sector].offset = offset;
-                               bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256;
+                               bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width;
                                offset += bank->sectors[sector].size;
                                bank->sectors[sector].is_erased = -1;
                                bank->sectors[sector].is_protected = -1;
@@ -1108,7 +1183,7 @@ int cfi_intel_protect_check(struct flash_bank_s *bank)
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
        cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
        target_t *target = cfi_info->target;
-       u8 command[8];
+       u8 command[CFI_MAX_BUS_WIDTH];
        int i;
        
        /* check if block lock bits are supported on this device */
@@ -1137,7 +1212,6 @@ int cfi_intel_protect_check(struct flash_bank_s *bank)
 int cfi_protect_check(struct flash_bank_s *bank)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       target_t *target = cfi_info->target;
 
        if (cfi_info->qry[0] != 'Q')
                return ERROR_FLASH_BANK_NOT_PROBED;

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)