SAM4L: Add target driver for SAM4L
This commit adds a target driver for SAM4L and it depends on the extended reset change.
This commit is contained in:
parent
0aef6c6774
commit
469ecbf0f9
|
@ -103,8 +103,9 @@
|
||||||
/* Flash General Purpose Registers (low) */
|
/* Flash General Purpose Registers (low) */
|
||||||
#define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18)
|
#define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18)
|
||||||
|
|
||||||
static int sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len);
|
static void sam4l_extended_reset(target *t);
|
||||||
int sam4_flash_write(struct target_flash *f, target_addr dest,
|
static int sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len);
|
||||||
|
static int sam4l_flash_write_buf(struct target_flash *f, target_addr dest,
|
||||||
const void *src, size_t len);
|
const void *src, size_t len);
|
||||||
|
|
||||||
const struct command_s sam4l_cmds[] = {
|
const struct command_s sam4l_cmds[] = {
|
||||||
|
@ -171,18 +172,17 @@ static const size_t __nvp_size[16] = {
|
||||||
* Populate a target_flash struct with the necessary function pointers
|
* Populate a target_flash struct with the necessary function pointers
|
||||||
* and constants to describe our flash.
|
* and constants to describe our flash.
|
||||||
*/
|
*/
|
||||||
static void sam4_add_flash(target *t, uint32_t addr, size_t length)
|
static void sam4l_add_flash(target *t, uint32_t addr, size_t length)
|
||||||
{
|
{
|
||||||
struct target_flash *f = calloc(1, sizeof(struct target_flash));
|
struct target_flash *f = calloc(1, sizeof(struct target_flash));
|
||||||
f->start = addr;
|
f->start = addr;
|
||||||
f->length = length;
|
f->length = length;
|
||||||
f->blocksize = 512;
|
f->blocksize = 512;
|
||||||
f->erase = sam4_flash_erase;
|
f->erase = sam4l_flash_erase;
|
||||||
f->write = target_flash_write_buffered;
|
f->write = target_flash_write_buffered;
|
||||||
f->done = target_flash_done_buffered;
|
f->done = target_flash_done_buffered;
|
||||||
f->write_buf = sam4_flash_write;
|
f->write_buf = sam4l_flash_write_buf;
|
||||||
f->buf_size = 512;;
|
f->buf_size = 512;;
|
||||||
f->align = 512;
|
|
||||||
f->erased = 0xff;
|
f->erased = 0xff;
|
||||||
/* add it into the target structures flash chain */
|
/* add it into the target structures flash chain */
|
||||||
target_add_flash(t, f);
|
target_add_flash(t, f);
|
||||||
|
@ -220,7 +220,6 @@ static size_t sam_nvp_size(uint32_t idcode) {
|
||||||
#define SMAP_EXTID (SMAP_BASE + 0xf4)
|
#define SMAP_EXTID (SMAP_BASE + 0xf4)
|
||||||
#define SMAP_IDR (SMAP_BASE + 0xfc)
|
#define SMAP_IDR (SMAP_BASE + 0xfc)
|
||||||
|
|
||||||
static void sam4l_reset(target *t);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The probe function, look where the CIDR register should be, see if
|
* The probe function, look where the CIDR register should be, see if
|
||||||
|
@ -230,37 +229,29 @@ static void sam4l_reset(target *t);
|
||||||
*/
|
*/
|
||||||
bool sam4l_probe(target *t)
|
bool sam4l_probe(target *t)
|
||||||
{
|
{
|
||||||
uint32_t reg;
|
|
||||||
size_t ram_size, flash_size;
|
size_t ram_size, flash_size;
|
||||||
|
|
||||||
DEBUG("\nSAM4L: Probe function called\n");
|
DEBUG("\nSAM4L: Probe function called\n");
|
||||||
t->idcode = target_mem_read32(t, SAM4L_CHIPID_CIDR);
|
t->idcode = target_mem_read32(t, SAM4L_CHIPID_CIDR);
|
||||||
if (((t->idcode >> CHIPID_CIDR_ARCH_SHIFT) & CHIPID_CIDR_ARCH_MASK) == SAM4L_ARCH) {
|
if (((t->idcode >> CHIPID_CIDR_ARCH_SHIFT) & CHIPID_CIDR_ARCH_MASK) == SAM4L_ARCH) {
|
||||||
t->driver = "Atmel SAM4L";
|
t->driver = "Atmel SAM4L";
|
||||||
|
#ifdef SAM4_DISABLE_SRST
|
||||||
/* Check to see if our extended reset will fix this */
|
/* Check to see if our extended reset will fix this */
|
||||||
t->target_options |= CORTEXM_TOPT_INHIBIT_SRST;
|
t->target_options |= CORTEXM_TOPT_INHIBIT_SRST;
|
||||||
|
#endif
|
||||||
|
/* this option says we need to do "extra" stuff after reset */
|
||||||
t->target_options |= CORTEXM_TOPT_EXTENDED_RESET;
|
t->target_options |= CORTEXM_TOPT_EXTENDED_RESET;
|
||||||
t->extended_reset = sam4l_reset;
|
t->extended_reset = sam4l_extended_reset;
|
||||||
ram_size = sam_ram_size(t->idcode);
|
ram_size = sam_ram_size(t->idcode);
|
||||||
target_add_ram(t, 0x20000000, ram_size);
|
target_add_ram(t, 0x20000000, ram_size);
|
||||||
flash_size = sam_nvp_size(t->idcode);
|
flash_size = sam_nvp_size(t->idcode);
|
||||||
sam4_add_flash(t, 0x0, flash_size);
|
sam4l_add_flash(t, 0x0, flash_size);
|
||||||
DEBUG("\nSAM4L: RAM = 0x%x (%dK), FLASH = 0x%x (%dK)\n",
|
DEBUG("\nSAM4L: RAM = 0x%x (%dK), FLASH = 0x%x (%dK)\n",
|
||||||
ram_size, ram_size / 1024, flash_size, flash_size / 1024);
|
(unsigned int) ram_size, (unsigned int) (ram_size / 1024),
|
||||||
|
(unsigned int) flash_size, (unsigned int)(flash_size / 1024));
|
||||||
target_mem_write32(t, SMAP_CR, 0x1); /* enable SMAP */
|
|
||||||
DEBUG("\nSAM4L: SMAP Enabled\n");
|
|
||||||
DEBUG("\nSAM4L: Orig CHIPID = 0x%08lx\n", t->idcode);
|
|
||||||
reg = target_mem_read32(t, SMAP_CHIPID);
|
|
||||||
DEBUG("\nSAM4L: SMAP CHIPID = 0x%08lx\n", reg);
|
|
||||||
reg = target_mem_read32(t, SMAP_SR);
|
|
||||||
DEBUG("\nSAM4L: SMAP is %s\n", (reg & SMAP_SR_EN) ? "Enabled" : "Disabled");
|
|
||||||
DEBUG("\nSAM4L: Debugger is %s\n", (reg & SMAP_SR_DBGP) ? "Present" : "Not Present");
|
|
||||||
DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running");
|
|
||||||
sam4l_reset(t);
|
|
||||||
reg = target_mem_read32(t, SMAP_SR);
|
|
||||||
DEBUG("\nSAM4L: Core is %s\n", (reg & SMAP_SR_HCR) ? "In Reset" : "Running");
|
|
||||||
|
|
||||||
|
/* enable SMAP if not, check for HCR and reset if set */
|
||||||
|
sam4l_extended_reset(t);
|
||||||
DEBUG("\nSAM4L: SAM4L Selected.\n");
|
DEBUG("\nSAM4L: SAM4L Selected.\n");
|
||||||
if (target_check_error(t)) {
|
if (target_check_error(t)) {
|
||||||
DEBUG("SAM4L: target_check_error returned true\n");
|
DEBUG("SAM4L: target_check_error returned true\n");
|
||||||
|
@ -274,30 +265,34 @@ bool sam4l_probe(target *t)
|
||||||
* We've been reset, make sure we take the core out of reset
|
* We've been reset, make sure we take the core out of reset
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
sam4l_reset(target *t)
|
sam4l_extended_reset(target *t)
|
||||||
{
|
{
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DEBUG("SAM4L: Extended Reset\n");
|
DEBUG("SAM4L: Extended Reset\n");
|
||||||
|
/* enable SMAP in case we're dealing with a non-TCK SRST */
|
||||||
|
target_mem_write32(t, SMAP_CR, 0x1); /* enable SMAP */
|
||||||
reg = target_mem_read32(t, SMAP_SR);
|
reg = target_mem_read32(t, SMAP_SR);
|
||||||
DEBUG("\nSAM4L: SMAP_SR has 0x%08lx\n", reg);
|
DEBUG("\nSAM4L: SMAP_SR has 0x%08lx\n", (long unsigned int) reg);
|
||||||
if ((reg & SMAP_SR_HCR) != 0) {
|
if ((reg & SMAP_SR_HCR) != 0) {
|
||||||
|
/* write '1' bit to the status clear register */
|
||||||
target_mem_write32(t, SMAP_SCR, SMAP_SR_HCR);
|
target_mem_write32(t, SMAP_SCR, SMAP_SR_HCR);
|
||||||
i = 0;
|
/* waiting 250 loops for it to reset is arbitrary, it should happen right away */
|
||||||
do {
|
for (i = 0; i < 250; i++) {
|
||||||
reg = target_mem_read32(t, SMAP_SR);
|
reg = target_mem_read32(t, SMAP_SR);
|
||||||
i++;
|
}
|
||||||
} while (((reg & SMAP_SR_HCR) != 0) && (i < 100));
|
/* not sure what to do if we can't reset that bit */
|
||||||
if (i == 100) {
|
if (i > 249) {
|
||||||
DEBUG("\nSAM4L: Reset failed. SMAP_SR has 0x%08lx\n", reg);
|
DEBUG("\nSAM4L: Reset failed. SMAP_SR has 0x%08lx\n", (long unsigned int) reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* reset bus error if for some reason SMAP was disabled */
|
||||||
target_check_error(t);
|
target_check_error(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sam4_flash_command
|
* sam4l_flash_command
|
||||||
*
|
*
|
||||||
* Helper function, wait for the flash controller to be ready to receive a
|
* Helper function, wait for the flash controller to be ready to receive a
|
||||||
* command. Then send it the command, page number, and the authorization
|
* command. Then send it the command, page number, and the authorization
|
||||||
|
@ -307,13 +302,14 @@ sam4l_reset(target *t)
|
||||||
* pointers.
|
* pointers.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
sam4_flash_command(target *t, uint32_t page, uint32_t cmd)
|
sam4l_flash_command(target *t, uint32_t page, uint32_t cmd)
|
||||||
{
|
{
|
||||||
uint32_t cmd_reg;
|
uint32_t cmd_reg;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
int timeout;
|
int timeout;
|
||||||
DEBUG("\nSAM4L: sam4_flash_command: FSR: 0x%08x, page = %d, command = %d\n",
|
DEBUG("\nSAM4L: sam4l_flash_command: FSR: 0x%08x, page = %d, command = %d\n",
|
||||||
(unsigned int)(FLASHCALW_FSR), (int) page, (int) cmd);
|
(unsigned int)(FLASHCALW_FSR), (int) page, (int) cmd);
|
||||||
|
/* wait for Flash controller ready */
|
||||||
for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) {
|
for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) {
|
||||||
status = target_mem_read32(t, FLASHCALW_FSR);
|
status = target_mem_read32(t, FLASHCALW_FSR);
|
||||||
if (status & FLASHCALW_FSR_FRDY) {
|
if (status & FLASHCALW_FSR_FRDY) {
|
||||||
|
@ -321,14 +317,17 @@ sam4_flash_command(target *t, uint32_t page, uint32_t cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (timeout == FLASH_TIMEOUT) {
|
if (timeout == FLASH_TIMEOUT) {
|
||||||
DEBUG("\nSAM4L: sam4_flash_command: Not ready! Status = 0x%08x\n", (unsigned int) status);
|
DEBUG("\nSAM4L: sam4l_flash_command: Not ready! Status = 0x%08x\n", (unsigned int) status);
|
||||||
return -1; /* Failed */
|
return -1; /* Failed */
|
||||||
}
|
}
|
||||||
|
/* load up the new command */
|
||||||
cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) |
|
cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) |
|
||||||
((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) |
|
((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) |
|
||||||
(0xA5 << FLASHCALW_FCMD_KEY_SHIFT);
|
(0xA5 << FLASHCALW_FCMD_KEY_SHIFT);
|
||||||
DEBUG("\nSAM4L: sam4_flash_command: Wrting command word 0x%08x\n", (unsigned int) cmd_reg);
|
DEBUG("\nSAM4L: sam4l_flash_command: Wrting command word 0x%08x\n", (unsigned int) cmd_reg);
|
||||||
|
/* and kick it off */
|
||||||
target_mem_write32(t, FLASHCALW_FCMD, cmd_reg);
|
target_mem_write32(t, FLASHCALW_FCMD, cmd_reg);
|
||||||
|
/* don't actually wait for it to finish, the next command will stall if it is not done */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,30 +335,31 @@ sam4_flash_command(target *t, uint32_t page, uint32_t cmd)
|
||||||
* Write data from 'src' into flash using the algorithim provided by
|
* Write data from 'src' into flash using the algorithim provided by
|
||||||
* Atmel in their data sheet.
|
* Atmel in their data sheet.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size_t len)
|
sam4l_flash_write_buf(struct target_flash *f, target_addr addr, const void *src, size_t len)
|
||||||
{
|
{
|
||||||
target *t = f->t;
|
target *t = f->t;
|
||||||
uint32_t *src_data = (uint32_t *)src;
|
uint32_t *src_data = (uint32_t *)src;
|
||||||
|
uint32_t ndx;
|
||||||
uint16_t page;
|
uint16_t page;
|
||||||
|
|
||||||
DEBUG("\nSAM4L: sam4_flash_write: addr = 0x%08lx, len %d\n", addr, len);
|
DEBUG("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08lx, len %d\n", (long unsigned int) addr, (int) len);
|
||||||
/* This will fail with unaligned writes */
|
/* This will fail with unaligned writes, the write_buf version */
|
||||||
while (len) {
|
while (len) {
|
||||||
|
|
||||||
page = addr / SAM4L_PAGE_SIZE;
|
page = addr / SAM4L_PAGE_SIZE;
|
||||||
|
|
||||||
/* clear the page buffer */
|
/* clear the page buffer */
|
||||||
if (sam4_flash_command(t, 0, FLASH_CMD_CPB)) {
|
if (sam4l_flash_command(t, 0, FLASH_CMD_CPB)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Fill it with data to write */
|
|
||||||
target_mem_write(t, addr, src_data, SAM4L_PAGE_SIZE);
|
/* Now fill page buffer with our 512 bytes of data */
|
||||||
#if 0
|
|
||||||
for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) {
|
/* I did try to use target_mem_write however that resulted in the
|
||||||
/*
|
* last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...)
|
||||||
target_mem_write32(t, addr, *src_data);
|
* since it works this way I've not investigated further.
|
||||||
addr += 4;
|
|
||||||
*/
|
*/
|
||||||
|
for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) {
|
||||||
/*
|
/*
|
||||||
* the page buffer overlaps flash, its only 512 bytes long
|
* the page buffer overlaps flash, its only 512 bytes long
|
||||||
* and no matter where you write it from it goes to the page
|
* and no matter where you write it from it goes to the page
|
||||||
|
@ -370,11 +370,11 @@ sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size
|
||||||
target_mem_write32(t, addr+ndx, *src_data);
|
target_mem_write32(t, addr+ndx, *src_data);
|
||||||
src_data++;
|
src_data++;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/* write the page */
|
/* write the page */
|
||||||
if (sam4_flash_command(t, page, FLASH_CMD_WP)) {
|
if (sam4l_flash_command(t, page, FLASH_CMD_WP)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
/* it should be done after one page, but in case it isn't */
|
||||||
len -= SAM4L_PAGE_SIZE;
|
len -= SAM4L_PAGE_SIZE;
|
||||||
addr += SAM4L_PAGE_SIZE;
|
addr += SAM4L_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -385,19 +385,22 @@ sam4_flash_write(struct target_flash *f, target_addr addr, const void *src, size
|
||||||
* Erase flash across the addresses specified by addr and len
|
* Erase flash across the addresses specified by addr and len
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
sam4_flash_erase(struct target_flash *f, target_addr addr, size_t len)
|
sam4l_flash_erase(struct target_flash *f, target_addr addr, size_t len)
|
||||||
{
|
{
|
||||||
target *t = f->t;
|
target *t = f->t;
|
||||||
uint16_t page;
|
uint16_t page;
|
||||||
|
|
||||||
DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n",
|
DEBUG("SAM4L: flash erase address 0x%08x for %d bytes\n",
|
||||||
(unsigned int) addr, (unsigned int) len);
|
(unsigned int) addr, (unsigned int) len);
|
||||||
/* force len to be an integral number of pages */
|
/*
|
||||||
/* len = (len + (SAM4_PAGE_SIZE - 1)) & ~SAM4_PAGE_SIZE; */
|
* NB: if addr isn't aligned to a page boundary, or length
|
||||||
|
* is not an even multiple of page sizes, we may end up
|
||||||
|
* erasing data we didn't intend to.
|
||||||
|
*/
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
page = addr / SAM4_PAGE_SIZE;
|
page = addr / SAM4_PAGE_SIZE;
|
||||||
if (sam4_flash_command(t, page, FLASH_CMD_EP)) {
|
if (sam4l_flash_command(t, page, FLASH_CMD_EP)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
len -= SAM4_PAGE_SIZE;
|
len -= SAM4_PAGE_SIZE;
|
||||||
|
|
Loading…
Reference in New Issue