#define SAMD_NUM_SECTORS 16
-#define SAMD_FLASH 0x00000000 /* physical Flash memory */
+#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
#define SAMD_DSU 0x41002000 /* Device Service Unit */
#define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */
#define SAMD_PROCESSOR_M0 0x01
#define SAMD_FAMILY_D 0x00
#define SAMD_SERIES_20 0x00
-#define SAMD_SERIES_21 0x01
+#define SAMD_SERIES_21 0x01
+#define SAMD_SERIES_10 0x02
+#define SAMD_SERIES_11 0x03
struct samd_part {
uint8_t id;
uint32_t ram_kb;
};
+/* Known SAMD10 parts */
+static const struct samd_part samd10_parts[] = {
+ { 0x0, "SAMD10D14AMU", 16, 4 },
+ { 0x1, "SAMD10D13AMU", 8, 4 },
+ { 0x2, "SAMD10D12AMU", 4, 4 },
+ { 0x3, "SAMD10D14ASU", 16, 4 },
+ { 0x4, "SAMD10D13ASU", 8, 4 },
+ { 0x5, "SAMD10D12ASU", 4, 4 },
+ { 0x6, "SAMD10C14A", 16, 4 },
+ { 0x7, "SAMD10C13A", 8, 4 },
+ { 0x8, "SAMD10C12A", 4, 4 },
+};
+
+/* Known SAMD11 parts */
+static const struct samd_part samd11_parts[] = {
+ { 0x0, "SAMD11D14AMU", 16, 4 },
+ { 0x1, "SAMD11D13AMU", 8, 4 },
+ { 0x2, "SAMD11D12AMU", 4, 4 },
+ { 0x3, "SAMD11D14ASU", 16, 4 },
+ { 0x4, "SAMD11D13ASU", 8, 4 },
+ { 0x5, "SAMD11D12ASU", 4, 4 },
+ { 0x6, "SAMD11C14A", 16, 4 },
+ { 0x7, "SAMD11C13A", 8, 4 },
+ { 0x8, "SAMD11C12A", 4, 4 },
+};
+
/* 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 },
};
/* Known SAMD21 parts. */
-static struct samd_part samd21_parts[] = {
+static const struct samd_part samd21_parts[] = {
{ 0x0, "SAMD21J18A", 256, 32 },
{ 0x1, "SAMD21J17A", 128, 16 },
{ 0x2, "SAMD21J16A", 64, 8 },
{ 0xE, "SAMD21E14A", 16, 2 },
};
+/* Known SAMR21 parts. */
+static const struct samd_part samr21_parts[] = {
+ { 0x19, "SAMR21G18A", 256, 32 },
+ { 0x1A, "SAMR21G17A", 128, 32 },
+ { 0x1B, "SAMR21G16A", 64, 32 },
+ { 0x1C, "SAMR21E18A", 256, 32 },
+ { 0x1D, "SAMR21E17A", 128, 32 },
+ { 0x1E, "SAMR21E16A", 64, 32 },
+};
+
+
/* 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. */
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) },
+ { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
+ samr21_parts, ARRAY_SIZE(samr21_parts) },
+ { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10,
+ samd10_parts, ARRAY_SIZE(samd10_parts) },
+ { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11,
+ samd11_parts, ARRAY_SIZE(samd11_parts) },
};
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;
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;
* multiplied by the number of pages. */
if (bank->size != chip->num_pages * chip->page_size) {
LOG_WARNING("SAMD: bank size doesn't match NVM parameters. "
- "Identified %uKB Flash but NVMCTRL reports %u %uB pages",
+ "Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages",
part->flash_kb, chip->num_pages, chip->page_size);
}
/* Done */
chip->probed = true;
- LOG_INFO("SAMD MCU: %s (%uKB Flash, %uKB RAM)", part->name,
+ LOG_INFO("SAMD MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name,
part->flash_kb, part->ram_kb);
return ERROR_OK;
int res;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+ res = ERROR_OK;
+
for (int s = first; s <= last; s++) {
- /* Load an address that is within this sector (we use offset 0) */
- res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
- s * chip->sector_size);
- if (res != ERROR_OK)
- return res;
+ if (set != bank->sectors[s].is_protected) {
+ /* Load an address that is within this sector (we use offset 0) */
+ res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
+ s * chip->sector_size);
+ if (res != ERROR_OK)
+ goto exit;
- /* Tell the controller to lock that sector */
- res = target_write_u16(bank->target,
- SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
- SAMD_NVM_CMD(SAMD_NVM_CMD_LR));
- if (res != ERROR_OK)
- return res;
- }
+ /* Tell the controller to lock that sector */
+
+ uint16_t cmd = (set) ?
+ SAMD_NVM_CMD(SAMD_NVM_CMD_LR) :
+ SAMD_NVM_CMD(SAMD_NVM_CMD_UR);
+ res = target_write_u16(bank->target,
+ SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
+ cmd);
+ if (res != ERROR_OK)
+ goto exit;
+ }
+ }
+exit:
samd_protect_check(bank);
- return ERROR_OK;
+ return res;
}
static bool samd_check_error(struct flash_bank *bank)
}
if (res != ERROR_OK || error) {
- LOG_ERROR("Failed to erase row containing %08X" PRIx32, address);
+ LOG_ERROR("Failed to erase row containing %08" PRIx32, address);
return ERROR_FAIL;
}
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
/* 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)
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;
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;