X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fat91samd.c;h=ee9e9cbb9edcff95b9a95bb24220eea85efc9a46;hp=86acbc097c7af9ca13fc2b7da2a21ffaa4eea232;hb=c92a605e2622e5598c737a699d3164b9934bbd8c;hpb=215c41c0174e94ab00b36a7d56a054cdd7f30dd0 diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 86acbc097c..ee9e9cbb9e 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -60,6 +60,7 @@ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_FAMILY_D 0x00 #define SAMD_SERIES_20 0x00 +#define SAMD_SERIES_21 0x01 struct samd_part { uint8_t id; @@ -69,7 +70,7 @@ struct samd_part { }; /* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */ -static struct samd_part samd20_parts[] = { +static const struct samd_part samd20_parts[] = { { 0x0, "SAMD20J18A", 256, 32 }, { 0x1, "SAMD20J17A", 128, 16 }, { 0x2, "SAMD20J16A", 64, 8 }, @@ -86,6 +87,25 @@ static struct samd_part samd20_parts[] = { { 0xE, "SAMD20E14A", 16, 2 }, }; +/* Known SAMD21 parts. */ +static const struct samd_part samd21_parts[] = { + { 0x0, "SAMD21J18A", 256, 32 }, + { 0x1, "SAMD21J17A", 128, 16 }, + { 0x2, "SAMD21J16A", 64, 8 }, + { 0x3, "SAMD21J15A", 32, 4 }, + { 0x4, "SAMD21J14A", 16, 2 }, + { 0x5, "SAMD21G18A", 256, 32 }, + { 0x6, "SAMD21G17A", 128, 16 }, + { 0x7, "SAMD21G16A", 64, 8 }, + { 0x8, "SAMD21G15A", 32, 4 }, + { 0x9, "SAMD21G14A", 16, 2 }, + { 0xA, "SAMD21E18A", 256, 32 }, + { 0xB, "SAMD21E17A", 128, 16 }, + { 0xC, "SAMD21E16A", 64, 8 }, + { 0xD, "SAMD21E15A", 32, 4 }, + { 0xE, "SAMD21E14A", 16, 2 }, +}; + /* 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 * family this is and then we can use the corresponding table. */ @@ -93,14 +113,16 @@ struct samd_family { uint8_t processor; uint8_t family; uint8_t series; - struct samd_part *parts; + const struct samd_part *parts; size_t num_parts; }; /* Known SAMD families */ -static struct samd_family samd_families[] = { +static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, samd20_parts, ARRAY_SIZE(samd20_parts) }, + { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, + samd21_parts, ARRAY_SIZE(samd21_parts) }, }; struct samd_info { @@ -115,7 +137,7 @@ struct samd_info { static struct samd_info *samd_chips; -static struct samd_part *samd_find_part(uint32_t id) +static const struct samd_part *samd_find_part(uint32_t id) { uint8_t processor = (id >> 28); uint8_t family = (id >> 24) & 0x0F; @@ -158,7 +180,7 @@ static int samd_probe(struct flash_bank *bank) uint32_t id, param; int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; - struct samd_part *part; + const struct samd_part *part; if (chip->probed) return ERROR_OK; @@ -330,13 +352,6 @@ static int samd_erase(struct flash_bank *bank, int first, int last) return ERROR_FLASH_BANK_NOT_PROBED; } - /* Make sure the sectors make sense. */ - if (first >= bank->num_sectors || last >= bank->num_sectors) { - LOG_ERROR("Erase range %d - %d not valid (%d sectors total)", - first, last, bank->num_sectors); - return ERROR_FAIL; - } - /* The SAMD NVM has row erase granularity. There are four pages in a row * and the number of rows in a sector depends on the sector size, which in * turn depends on the Flash capacity as there is a fixed number of @@ -345,29 +360,60 @@ static int samd_erase(struct flash_bank *bank, int first, int last) /* For each sector to be erased */ for (int s = first; s <= last; s++) { - /* For each row in that sector */ - for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) { - res = samd_erase_row(bank, r * chip->page_size * 4); - if (res != ERROR_OK) { - LOG_ERROR("SAMD: failed to erase sector %d", s); - return res; - } + if (bank->sectors[s].is_protected) { + LOG_ERROR("SAMD: failed to erase sector %d. That sector is write-protected", s); + return ERROR_FLASH_OPERATION_FAILED; } - bank->sectors[s].is_erased = 1; + if (!bank->sectors[s].is_erased) { + /* For each row in that sector */ + for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) { + res = samd_erase_row(bank, r * chip->page_size * 4); + if (res != ERROR_OK) { + LOG_ERROR("SAMD: failed to erase sector %d", s); + return res; + } + } + + bank->sectors[s].is_erased = 1; + } } return ERROR_OK; } +static struct flash_sector *samd_find_sector_by_address(struct flash_bank *bank, uint32_t address) +{ + struct samd_info *chip = (struct samd_info *)bank->driver_priv; + + for (int i = 0; i < bank->num_sectors; i++) { + if (bank->sectors[i].offset <= address && + address < bank->sectors[i].offset + chip->sector_size) + return &bank->sectors[i]; + } + return NULL; +} + /* Write an entire row (four pages) from host buffer 'buf' to row-aligned * 'address' in the Flash. */ static int samd_write_row(struct flash_bank *bank, uint32_t address, - uint8_t *buf) + const uint8_t *buf) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; + struct flash_sector *sector = samd_find_sector_by_address(bank, address); + + if (!sector) { + LOG_ERROR("Can't find sector corresponding to address 0x%08" PRIx32, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (sector->is_protected) { + LOG_ERROR("Trying to write to a protected sector at 0x%08" PRIx32, address); + return ERROR_FLASH_OPERATION_FAILED; + } + /* Erase the row that we'll be writing to */ res = samd_erase_row(bank, address); if (res != ERROR_OK) @@ -396,13 +442,15 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address, buf += chip->page_size; } + sector->is_erased = 0; + return res; } /* Write partial contents into row-aligned 'address' on the Flash from host * buffer 'buf' by writing 'nb' of 'buf' at 'row_offset' into the Flash row. */ static int samd_write_row_partial(struct flash_bank *bank, uint32_t address, - uint8_t *buf, uint32_t row_offset, uint32_t nb) + const uint8_t *buf, uint32_t row_offset, uint32_t nb) { int res; struct samd_info *chip = (struct samd_info *)bank->driver_priv; @@ -431,7 +479,7 @@ static int samd_write_row_partial(struct flash_bank *bank, uint32_t address, return res; } -static int samd_write(struct flash_bank *bank, uint8_t *buffer, +static int samd_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res;