--- /dev/null
+/***************************************************************************
+ * 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
#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[] = {
&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},
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)
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;
}
0xeafffffe /* b 81ac <sp_16_done> */
};
- /* 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,
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 <code>: */
+ 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 <busy>: */
+ 0xEA85880E, /* ldrh r6, [r1, #0] */
+ /* eor.w r7, r5, r6 */
+ 0x40270706, /* ands r7, r4 */
+ 0x3A01D1FA, /* bne.n 14 <busy> */
+ /* subs r2, #1 */
+ 0xF101D002, /* beq.n 28 <success> */
+ 0xE7EB0102, /* add.w r1, r1, #2 */
+ /* b.n 0 <code> */
+
+ /* 00000028 <success>: */
+ 0x0580F04F, /* mov.w r5, #128 */
+ 0xBF00E7FF, /* b.n 30 <done> */
+ /* nop (for alignment purposes) */
+
+ /* 00000030 <done>: */
+ 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[] = {
/* <sp_16_code>: */
0xe0d050b2, /* ldrh r5, [r0], #2 */
0xeafffffe /* b 81ac <sp_16_done> */
};
- /* 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 <sp_16_code_end>: */
0xe4d05001, /* ldrb r5, [r0], #1 */
} 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:
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;
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;
}
}
-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)
{
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;