From 34e8d1a50d9ee965e2efa4aae6e2e97caef37c23 Mon Sep 17 00:00:00 2001 From: IS2T Date: Wed, 19 Jun 2013 08:03:17 +0200 Subject: [PATCH] Support for SST 39VF3201C NOR flash * Add Thumb-2 code to write flash memories that don't support DQ5 polling * Make sure default values for unlock commands are set even if there is no PRI information given by the flash * Add a fixup to disable DQ5 polling for the SST 39VF3201C Change-Id: Ib08cf20547d0f500d5f78241521e6b49050c3d40 Signed-off-by: IS2T development team Reviewed-on: http://openocd.zylin.com/1449 Tested-by: jenkins Reviewed-by: Spencer Oliver --- .../loaders/flash/armv7m_cfi_span_16_dq7.s | 72 +++++++++++++++ src/flash/nor/cfi.c | 88 ++++++++++++++----- src/flash/nor/cfi.h | 4 +- 3 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 contrib/loaders/flash/armv7m_cfi_span_16_dq7.s diff --git a/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s b/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s new file mode 100644 index 000000000..5b29a3bda --- /dev/null +++ b/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005, 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * Copyright (C) 2010 Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + + .text + .syntax unified + .arch armv7-m + .thumb + .thumb_func + + .align 2 + +/* input parameters - */ +/* R0 = source address */ +/* R1 = destination address */ +/* R2 = number of writes */ +/* R3 = flash write command */ +/* R4 = constant to mask DQ7 bits */ +/* output parameters - */ +/* R5 = 0x80 ok 0x00 bad */ +/* temp registers - */ +/* R6 = value read from flash to test status */ +/* R7 = holding register */ +/* unlock registers - */ +/* R8 = unlock1_addr */ +/* R9 = unlock1_cmd */ +/* R10 = unlock2_addr */ +/* R11 = unlock2_cmd */ + +code: + ldrh r5, [r0], #2 + strh r9, [r8] + strh r11, [r10] + strh r3, [r8] + strh r5, [r1] + nop +busy: + ldrh r6, [r1] + eor r7, r5, r6 + ands r7, r4, r7 + bne busy + subs r2, r2, #1 /* 0x1 */ + beq success + add r1, r1, #2 /* 0x2 */ + b code + +success: + mov r5, #128 /* 0x80 */ + b done + +done: + bkpt #0 + + .end diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 9fe1173af..c443de2dd 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -46,16 +46,19 @@ #define AT49BV6416 0x00d6 #define AT49BV6416T 0x00d2 -static struct cfi_unlock_addresses cfi_unlock_addresses[] = { +static const struct cfi_unlock_addresses cfi_unlock_addresses[] = { [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa }, [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa }, }; +static const int cfi_status_poll_mask_dq6_dq7 = CFI_STATUS_POLL_MASK_DQ6_DQ7; + /* CFI fixups forward declarations */ -static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param); -static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param); -static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *param); -static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param); +static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param); +static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, const void *param); +static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void *param); +static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, const void *param); +static void cfi_fixup_0002_polling_bits(struct flash_bank *bank, const void *param); /* fixup after reading cmdset 0002 primary query table */ static const struct cfi_fixup cfi_0002_fixups[] = { @@ -71,6 +74,8 @@ static const struct cfi_fixup cfi_0002_fixups[] = { &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x274b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_SST, 0x235f, cfi_fixup_0002_polling_bits, /* 39VF3201C */ + &cfi_status_poll_mask_dq6_dq7}, {CFI_MFR_SST, 0x236d, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_reversed_erase_regions, NULL}, @@ -522,6 +527,11 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) if (retval != ERROR_OK) return retval; + /* default values for implementation specific workarounds */ + pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; + pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; + pri_ext->_reversed_geometry = 0; + if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) @@ -590,11 +600,6 @@ static int cfi_read_spansion_pri_ext(struct flash_bank *bank) LOG_DEBUG("WP# protection 0x%x", pri_ext->TopBottom); - /* default values for implementation specific workarounds */ - pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; - pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; - pri_ext->_reversed_geometry = 0; - return ERROR_OK; } @@ -1695,7 +1700,7 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, 0xeafffffe /* b 81ac */ }; - /* see contib/loaders/flash/armv7m_cfi_span_16.s for src */ + /* see contrib/loaders/flash/armv7m_cfi_span_16.s for src */ static const uint32_t armv7m_word_16_code[] = { 0x5B02F830, 0x9000F8A8, @@ -1717,7 +1722,36 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, 0x0000BE00 }; - /* see contib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */ + /* see contrib/loaders/flash/armv7m_cfi_span_16_dq7.s for src */ + static const uint32_t armv7m_word_16_code_dq7only[] = { + /* 00000000 : */ + 0x5B02F830, /* ldrh.w r5, [r0], #2 */ + 0x9000F8A8, /* strh.w r9, [r8] */ + 0xB000F8AA, /* strh.w fp, [sl] */ + 0x3000F8A8, /* strh.w r3, [r8] */ + 0xBF00800D, /* strh r5, [r1, #0] */ + /* nop */ + + /* 00000014 : */ + 0xEA85880E, /* ldrh r6, [r1, #0] */ + /* eor.w r7, r5, r6 */ + 0x40270706, /* ands r7, r4 */ + 0x3A01D1FA, /* bne.n 14 */ + /* subs r2, #1 */ + 0xF101D002, /* beq.n 28 */ + 0xE7EB0102, /* add.w r1, r1, #2 */ + /* b.n 0 */ + + /* 00000028 : */ + 0x0580F04F, /* mov.w r5, #128 */ + 0xBF00E7FF, /* b.n 30 */ + /* nop (for alignment purposes) */ + + /* 00000030 : */ + 0x0000BE00 /* bkpt 0x0000 */ + }; + + /* see contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */ static const uint32_t armv4_5_word_16_code_dq7only[] = { /* : */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ @@ -1741,7 +1775,7 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, 0xeafffffe /* b 81ac */ }; - /* see contib/loaders/flash/armv4_5_cfi_span_8.s for src */ + /* see contrib/loaders/flash/armv4_5_cfi_span_8.s for src */ static const uint32_t armv4_5_word_8_code[] = { /* 000081b0 : */ 0xe4d05001, /* ldrb r5, [r0], #1 */ @@ -1817,11 +1851,13 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, } else { /* No DQ5 support. Use DQ7 DATA# polling only. */ if (is_armv7m(target_to_armv7m(target))) { - LOG_ERROR("Unknown ARM architecture"); - return ERROR_FAIL; + /* armv7m target */ + target_code_src = armv7m_word_16_code_dq7only; + target_code_size = sizeof(armv7m_word_16_code_dq7only); + } else { /* armv4_5 target */ + target_code_src = armv4_5_word_16_code_dq7only; + target_code_size = sizeof(armv4_5_word_16_code_dq7only); } - target_code_src = armv4_5_word_16_code_dq7only; - target_code_size = sizeof(armv4_5_word_16_code_dq7only); } break; case 4: @@ -2427,7 +2463,7 @@ static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, return cfi_reset(bank); } -static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *param) +static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, const void *param) { (void) param; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -2436,7 +2472,7 @@ static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *para pri_ext->_reversed_geometry = 1; } -static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param) +static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, const void *param) { int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; @@ -2457,16 +2493,24 @@ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param) } } -static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param) +static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; - struct cfi_unlock_addresses *unlock_addresses = param; + const struct cfi_unlock_addresses *unlock_addresses = param; pri_ext->_unlock1 = unlock_addresses->unlock1; pri_ext->_unlock2 = unlock_addresses->unlock2; } +static void cfi_fixup_0002_polling_bits(struct flash_bank *bank, const void *param) +{ + struct cfi_flash_bank *cfi_info = bank->driver_priv; + const int status_poll_mask = *(const int *)param; + + cfi_info->status_poll_mask = status_poll_mask; +} + static int cfi_query_string(struct flash_bank *bank, int address) { @@ -3028,7 +3072,7 @@ static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param) +static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, const void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index b587ed482..d92fcc0b1 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -143,8 +143,8 @@ struct cfi_unlock_addresses { struct cfi_fixup { uint16_t mfr; uint16_t id; - void (*fixup)(struct flash_bank *bank, void *param); - void *param; + void (*fixup)(struct flash_bank *bank, const void *param); + const void *param; }; #define CFI_MFR_AMD 0x0001