lpc: Reduce differences between lpc11xx and lpc43xx code.
This commit is contained in:
parent
54eb3a719f
commit
cd5d569d38
|
@ -195,14 +195,6 @@ static const char tdesc_cortex_mf[] =
|
||||||
" </feature>"
|
" </feature>"
|
||||||
"</target>";
|
"</target>";
|
||||||
|
|
||||||
#define REG_SP 13
|
|
||||||
#define REG_LR 14
|
|
||||||
#define REG_PC 15
|
|
||||||
#define REG_XPSR 16
|
|
||||||
#define REG_MSP 17
|
|
||||||
#define REG_PSP 18
|
|
||||||
#define REG_SPECIAL 19
|
|
||||||
|
|
||||||
bool cortexm_probe(target *t)
|
bool cortexm_probe(target *t)
|
||||||
{
|
{
|
||||||
t->driver = cortexm_driver_str;
|
t->driver = cortexm_driver_str;
|
||||||
|
|
|
@ -143,6 +143,16 @@
|
||||||
#define CORTEXM_DWT_FUNC_FUNC_WRITE (6 << 0)
|
#define CORTEXM_DWT_FUNC_FUNC_WRITE (6 << 0)
|
||||||
#define CORTEXM_DWT_FUNC_FUNC_ACCESS (7 << 0)
|
#define CORTEXM_DWT_FUNC_FUNC_ACCESS (7 << 0)
|
||||||
|
|
||||||
|
#define REG_SP 13
|
||||||
|
#define REG_LR 14
|
||||||
|
#define REG_PC 15
|
||||||
|
#define REG_XPSR 16
|
||||||
|
#define REG_MSP 17
|
||||||
|
#define REG_PSP 18
|
||||||
|
#define REG_SPECIAL 19
|
||||||
|
|
||||||
|
#define ARM_THUMB_BREAKPOINT 0xBE00
|
||||||
|
|
||||||
bool cortexm_attach(target *t);
|
bool cortexm_attach(target *t);
|
||||||
void cortexm_detach(target *t);
|
void cortexm_detach(target *t);
|
||||||
void cortexm_halt_resume(target *t, bool step);
|
void cortexm_halt_resume(target *t, bool step);
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Black Magic Debug project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LPC_COMMON_H
|
||||||
|
#define __LPC_COMMON_H
|
||||||
|
|
||||||
|
#define IAP_CMD_INIT 49
|
||||||
|
#define IAP_CMD_PREPARE 50
|
||||||
|
#define IAP_CMD_PROGRAM 51
|
||||||
|
#define IAP_CMD_ERASE 52
|
||||||
|
#define IAP_CMD_BLANKCHECK 53
|
||||||
|
#define IAP_CMD_SET_ACTIVE_BANK 60
|
||||||
|
|
||||||
|
#define IAP_STATUS_CMD_SUCCESS 0
|
||||||
|
#define IAP_STATUS_INVALID_COMMAND 1
|
||||||
|
#define IAP_STATUS_SRC_ADDR_ERROR 2
|
||||||
|
#define IAP_STATUS_DST_ADDR_ERROR 3
|
||||||
|
#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4
|
||||||
|
#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5
|
||||||
|
#define IAP_STATUS_COUNT_ERROR 6
|
||||||
|
#define IAP_STATUS_INVALID_SECTOR 7
|
||||||
|
#define IAP_STATUS_SECTOR_NOT_BLANK 8
|
||||||
|
#define IAP_STATUS_SECTOR_NOT_PREPARED 9
|
||||||
|
#define IAP_STATUS_COMPARE_ERROR 10
|
||||||
|
#define IAP_STATUS_BUSY 11
|
||||||
|
|
||||||
|
/* CPU Frequency */
|
||||||
|
#define CPU_CLK_KHZ 12000
|
||||||
|
|
||||||
|
struct flash_param {
|
||||||
|
uint16_t opcode;/* opcode to return to after calling the ROM */
|
||||||
|
uint16_t pad0;
|
||||||
|
uint32_t command;/* IAP command */
|
||||||
|
union {
|
||||||
|
uint32_t words[5];/* command parameters */
|
||||||
|
struct {
|
||||||
|
uint32_t start_sector;
|
||||||
|
uint32_t end_sector;
|
||||||
|
uint32_t flash_bank;
|
||||||
|
} prepare;
|
||||||
|
struct {
|
||||||
|
uint32_t start_sector;
|
||||||
|
uint32_t end_sector;
|
||||||
|
uint32_t cpu_clk_khz;
|
||||||
|
uint32_t flash_bank;
|
||||||
|
} erase;
|
||||||
|
struct {
|
||||||
|
uint32_t dest;
|
||||||
|
uint32_t source;
|
||||||
|
uint32_t byte_count;
|
||||||
|
uint32_t cpu_clk_khz;
|
||||||
|
} program;
|
||||||
|
struct {
|
||||||
|
uint32_t start_sector;
|
||||||
|
uint32_t end_sector;
|
||||||
|
uint32_t flash_bank;
|
||||||
|
} blank_check;
|
||||||
|
struct {
|
||||||
|
uint32_t flash_bank;
|
||||||
|
uint32_t cpu_clk_khz;
|
||||||
|
} make_active;
|
||||||
|
};
|
||||||
|
uint32_t result[5]; /* result data */
|
||||||
|
} __attribute__((aligned(4)));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2011 Mike Smith <drziplok@me.com>
|
||||||
|
* Copyright (C) 2015 Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ -14,26 +17,15 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "adiv5.h"
|
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
#include "lpc_common.h"
|
||||||
|
|
||||||
#define IAP_PGM_CHUNKSIZE 256 /* should fit in RAM on any device */
|
#define IAP_PGM_CHUNKSIZE 256 /* should fit in RAM on any device */
|
||||||
|
|
||||||
struct flash_param {
|
|
||||||
uint16_t opcodes[2]; /* two opcodes to return to after calling the ROM */
|
|
||||||
uint32_t command[5]; /* command operands */
|
|
||||||
uint32_t result[4]; /* result data */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_program {
|
|
||||||
struct flash_param p;
|
|
||||||
uint8_t data[IAP_PGM_CHUNKSIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct flash_program flash_pgm;
|
|
||||||
|
|
||||||
#define MSP 17 /* Main stack pointer register number */
|
|
||||||
#define MIN_RAM_SIZE_FOR_LPC8xx 1024
|
#define MIN_RAM_SIZE_FOR_LPC8xx 1024
|
||||||
#define MIN_RAM_SIZE_FOR_LPC1xxx 2048
|
#define MIN_RAM_SIZE_FOR_LPC1xxx 2048
|
||||||
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
|
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
|
||||||
|
@ -41,24 +33,6 @@ static struct flash_program flash_pgm;
|
||||||
#define IAP_ENTRYPOINT 0x1fff1ff1
|
#define IAP_ENTRYPOINT 0x1fff1ff1
|
||||||
#define IAP_RAM_BASE 0x10000000
|
#define IAP_RAM_BASE 0x10000000
|
||||||
|
|
||||||
#define IAP_CMD_PREPARE 50
|
|
||||||
#define IAP_CMD_PROGRAM 51
|
|
||||||
#define IAP_CMD_ERASE 52
|
|
||||||
#define IAP_CMD_BLANKCHECK 53
|
|
||||||
|
|
||||||
#define IAP_STATUS_CMD_SUCCESS 0
|
|
||||||
#define IAP_STATUS_INVALID_COMMAND 1
|
|
||||||
#define IAP_STATUS_SRC_ADDR_ERROR 2
|
|
||||||
#define IAP_STATUS_DST_ADDR_ERROR 3
|
|
||||||
#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4
|
|
||||||
#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5
|
|
||||||
#define IAP_STATUS_COUNT_ERROR 6
|
|
||||||
#define IAP_STATUS_INVALID_SECTOR 7
|
|
||||||
#define IAP_STATUS_SECTOR_NOT_BLANK 8
|
|
||||||
#define IAP_STATUS_SECTOR_NOT_PREPARED 9
|
|
||||||
#define IAP_STATUS_COMPARE_ERROR 10
|
|
||||||
#define IAP_STATUS_BUSY 11
|
|
||||||
|
|
||||||
static const char lpc8xx_driver[] = "lpc8xx";
|
static const char lpc8xx_driver[] = "lpc8xx";
|
||||||
static const char lpc11xx_driver[] = "lpc11xx";
|
static const char lpc11xx_driver[] = "lpc11xx";
|
||||||
static void lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len);
|
static void lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len);
|
||||||
|
@ -67,6 +41,11 @@ static int lpc11xx_flash_erase(target *t, uint32_t addr, size_t len);
|
||||||
static int lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src,
|
static int lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
|
struct flash_program {
|
||||||
|
struct flash_param p;
|
||||||
|
uint8_t data[IAP_PGM_CHUNKSIZE];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that this memory map is actually for the largest of the lpc11xx devices;
|
* Note that this memory map is actually for the largest of the lpc11xx devices;
|
||||||
* There seems to be no good way to decode the part number to determine the RAM
|
* There seems to be no good way to decode the part number to determine the RAM
|
||||||
|
@ -168,8 +147,8 @@ lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len)
|
||||||
uint32_t regs[t->regs_size / sizeof(uint32_t)];
|
uint32_t regs[t->regs_size / sizeof(uint32_t)];
|
||||||
|
|
||||||
/* fill out the remainder of the parameters and copy the structure to RAM */
|
/* fill out the remainder of the parameters and copy the structure to RAM */
|
||||||
param->opcodes[0] = 0xbe00;
|
param->opcode = ARM_THUMB_BREAKPOINT;
|
||||||
param->opcodes[1] = 0x0000;
|
param->pad0 = 0x0000;
|
||||||
target_mem_write(t, IAP_RAM_BASE, param, param_len);
|
target_mem_write(t, IAP_RAM_BASE, param, param_len);
|
||||||
|
|
||||||
/* set up for the call to the IAP ROM */
|
/* set up for the call to the IAP ROM */
|
||||||
|
@ -179,11 +158,11 @@ lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len)
|
||||||
|
|
||||||
// stack pointer - top of the smallest ram less 32 for IAP usage
|
// stack pointer - top of the smallest ram less 32 for IAP usage
|
||||||
if (t->driver == lpc8xx_driver)
|
if (t->driver == lpc8xx_driver)
|
||||||
regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES;
|
regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES;
|
||||||
else
|
else
|
||||||
regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES;
|
regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES;
|
||||||
regs[14] = IAP_RAM_BASE | 1;
|
regs[REG_LR] = IAP_RAM_BASE | 1;
|
||||||
regs[15] = IAP_ENTRYPOINT;
|
regs[REG_PC] = IAP_ENTRYPOINT;
|
||||||
target_regs_write(t, regs);
|
target_regs_write(t, regs);
|
||||||
|
|
||||||
/* start the target and wait for it to halt again */
|
/* start the target and wait for it to halt again */
|
||||||
|
@ -205,11 +184,12 @@ static int flash_page_size(target *t)
|
||||||
static int
|
static int
|
||||||
lpc11xx_flash_prepare(target *t, uint32_t addr, int len)
|
lpc11xx_flash_prepare(target *t, uint32_t addr, int len)
|
||||||
{
|
{
|
||||||
|
struct flash_program flash_pgm;
|
||||||
/* prepare the sector(s) to be erased */
|
/* prepare the sector(s) to be erased */
|
||||||
memset(&flash_pgm.p, 0, sizeof(flash_pgm.p));
|
memset(&flash_pgm.p, 0, sizeof(flash_pgm.p));
|
||||||
flash_pgm.p.command[0] = IAP_CMD_PREPARE;
|
flash_pgm.p.command = IAP_CMD_PREPARE;
|
||||||
flash_pgm.p.command[1] = addr / flash_page_size(t);
|
flash_pgm.p.prepare.start_sector = addr / flash_page_size(t);
|
||||||
flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t);
|
flash_pgm.p.prepare.end_sector = (addr + len - 1) / flash_page_size(t);
|
||||||
|
|
||||||
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -222,6 +202,7 @@ lpc11xx_flash_prepare(target *t, uint32_t addr, int len)
|
||||||
static int
|
static int
|
||||||
lpc11xx_flash_erase(target *t, uint32_t addr, size_t len)
|
lpc11xx_flash_erase(target *t, uint32_t addr, size_t len)
|
||||||
{
|
{
|
||||||
|
struct flash_program flash_pgm;
|
||||||
|
|
||||||
if (addr % flash_page_size(t))
|
if (addr % flash_page_size(t))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -231,15 +212,18 @@ lpc11xx_flash_erase(target *t, uint32_t addr, size_t len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* and now erase them */
|
/* and now erase them */
|
||||||
flash_pgm.p.command[0] = IAP_CMD_ERASE;
|
flash_pgm.p.command = IAP_CMD_ERASE;
|
||||||
flash_pgm.p.command[1] = addr / flash_page_size(t);
|
flash_pgm.p.erase.start_sector = addr / flash_page_size(t);
|
||||||
flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t);
|
flash_pgm.p.erase.end_sector = (addr + len - 1) / flash_page_size(t);
|
||||||
flash_pgm.p.command[3] = 12000; /* XXX safe to assume this? */
|
flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
flash_pgm.p.command[0] = IAP_CMD_BLANKCHECK;
|
|
||||||
|
/* check erase ok */
|
||||||
|
flash_pgm.p.command = IAP_CMD_BLANKCHECK;
|
||||||
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -255,6 +239,7 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
|
||||||
unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE;
|
unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE;
|
||||||
unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE;
|
unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE;
|
||||||
unsigned chunk;
|
unsigned chunk;
|
||||||
|
struct flash_program flash_pgm;
|
||||||
|
|
||||||
for (chunk = first_chunk; chunk <= last_chunk; chunk++) {
|
for (chunk = first_chunk; chunk <= last_chunk; chunk++) {
|
||||||
|
|
||||||
|
@ -269,8 +254,8 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
|
||||||
size_t copylen = IAP_PGM_CHUNKSIZE - chunk_offset;
|
size_t copylen = IAP_PGM_CHUNKSIZE - chunk_offset;
|
||||||
if (copylen > len)
|
if (copylen > len)
|
||||||
copylen = len;
|
copylen = len;
|
||||||
memcpy(&flash_pgm.data[chunk_offset], src, copylen);
|
|
||||||
|
|
||||||
|
memcpy(flash_pgm.data + chunk_offset, src, copylen);
|
||||||
/* if we are programming the vectors, calculate the magic number */
|
/* if we are programming the vectors, calculate the magic number */
|
||||||
if ((chunk == 0) && (chunk_offset == 0)) {
|
if ((chunk == 0) && (chunk_offset == 0)) {
|
||||||
if (copylen < 32) {
|
if (copylen < 32) {
|
||||||
|
@ -290,9 +275,7 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
src += copylen;
|
src += copylen;
|
||||||
chunk_offset = 0;
|
chunk_offset = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* interior chunk, must be aligned and full-sized */
|
/* interior chunk, must be aligned and full-sized */
|
||||||
memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE);
|
memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE);
|
||||||
len -= IAP_PGM_CHUNKSIZE;
|
len -= IAP_PGM_CHUNKSIZE;
|
||||||
|
@ -304,12 +287,12 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* set the destination address and program */
|
/* set the destination address and program */
|
||||||
flash_pgm.p.command[0] = IAP_CMD_PROGRAM;
|
flash_pgm.p.command = IAP_CMD_PROGRAM;
|
||||||
flash_pgm.p.command[1] = chunk * IAP_PGM_CHUNKSIZE;
|
flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE;
|
||||||
flash_pgm.p.command[2] = IAP_RAM_BASE + offsetof(struct flash_program, data);
|
flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data);
|
||||||
flash_pgm.p.command[3] = IAP_PGM_CHUNKSIZE;
|
flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE;
|
||||||
/* assuming we are running off IRC - safe lower bound */
|
flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
flash_pgm.p.command[4] = 12000; /* XXX safe to presume this? */
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
144
src/lpc43xx.c
144
src/lpc43xx.c
|
@ -1,7 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the Black Magic Debug project.
|
* This file is part of the Black Magic Debug project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Gareth McMullin <gareth@blacksphere.co.nz>
|
* Copyright (C) 2014 Allen Ibara <aibara>
|
||||||
|
* Copyright (C) 2015 Gareth McMullin <gareth@blacksphere.co.nz>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,17 +20,13 @@
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "adiv5.h"
|
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "gdb_packet.h"
|
#include "gdb_packet.h"
|
||||||
|
#include "cortexm.h"
|
||||||
|
#include "lpc_common.h"
|
||||||
|
|
||||||
#define LPC43XX_CHIPID 0x40043200
|
#define LPC43XX_CHIPID 0x40043200
|
||||||
#define ARM_CPUID 0xE000ED00
|
#define ARM_CPUID 0xE000ED00
|
||||||
#define ARM_THUMB_BREAKPOINT 0xBE00
|
|
||||||
|
|
||||||
#define R_MSP 17 // Main stack pointer register number
|
|
||||||
#define R_PC 15 // Program counter register number
|
|
||||||
#define R_LR 14 // Link register number
|
|
||||||
|
|
||||||
#define IAP_ENTRYPOINT_LOCATION 0x10400100
|
#define IAP_ENTRYPOINT_LOCATION 0x10400100
|
||||||
|
|
||||||
|
@ -47,25 +44,6 @@
|
||||||
|
|
||||||
#define IAP_PGM_CHUNKSIZE 4096
|
#define IAP_PGM_CHUNKSIZE 4096
|
||||||
|
|
||||||
#define IAP_CMD_INIT 49
|
|
||||||
#define IAP_CMD_PREPARE 50
|
|
||||||
#define IAP_CMD_PROGRAM 51
|
|
||||||
#define IAP_CMD_ERASE 52
|
|
||||||
#define IAP_CMD_BLANKCHECK 53
|
|
||||||
#define IAP_CMD_SET_ACTIVE_BANK 60
|
|
||||||
|
|
||||||
#define IAP_STATUS_CMD_SUCCESS 0
|
|
||||||
#define IAP_STATUS_INVALID_COMMAND 1
|
|
||||||
#define IAP_STATUS_SRC_ADDR_ERROR 2
|
|
||||||
#define IAP_STATUS_DST_ADDR_ERROR 3
|
|
||||||
#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4
|
|
||||||
#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5
|
|
||||||
#define IAP_STATUS_COUNT_ERROR 6
|
|
||||||
#define IAP_STATUS_INVALID_SECTOR 7
|
|
||||||
#define IAP_STATUS_SECTOR_NOT_BLANK 8
|
|
||||||
#define IAP_STATUS_SECTOR_NOT_PREPARED 9
|
|
||||||
#define IAP_STATUS_COMPARE_ERROR 10
|
|
||||||
#define IAP_STATUS_BUSY 11
|
|
||||||
|
|
||||||
#define FLASH_BANK_A_BASE 0x1A000000
|
#define FLASH_BANK_A_BASE 0x1A000000
|
||||||
#define FLASH_BANK_A_SIZE 0x80000
|
#define FLASH_BANK_A_SIZE 0x80000
|
||||||
|
@ -75,45 +53,6 @@
|
||||||
#define FLASH_NUM_SECTOR 15
|
#define FLASH_NUM_SECTOR 15
|
||||||
#define FLASH_LARGE_SECTOR_OFFSET 0x00010000
|
#define FLASH_LARGE_SECTOR_OFFSET 0x00010000
|
||||||
|
|
||||||
/* CPU Frequency */
|
|
||||||
#define CPU_CLK_KHZ 12000
|
|
||||||
|
|
||||||
struct flash_param {
|
|
||||||
uint16_t opcode; /* opcode to return to after calling the ROM */
|
|
||||||
uint16_t pad0;
|
|
||||||
uint32_t command; /* IAP command */
|
|
||||||
union {
|
|
||||||
uint32_t words[5]; /* command parameters */
|
|
||||||
struct {
|
|
||||||
uint32_t start_sector;
|
|
||||||
uint32_t end_sector;
|
|
||||||
uint32_t flash_bank;
|
|
||||||
} prepare;
|
|
||||||
struct {
|
|
||||||
uint32_t start_sector;
|
|
||||||
uint32_t end_sector;
|
|
||||||
uint32_t cpu_clk_khz;
|
|
||||||
uint32_t flash_bank;
|
|
||||||
} erase;
|
|
||||||
struct {
|
|
||||||
uint32_t dest;
|
|
||||||
uint32_t source;
|
|
||||||
uint32_t byte_count;
|
|
||||||
uint32_t cpu_clk_khz;
|
|
||||||
} program;
|
|
||||||
struct {
|
|
||||||
uint32_t start_sector;
|
|
||||||
uint32_t end_sector;
|
|
||||||
uint32_t flash_bank;
|
|
||||||
} blank_check;
|
|
||||||
struct {
|
|
||||||
uint32_t flash_bank;
|
|
||||||
uint32_t cpu_clk_khz;
|
|
||||||
} make_active;
|
|
||||||
} params;
|
|
||||||
uint32_t result[5]; /* result data */
|
|
||||||
} __attribute__((aligned(4)));
|
|
||||||
|
|
||||||
struct flash_program {
|
struct flash_program {
|
||||||
struct flash_param p;
|
struct flash_param p;
|
||||||
uint8_t data[IAP_PGM_CHUNKSIZE];
|
uint8_t data[IAP_PGM_CHUNKSIZE];
|
||||||
|
@ -242,9 +181,9 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[])
|
||||||
for (bank = 0; bank < FLASH_NUM_BANK; bank++)
|
for (bank = 0; bank < FLASH_NUM_BANK; bank++)
|
||||||
{
|
{
|
||||||
flash_pgm.p.command = IAP_CMD_PREPARE;
|
flash_pgm.p.command = IAP_CMD_PREPARE;
|
||||||
flash_pgm.p.params.prepare.start_sector = 0;
|
flash_pgm.p.prepare.start_sector = 0;
|
||||||
flash_pgm.p.params.prepare.end_sector = FLASH_NUM_SECTOR-1;
|
flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1;
|
||||||
flash_pgm.p.params.prepare.flash_bank = bank;
|
flash_pgm.p.prepare.flash_bank = bank;
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -252,10 +191,10 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
flash_pgm.p.command = IAP_CMD_ERASE;
|
flash_pgm.p.command = IAP_CMD_ERASE;
|
||||||
flash_pgm.p.params.erase.start_sector = 0;
|
flash_pgm.p.erase.start_sector = 0;
|
||||||
flash_pgm.p.params.prepare.end_sector = FLASH_NUM_SECTOR-1;
|
flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1;
|
||||||
flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ;
|
flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
flash_pgm.p.params.erase.flash_bank = bank;
|
flash_pgm.p.erase.flash_bank = bank;
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS)
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS)
|
||||||
|
@ -343,8 +282,8 @@ static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned para
|
||||||
target_mem_read(t, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry));
|
target_mem_read(t, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry));
|
||||||
|
|
||||||
/* fill out the remainder of the parameters and copy the structure to RAM */
|
/* fill out the remainder of the parameters and copy the structure to RAM */
|
||||||
param->opcode = ARM_THUMB_BREAKPOINT; /* breakpoint */
|
param->opcode = ARM_THUMB_BREAKPOINT;
|
||||||
param->pad0 = 0x0000; /* pad */
|
param->pad0 = 0x0000;
|
||||||
target_mem_write(t, IAP_RAM_BASE, param, param_len);
|
target_mem_write(t, IAP_RAM_BASE, param, param_len);
|
||||||
|
|
||||||
/* set up for the call to the IAP ROM */
|
/* set up for the call to the IAP ROM */
|
||||||
|
@ -352,9 +291,9 @@ static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned para
|
||||||
regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command);
|
regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command);
|
||||||
regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result);
|
regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result);
|
||||||
|
|
||||||
regs[R_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE;
|
regs[REG_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE;
|
||||||
regs[R_LR] = IAP_RAM_BASE | 1;
|
regs[REG_LR] = IAP_RAM_BASE | 1;
|
||||||
regs[R_PC] = iap_entry;
|
regs[REG_PC] = iap_entry;
|
||||||
target_regs_write(t, regs);
|
target_regs_write(t, regs);
|
||||||
|
|
||||||
/* start the target and wait for it to halt again */
|
/* start the target and wait for it to halt again */
|
||||||
|
@ -370,11 +309,11 @@ static int lpc43xx_flash_prepare(target *t, uint32_t addr, int len)
|
||||||
struct flash_program flash_pgm;
|
struct flash_program flash_pgm;
|
||||||
|
|
||||||
/* prepare the sector(s) to be erased */
|
/* prepare the sector(s) to be erased */
|
||||||
|
memset(&flash_pgm.p, 0, sizeof(flash_pgm.p));
|
||||||
flash_pgm.p.command = IAP_CMD_PREPARE;
|
flash_pgm.p.command = IAP_CMD_PREPARE;
|
||||||
flash_pgm.p.params.prepare.start_sector = sector_number(addr);
|
flash_pgm.p.prepare.start_sector = sector_number(addr);
|
||||||
flash_pgm.p.params.prepare.end_sector = sector_number(addr+len);
|
flash_pgm.p.prepare.end_sector = sector_number(addr+len);
|
||||||
flash_pgm.p.params.prepare.flash_bank = flash_bank(addr);
|
flash_pgm.p.prepare.flash_bank = flash_bank(addr);
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
|
||||||
|
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -402,10 +341,10 @@ static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len)
|
||||||
|
|
||||||
/* and now erase them */
|
/* and now erase them */
|
||||||
flash_pgm.p.command = IAP_CMD_ERASE;
|
flash_pgm.p.command = IAP_CMD_ERASE;
|
||||||
flash_pgm.p.params.erase.start_sector = sector_number(addr);
|
flash_pgm.p.erase.start_sector = sector_number(addr);
|
||||||
flash_pgm.p.params.erase.end_sector = sector_number(addr+len);
|
flash_pgm.p.erase.end_sector = sector_number(addr+len);
|
||||||
flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ;
|
flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
flash_pgm.p.params.erase.flash_bank = flash_bank(addr);
|
flash_pgm.p.erase.flash_bank = flash_bank(addr);
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -414,9 +353,9 @@ static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len)
|
||||||
|
|
||||||
/* check erase ok */
|
/* check erase ok */
|
||||||
flash_pgm.p.command = IAP_CMD_BLANKCHECK;
|
flash_pgm.p.command = IAP_CMD_BLANKCHECK;
|
||||||
flash_pgm.p.params.blank_check.start_sector = sector_number(addr);
|
flash_pgm.p.blank_check.start_sector = sector_number(addr);
|
||||||
flash_pgm.p.params.blank_check.end_sector = sector_number(addr+len);
|
flash_pgm.p.blank_check.end_sector = sector_number(addr+len);
|
||||||
flash_pgm.p.params.blank_check.flash_bank = flash_bank(addr);
|
flash_pgm.p.blank_check.flash_bank = flash_bank(addr);
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -437,17 +376,13 @@ static int lpc43xx_flash_write(target *t,
|
||||||
{
|
{
|
||||||
unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE;
|
unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE;
|
||||||
unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE;
|
unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE;
|
||||||
unsigned chunk_offset;
|
unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE;
|
||||||
unsigned chunk;
|
unsigned chunk;
|
||||||
struct flash_program flash_pgm;
|
struct flash_program flash_pgm;
|
||||||
|
|
||||||
for (chunk = first_chunk; chunk <= last_chunk; chunk++) {
|
for (chunk = first_chunk; chunk <= last_chunk; chunk++) {
|
||||||
if (chunk == first_chunk) {
|
|
||||||
chunk_offset = dest % IAP_PGM_CHUNKSIZE;
|
|
||||||
} else {
|
|
||||||
chunk_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
DEBUG("chunk %u len %zu\n", chunk, len);
|
||||||
/* first and last chunk may require special handling */
|
/* first and last chunk may require special handling */
|
||||||
if ((chunk == first_chunk) || (chunk == last_chunk)) {
|
if ((chunk == first_chunk) || (chunk == last_chunk)) {
|
||||||
|
|
||||||
|
@ -464,6 +399,7 @@ static int lpc43xx_flash_write(target *t,
|
||||||
/* update to suit */
|
/* update to suit */
|
||||||
len -= copylen;
|
len -= copylen;
|
||||||
src += copylen;
|
src += copylen;
|
||||||
|
chunk_offset = 0;
|
||||||
} else {
|
} else {
|
||||||
/* interior chunk, must be aligned and full-sized */
|
/* interior chunk, must be aligned and full-sized */
|
||||||
memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE);
|
memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE);
|
||||||
|
@ -472,21 +408,15 @@ static int lpc43xx_flash_write(target *t,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare... */
|
/* prepare... */
|
||||||
if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) {
|
if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
/* copy buffer into target memory */
|
|
||||||
target_mem_write(t,
|
|
||||||
IAP_RAM_BASE + offsetof(struct flash_program, data),
|
|
||||||
flash_pgm.data, sizeof(flash_pgm.data));
|
|
||||||
|
|
||||||
/* set the destination address and program */
|
/* set the destination address and program */
|
||||||
flash_pgm.p.command = IAP_CMD_PROGRAM;
|
flash_pgm.p.command = IAP_CMD_PROGRAM;
|
||||||
flash_pgm.p.params.program.dest = chunk * IAP_PGM_CHUNKSIZE;
|
flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE;
|
||||||
flash_pgm.p.params.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data);
|
flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data);
|
||||||
flash_pgm.p.params.program.byte_count = IAP_PGM_CHUNKSIZE;
|
flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE;
|
||||||
flash_pgm.p.params.program.cpu_clk_khz = CPU_CLK_KHZ;
|
flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
@ -524,8 +454,8 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[])
|
||||||
|
|
||||||
/* special command to compute/write magic vector for signature */
|
/* special command to compute/write magic vector for signature */
|
||||||
flash_pgm.p.command = IAP_CMD_SET_ACTIVE_BANK;
|
flash_pgm.p.command = IAP_CMD_SET_ACTIVE_BANK;
|
||||||
flash_pgm.p.params.make_active.flash_bank = bank;
|
flash_pgm.p.make_active.flash_bank = bank;
|
||||||
flash_pgm.p.params.make_active.cpu_clk_khz = CPU_CLK_KHZ;
|
flash_pgm.p.make_active.cpu_clk_khz = CPU_CLK_KHZ;
|
||||||
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS;
|
||||||
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm));
|
||||||
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) {
|
||||||
|
|
Loading…
Reference in New Issue