lpc: Reduce differences between lpc11xx and lpc43xx code.

This commit is contained in:
Gareth McMullin 2015-04-04 12:44:30 -07:00
parent 54eb3a719f
commit cd5d569d38
5 changed files with 168 additions and 170 deletions

View File

@ -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;

View File

@ -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);

83
src/include/lpc_common.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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) {