diff --git a/src/sam3x.c b/src/sam3x.c index 79dca3d..38a3ef7 100644 --- a/src/sam3x.c +++ b/src/sam3x.c @@ -68,9 +68,22 @@ static const char sam3n_xml_memory_map[] = "" " " ""; +static const char sam4s_xml_memory_map[] = "" +/* ""*/ + "" + " " + " 0x200" + " " + " " + " " + ""; + /* Enhanced Embedded Flash Controller (EEFC) Register Map */ #define SAM3N_EEFC_BASE 0x400E0A00 #define SAM3X_EEFC_BASE(x) (0x400E0A00+((x)*0x400)) +#define SAM4S_EEFC_BASE(x) (0x400E0A00+((x)*0x200)) #define EEFC_FMR(base) ((base)+0x00) #define EEFC_FCR(base) ((base)+0x04) #define EEFC_FSR(base) ((base)+0x08) @@ -99,14 +112,18 @@ static const char sam3n_xml_memory_map[] = "" #define SAM3X_CHIPID_CIDR 0x400E0940 #define SAM3N_CHIPID_CIDR 0x400E0740 +#define SAM4S_CHIPID_CIDR 0x400E0740 #define CHIPID_CIDR_VERSION_MASK (0x1F << 0) #define CHIPID_CIDR_EPROC_CM3 (0x03 << 5) +#define CHIPID_CIDR_EPROC_CM4 (0x07 << 5) #define CHIPID_CIDR_EPROC_MASK (0x07 << 5) #define CHIPID_CIDR_NVPSIZ_MASK (0x0F << 8) #define CHIPID_CIDR_NVPSIZ_128K (0x07 << 8) #define CHIPID_CIDR_NVPSIZ_256K (0x09 << 8) #define CHIPID_CIDR_NVPSIZ_512K (0x0A << 8) +#define CHIPID_CIDR_NVPSIZ_1024K (0x0C << 8) +#define CHIPID_CIDR_NVPSIZ_2048K (0x0E << 8) #define CHIPID_CIDR_NVPSIZ2_MASK (0x0F << 12) #define CHIPID_CIDR_SRAMSIZ_MASK (0x0F << 16) #define CHIPID_CIDR_ARCH_MASK (0xFF << 20) @@ -116,12 +133,16 @@ static const char sam3n_xml_memory_map[] = "" #define CHIPID_CIDR_ARCH_SAM3NxA (0x93 << 20) #define CHIPID_CIDR_ARCH_SAM3NxB (0x94 << 20) #define CHIPID_CIDR_ARCH_SAM3NxC (0x95 << 20) +#define CHIPID_CIDR_ARCH_SAM4SxA (0x88 << 20) +#define CHIPID_CIDR_ARCH_SAM4SxB (0x89 << 20) +#define CHIPID_CIDR_ARCH_SAM4SxC (0x8A << 20) #define CHIPID_CIDR_NVPTYP_MASK (0x07 << 28) #define CHIPID_CIDR_NVPTYP_FLASH (0x02 << 28) #define CHIPID_CIDR_NVPTYP_ROM_FLASH (0x03 << 28) #define CHIPID_CIDR_EXT (0x01 << 31) -#define PAGE_SIZE 256 +#define SAM3_PAGE_SIZE 256 +#define SAM4_PAGE_SIZE 512 bool sam3x_probe(struct target_s *target) { @@ -155,6 +176,19 @@ bool sam3x_probe(struct target_s *target) return true; } + target->idcode = adiv5_ap_mem_read(ap, SAM4S_CHIPID_CIDR); + switch (target->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { + case CHIPID_CIDR_ARCH_SAM4SxA | CHIPID_CIDR_EPROC_CM4: + case CHIPID_CIDR_ARCH_SAM4SxB | CHIPID_CIDR_EPROC_CM4: + case CHIPID_CIDR_ARCH_SAM4SxC | CHIPID_CIDR_EPROC_CM4: + target->driver = "Atmel SAM4S"; + target->xml_mem_map = sam4s_xml_memory_map; + target->flash_erase = sam3x_flash_erase; + target->flash_write = sam3x_flash_write; + target_add_commands(target, sam3x_cmd_list, "SAM4S"); + return true; + } + return false; } @@ -203,6 +237,33 @@ sam3x_flash_base(struct target_s *target, uint32_t addr, uint32_t *offset) } } + if (strcmp(target->driver, "Atmel SAM4S") == 0) { + uint32_t half = -1; + switch (target->idcode & CHIPID_CIDR_NVPSIZ_MASK) { + case CHIPID_CIDR_NVPSIZ_128K: + case CHIPID_CIDR_NVPSIZ_256K: + case CHIPID_CIDR_NVPSIZ_512K: + if (offset) + *offset = addr - 0x400000; + return SAM4S_EEFC_BASE(0); + case CHIPID_CIDR_NVPSIZ_1024K: + half = 0x480000; + break; + case CHIPID_CIDR_NVPSIZ_2048K: + half = 0x500000; + break; + } + if (addr >= half) { + if (offset) + *offset = addr - half; + return SAM4S_EEFC_BASE(1); + } else { + if (offset) + *offset = addr - 0x400000; + return SAM4S_EEFC_BASE(0); + } + } + /* SAM3N device */ if (offset) *offset = addr - 0x400000; @@ -211,10 +272,16 @@ sam3x_flash_base(struct target_s *target, uint32_t addr, uint32_t *offset) static int sam3x_flash_erase(struct target_s *target, uint32_t addr, int len) { + unsigned page_size; + if (strcmp(target->driver, "Atmel SAM4S") == 0) { + page_size = SAM4_PAGE_SIZE; + } else { + page_size = SAM3_PAGE_SIZE; + } uint32_t offset; uint32_t base = sam3x_flash_base(target, addr, &offset); - unsigned chunk = offset / PAGE_SIZE; - uint8_t buf[PAGE_SIZE]; + unsigned chunk = offset / page_size; + uint8_t buf[page_size]; /* This device doesn't really have a page erase function. * This Erase/Write page is the best we have, so we write with all @@ -223,14 +290,14 @@ static int sam3x_flash_erase(struct target_s *target, uint32_t addr, int len) memset(buf, 0xff, sizeof(buf)); /* Only do this once, since it doesn't change. */ - target_mem_write_words(target, addr, (void*)buf, PAGE_SIZE); + target_mem_write_words(target, addr, (void*)buf, page_size); while (len) { if(sam3x_flash_cmd(target, base, EEFC_FCR_FCMD_EWP, chunk)) return -1; - len -= PAGE_SIZE; - addr += PAGE_SIZE; + len -= page_size; + addr += page_size; chunk++; } @@ -240,12 +307,18 @@ static int sam3x_flash_erase(struct target_s *target, uint32_t addr, int len) static int sam3x_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src, int len) { + unsigned page_size; + if (strcmp(target->driver, "Atmel SAM4S") == 0) { + page_size = SAM4_PAGE_SIZE; + } else { + page_size = SAM3_PAGE_SIZE; + } uint32_t offset; uint32_t base = sam3x_flash_base(target, dest, &offset); - uint8_t buf[PAGE_SIZE]; - unsigned first_chunk = offset / PAGE_SIZE; - unsigned last_chunk = (offset + len - 1) / PAGE_SIZE; - offset %= PAGE_SIZE; + uint8_t buf[page_size]; + unsigned first_chunk = offset / page_size; + unsigned last_chunk = (offset + len - 1) / page_size; + offset %= page_size; dest -= offset; for (unsigned chunk = first_chunk; chunk <= last_chunk; chunk++) { @@ -258,7 +331,7 @@ static int sam3x_flash_write(struct target_s *target, uint32_t dest, memset(buf, 0xff, sizeof(buf)); /* copy as much as fits */ - int copylen = PAGE_SIZE - offset; + int copylen = page_size - offset; if (copylen > len) copylen = len; memcpy(&buf[offset], src, copylen); @@ -270,12 +343,12 @@ static int sam3x_flash_write(struct target_s *target, uint32_t dest, } else { /* interior chunk, must be aligned and full-sized */ - memcpy(buf, src, PAGE_SIZE); - len -= PAGE_SIZE; - src += PAGE_SIZE; + memcpy(buf, src, page_size); + len -= page_size; + src += page_size; } - target_mem_write_words(target, dest, (void*)buf, PAGE_SIZE); + target_mem_write_words(target, dest, (void*)buf, page_size); if(sam3x_flash_cmd(target, base, EEFC_FCR_FCMD_WP, chunk)) return -1; }