X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fat91samd.c;h=a0bfcc363f8a92510e42e4e4212994cce03df054;hp=ece1fd20f6d6d9bf6d3b147264377dd10df55289;hb=b5fa1e4d7779ca3a7f3de7d5cd3f0732ec8a11ff;hpb=08607aefc0da2394bcce067989812081f742f5e2 diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index ece1fd20f6..a0bfcc363f 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -25,6 +25,8 @@ #include "imp.h" #include "helper/binarybuffer.h" +#include + #define SAMD_NUM_SECTORS 16 #define SAMD_PAGE_SIZE_MAX 1024 @@ -34,6 +36,7 @@ #define SAMD_DSU 0x41002000 /* Device Service Unit */ #define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */ +#define SAMD_DSU_STATUSA 1 /* DSU status register */ #define SAMD_DSU_DID 0x18 /* Device ID register */ #define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */ @@ -60,14 +63,25 @@ #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 +#define SAMD_FAMILY_L 0x01 +#define SAMD_FAMILY_C 0x02 #define SAMD_SERIES_20 0x00 #define SAMD_SERIES_21 0x01 #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; @@ -149,6 +163,61 @@ static const struct samd_part samr21_parts[] = { { 0x1E, "SAMR21E16A", 64, 32 }, }; +/* Known SAML21 parts. */ +static const struct samd_part saml21_parts[] = { + { 0x00, "SAML21J18A", 256, 32 }, + { 0x01, "SAML21J17A", 128, 16 }, + { 0x02, "SAML21J16A", 64, 8 }, + { 0x05, "SAML21G18A", 256, 32 }, + { 0x06, "SAML21G17A", 128, 16 }, + { 0x07, "SAML21G16A", 64, 8 }, + { 0x0A, "SAML21E18A", 256, 32 }, + { 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. */ +static const struct samd_part samc20_parts[] = { + { 0x00, "SAMC20J18A", 256, 32 }, + { 0x01, "SAMC20J17A", 128, 16 }, + { 0x02, "SAMC20J16A", 64, 8 }, + { 0x03, "SAMC20J15A", 32, 4 }, + { 0x05, "SAMC20G18A", 256, 32 }, + { 0x06, "SAMC20G17A", 128, 16 }, + { 0x07, "SAMC20G16A", 64, 8 }, + { 0x08, "SAMC20G15A", 32, 4 }, + { 0x0A, "SAMC20E18A", 256, 32 }, + { 0x0B, "SAMC20E17A", 128, 16 }, + { 0x0C, "SAMC20E16A", 64, 8 }, + { 0x0D, "SAMC20E15A", 32, 4 }, +}; + +/* Known SAMC21 parts. */ +static const struct samd_part samc21_parts[] = { + { 0x00, "SAMC21J18A", 256, 32 }, + { 0x01, "SAMC21J17A", 128, 16 }, + { 0x02, "SAMC21J16A", 64, 8 }, + { 0x03, "SAMC21J15A", 32, 4 }, + { 0x05, "SAMC21G18A", 256, 32 }, + { 0x06, "SAMC21G17A", 128, 16 }, + { 0x07, "SAMC21G16A", 64, 8 }, + { 0x08, "SAMC21G15A", 32, 4 }, + { 0x0A, "SAMC21E18A", 256, 32 }, + { 0x0B, "SAMC21E17A", 128, 16 }, + { 0x0C, "SAMC21E16A", 64, 8 }, + { 0x0D, "SAMC21E15A", 32, 4 }, +}; /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact @@ -173,6 +242,12 @@ static const struct samd_family samd_families[] = { samd10_parts, ARRAY_SIZE(samd10_parts) }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, samd11_parts, ARRAY_SIZE(samd11_parts) }, + { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, + saml21_parts, ARRAY_SIZE(saml21_parts) }, + { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, + samc20_parts, ARRAY_SIZE(samc20_parts) }, + { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, + samc21_parts, ARRAY_SIZE(samc21_parts) }, }; struct samd_info { @@ -180,6 +255,7 @@ struct samd_info { int num_pages; int sector_size; + bool manual_wp; bool probed; struct target *target; struct samd_info *next; @@ -187,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 >> 24) & 0x0F; - uint8_t series = (id >> 16) & 0xFF; - 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 && @@ -306,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; @@ -658,6 +739,19 @@ 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); + error = samd_check_error(bank->target); if (error) return ERROR_FAIL; @@ -708,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; @@ -724,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. */ @@ -973,8 +1080,8 @@ COMMAND_HANDLER(samd_handle_bootloader_command) nb = (2 << (8 - size)) * page_size; /* There are 4 pages per row */ - command_print(CMD_CTX, "Bootloader size is %u bytes (%u rows)", - nb, nb / (page_size * 4)); + command_print(CMD_CTX, "Bootloader size is %" PRIu32 " bytes (%" PRIu32 " rows)", + nb, (uint32_t)(nb / (page_size * 4))); } } } @@ -982,7 +1089,46 @@ COMMAND_HANDLER(samd_handle_bootloader_command) return res; } + + +COMMAND_HANDLER(samd_handle_reset_deassert) +{ + struct target *target = get_current_target(CMD_CTX); + struct armv7m_common *armv7m = target_to_armv7m(target); + struct adiv5_dap *swjdp = armv7m->arm.dap; + int retval = ERROR_OK; + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + /* In case of sysresetreq, debug retains state set in cortex_m_assert_reset() + * so we just release reset held by DSU + * + * n_RESET (srst) clears the DP, so reenable debug and set vector catch here + * + * After vectreset DSU release is not needed however makes no harm + */ + if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) { + retval = mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); + if (retval == ERROR_OK) + retval = mem_ap_write_u32(swjdp, DCB_DEMCR, + TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); + /* do not return on error here, releasing DSU reset is more important */ + } + + /* clear CPU Reset Phase Extension bit */ + int retval2 = target_write_u8(target, SAMD_DSU + SAMD_DSU_STATUSA, (1<<1)); + if (retval2 != ERROR_OK) + return retval2; + + return retval; +} + static const struct command_registration at91samd_exec_command_handlers[] = { + { + .name = "dsu_reset_deassert", + .handler = samd_handle_reset_deassert, + .mode = COMMAND_EXEC, + .help = "deasert internal reset held by DSU" + }, { .name = "info", .handler = samd_handle_info_command,