From: Andreas Loehre Date: Thu, 6 Aug 2015 17:41:10 +0000 (+0200) Subject: flash: at91samd: Add SAML21 variant B device support and fix SAMC20/SAMC21 X-Git-Tag: v0.10.0-rc1~364 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=b5fa1e4d7779ca3a7f3de7d5cd3f0732ec8a11ff;ds=sidebyside flash: at91samd: Add SAML21 variant B device support and fix SAMC20/SAMC21 This adds support for the Atmel SAML21 variant B parts. There is minimal change between the two variants, but in variant B the automatic page write which the at91samd flash driver relies on to be enabled is disabled by default. With this patch the write row function will now issue a page write command after each of the four pages in the row if the MANW (manual write) bit is set. This also fixes flash write for the SAMC20/SAMC21 devices which have the MANW bit set by default as well. I have also moved the device ID (DID) register bitfield extraction from the find_part into helper macros. These can be used in the future if there are more workarounds for specific devices. Tested (programming) on: ATSAML21-XPRO ATSAML21-XPRO-B SAMC21 Xplained Pro SAMD21 Xplained Pro SAMD20 Xplained Pro Change-Id: I401a8aa1efd64730840c0d62cf49a1e880ea5900 Signed-off-by: Andreas Loehre Reviewed-on: http://openocd.zylin.com/2903 Tested-by: jenkins Reviewed-by: Tomas Vanek --- diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 9b0f7eebe5..a0bfcc363f 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -63,6 +63,9 @@ #define SAMD_NVM_CMD_SSB 0x45 /* Set Security Bit */ #define SAMD_NVM_CMD_INVALL 0x46 /* Invalidate all caches */ +/* NVMCTRL bits */ +#define SAMD_NVM_CTRLB_MANW 0x80 + /* Known identifiers */ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_FAMILY_D 0x00 @@ -73,6 +76,12 @@ #define SAMD_SERIES_10 0x02 #define SAMD_SERIES_11 0x03 +/* Device ID macros */ +#define SAMD_GET_PROCESSOR(id) (id >> 28) +#define SAMD_GET_FAMILY(id) (((id >> 23) & 0x1F)) +#define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F)) +#define SAMD_GET_DEVSEL(id) (id & 0xFF) + struct samd_part { uint8_t id; const char *name; @@ -166,6 +175,16 @@ static const struct samd_part saml21_parts[] = { { 0x0B, "SAML21E17A", 128, 16 }, { 0x0C, "SAML21E16A", 64, 8 }, { 0x0D, "SAML21E15A", 32, 4 }, + { 0x0F, "SAML21J18B", 256, 32 }, + { 0x10, "SAML21J17B", 128, 16 }, + { 0x11, "SAML21J16B", 64, 8 }, + { 0x14, "SAML21G18B", 256, 32 }, + { 0x15, "SAML21G17B", 128, 16 }, + { 0x16, "SAML21G16B", 64, 8 }, + { 0x19, "SAML21E18B", 256, 32 }, + { 0x1A, "SAML21E17B", 128, 16 }, + { 0x1B, "SAML21E16B", 64, 8 }, + { 0x1C, "SAML21E15B", 32, 4 }, }; /* Known SAMC20 parts. */ @@ -236,6 +255,7 @@ struct samd_info { int num_pages; int sector_size; + bool manual_wp; bool probed; struct target *target; struct samd_info *next; @@ -243,12 +263,14 @@ struct samd_info { static struct samd_info *samd_chips; + + static const struct samd_part *samd_find_part(uint32_t id) { - uint8_t processor = (id >> 28); - uint8_t family = (id >> 23) & 0x1F; - uint8_t series = (id >> 16) & 0x3F; - uint8_t devsel = id & 0xFF; + uint8_t processor = SAMD_GET_PROCESSOR(id); + uint8_t family = SAMD_GET_FAMILY(id); + uint8_t series = SAMD_GET_SERIES(id); + uint8_t devsel = SAMD_GET_DEVSEL(id); for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && @@ -362,6 +384,9 @@ static int samd_probe(struct flash_bank *bank) samd_protect_check(bank); + /* By default we do not need to send page write commands */ + chip->manual_wp = false; + /* Done */ chip->probed = true; @@ -714,6 +739,16 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address, return res; } + /* For some devices automatic page write is not default so we need + * to issue a write page CMD to the NVM */ + if (chip->manual_wp == true) { + res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_WP); + if (res != ERROR_OK) { + LOG_ERROR("%s: %d", __func__, __LINE__); + return res; + } + } + /* Access through AHB is stalled while flash is being programmed */ usleep(200); @@ -767,6 +802,7 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; + uint32_t nvm_ctrlb; uint32_t address; uint32_t nb = 0; struct samd_info *chip = (struct samd_info *)bank->driver_priv; @@ -783,6 +819,18 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_FLASH_BANK_NOT_PROBED; } + /* Check if we need to do manual page write commands */ + res = target_read_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); + + if (res != ERROR_OK) + return res; + + if (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) + chip->manual_wp = true; + else + chip->manual_wp = false; + + if (offset % row_size) { /* We're starting at an unaligned offset so we'll write a partial row * comprising that offset and up to the end of that row. */