diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index f018e893d5da0366f77af54c97393059f49e6cab..ad88c5143dbe8e544187224cf475dc0c5790a133 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -25,7 +25,7 @@
 
 #include <target/cortex_m.h>
 
-#define SAMD_NUM_SECTORS	16
+#define SAMD_NUM_PROT_BLOCKS	16
 #define SAMD_PAGE_SIZE_MAX	1024
 
 #define SAMD_FLASH			((uint32_t)0x00000000)	/* physical Flash memory */
@@ -286,6 +286,7 @@ struct samd_info {
 	uint32_t page_size;
 	int num_pages;
 	int sector_size;
+	int prot_block_size;
 
 	bool probed;
 	struct target *target;
@@ -319,7 +320,7 @@ static const struct samd_part *samd_find_part(uint32_t id)
 
 static int samd_protect_check(struct flash_bank *bank)
 {
-	int res;
+	int res, prot_block;
 	uint16_t lock;
 
 	res = target_read_u16(bank->target,
@@ -328,8 +329,8 @@ static int samd_protect_check(struct flash_bank *bank)
 		return res;
 
 	/* Lock bits are active-low */
-	for (int i = 0; i < bank->num_sectors; i++)
-		bank->sectors[i].is_protected = !(lock & (1<<i));
+	for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
+		bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
 
 	return ERROR_OK;
 }
@@ -380,8 +381,6 @@ static int samd_probe(struct flash_bank *bank)
 
 	bank->size = part->flash_kb * 1024;
 
-	chip->sector_size = bank->size / SAMD_NUM_SECTORS;
-
 	res = samd_get_flash_page_info(bank->target, &chip->page_size,
 			&chip->num_pages);
 	if (res != ERROR_OK) {
@@ -397,21 +396,23 @@ static int samd_probe(struct flash_bank *bank)
 				part->flash_kb, chip->num_pages, chip->page_size);
 	}
 
+	/* Erase granularity = 1 row = 4 pages */
+	chip->sector_size = chip->page_size * 4;
+
 	/* Allocate the sector table */
-	bank->num_sectors = SAMD_NUM_SECTORS;
-	bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0]));
+	bank->num_sectors = chip->num_pages / 4;
+	bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
 	if (!bank->sectors)
 		return ERROR_FAIL;
 
-	/* Fill out the sector information: all SAMD sectors are the same size and
-	 * there is always a fixed number of them. */
-	for (int i = 0; i < bank->num_sectors; i++) {
-		bank->sectors[i].size = chip->sector_size;
-		bank->sectors[i].offset = i * chip->sector_size;
-		/* mark as unknown */
-		bank->sectors[i].is_erased = -1;
-		bank->sectors[i].is_protected = -1;
-	}
+	/* 16 protection blocks per device */
+	chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS;
+
+	/* Allocate the table of protection blocks */
+	bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS;
+	bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
+	if (!bank->prot_blocks)
+		return ERROR_FAIL;
 
 	samd_protect_check(bank);
 
@@ -606,9 +607,10 @@ out_user_row:
 	return res;
 }
 
-static int samd_protect(struct flash_bank *bank, int set, int first, int last)
+static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
 {
-	struct samd_info *chip = (struct samd_info *)bank->driver_priv;
+	int res = ERROR_OK;
+	int prot_block;
 
 	/* We can issue lock/unlock region commands with the target running but
 	 * the settings won't persist unless we're able to modify the LOCK regions
@@ -618,18 +620,16 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
 		return ERROR_TARGET_NOT_HALTED;
 	}
 
-	int res = ERROR_OK;
-
-	for (int s = first; s <= last; s++) {
-		if (set != bank->sectors[s].is_protected) {
-			/* Load an address that is within this sector (we use offset 0) */
+	for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
+		if (set != bank->prot_blocks[prot_block].is_protected) {
+			/* Load an address that is within this protection block (we use offset 0) */
 			res = target_write_u32(bank->target,
 							SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
-							((s * chip->sector_size) >> 1));
+							bank->prot_blocks[prot_block].offset >> 1);
 			if (res != ERROR_OK)
 				goto exit;
 
-			/* Tell the controller to lock that sector */
+			/* Tell the controller to lock that block */
 			res = samd_issue_nvmctrl_command(bank->target,
 					set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
 			if (res != ERROR_OK)
@@ -644,7 +644,7 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last)
 	 * locked.  See Table 9-3 in the SAMD20 datasheet for more details. */
 
 	res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
-			48 + first, 48 + last);
+			48 + first_prot_bl, 48 + last_prot_bl);
 	if (res != ERROR_OK)
 		LOG_WARNING("SAMD: protect settings were not made persistent!");
 
@@ -656,10 +656,9 @@ exit:
 	return res;
 }
 
-static int samd_erase(struct flash_bank *bank, int first, int last)
+static int samd_erase(struct flash_bank *bank, int first_sect, int last_sect)
 {
-	int res;
-	int rows_in_sector;
+	int res, s;
 	struct samd_info *chip = (struct samd_info *)bank->driver_priv;
 
 	if (bank->target->state != TARGET_HALTED) {
@@ -673,26 +672,12 @@ static int samd_erase(struct flash_bank *bank, int first, int last)
 			return ERROR_FLASH_BANK_NOT_PROBED;
 	}
 
-	/* 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
-	 * sectors. */
-	rows_in_sector = chip->sector_size / (chip->page_size * 4);
-
 	/* For each sector to be erased */
-	for (int s = first; s <= last; s++) {
-		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;
-		}
-
-		/* 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->target, r * chip->page_size * 4);
-			if (res != ERROR_OK) {
-				LOG_ERROR("SAMD: failed to erase sector %d", s);
-				return res;
-			}
+	for (s = first_sect; s <= last_sect; s++) {
+		res = samd_erase_row(bank->target, bank->sectors[s].offset);
+		if (res != ERROR_OK) {
+			LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
+			return res;
 		}
 	}