xdebug

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 1b4559aa03e8793a3901fd4a21dfb673f6e8b8e1
parent 33c90067c1043e4163e9736f1730bf54384c908c
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed,  8 Mar 2023 15:01:38 -0800

flash agents

- import the flash agents from mdebug
- replace u32 with uint32_t throughout

Diffstat:
MMakefile | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Aagents/cc13xx-romapi.h | 35+++++++++++++++++++++++++++++++++++
Aagents/cc13xx.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/efr32bg2x.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/lpc13xx.c | 5+++++
Aagents/lpc13xx_lpc15xx.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/lpc15xx.c | 7+++++++
Aagents/lpc43xx-spifi.c | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/lpclink2.c | 5+++++
Aagents/nrf528xx.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/pico.c | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/stm32f0xx.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aagents/stm32f4xx.c | 6++++++
Aagents/stm32fxxx.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agen/builtins.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/agent.ld | 32++++++++++++++++++++++++++++++++
Ainclude/agent/flash.h | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/fw/io.h | 15+++++++++++++++
18 files changed, 1714 insertions(+), 10 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,24 +5,84 @@ CFLAGS := -Wall -g -O1 CFLAGS += -Itui -Itermbox -D_XOPEN_SOURCE LIBS := -lusb-1.0 +# TOOLCHAIN := arm-none-eabi- + +ifneq ($(TOOLCHAIN),) +# if there's a cross-compiler, build agents from source + +TARGET_CC := $(TOOLCHAIN)gcc +TARGET_OBJCOPY := $(TOOLCHAIN)objcopy +TARGET_OBJDUMP := $(TOOLCHAIN)objdump + +ARCH_M3_CFLAGS := -mcpu=cortex-m3 -mthumb +ARCH_M3_LIBS := $(shell $(TARGET_CC) $(ARCH_M3_CFLAGS) -print-libgcc-file-name) + +ARCH_M0_CFLAGS := -mcpu=cortex-m0 -mthumb +ARCH_M0_LIBS := $(shell $(TARGET_CC) $(ARCH_M0_CFLAGS) -print-libgcc-file-name) + +TARGET_CFLAGS := -g -Os -Wall -I. -Iinclude +TARGET_CFLAGS += -Wno-unused-but-set-variable +TARGET_CFLAGS += -ffunction-sections -fdata-sections +TARGET_CFLAGS += -fno-builtin -nostdlib -ffreestanding + +agent = $(eval AGENTS += $(strip $1))\ +$(eval ALL += $(patsubst %,out/agents/%.bin,$(strip $1)))\ +$(eval ALL += $(patsubst %,out/agents/%.lst,$(strip $1)))\ +$(eval out/agents/$(strip $1).elf: LOADADDR := $(strip $2))\ +$(eval out/agents/$(strip $1).elf: ARCH := $(strip $3)) + +$(call agent, lpclink2, 0x10080400, M3) +$(call agent, stm32f4xx, 0x20000400, M3) +$(call agent, stm32f0xx, 0x20000400, M0) +$(call agent, lpc13xx, 0x10000400, M3) +$(call agent, lpc15xx, 0x02000400, M3) +$(call agent, cc13xx, 0x20000400, M3) +$(call agent, nrf528xx, 0x20000400, M3) +$(call agent, efr32bg2x, 0x20000400, M3) +$(call agent, pico, 0x20000400, M0) + +out/mkbuiltins: tools/mkbuiltins.c + @mkdir -p $(dir $@) + gcc -o $@ $(CFLAGS) $< + +AGENT_BINS := $(patsubst %,out/agents/%.bin,$(AGENTS)) + +gen/builtins.c: $(AGENT_BINS) out/mkbuiltins + @mkdir -p $(dir $@) + ./out/mkbuiltins $(AGENT_BINS) > $@ + +out/agents/%.bin: out/agents/%.elf + @mkdir -p $(dir $@) + $(TARGET_OBJCOPY) -O binary $< $@ + +out/agents/%.lst: out/agents/%.elf + @mkdir -p $(dir $@) + $(TARGET_OBJDUMP) -d $< > $@ + +out/agents/%.elf: agents/%.c + @mkdir -p $(dir $@) + $(TARGET_CC) $(TARGET_CFLAGS) $(ARCH_$(ARCH)_CFLAGS) -Wl,--script=include/agent.ld -Wl,-Ttext=$(LOADADDR) -o $@ $< $(ARCH_$(ARCH)_LIBS) + +endif + COMMON := src/transport-arm-debug.c src/transport-dap.c src/usb.c -XTESTSRCS := src/xtest.c $(COMMON) -XTESTOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XTESTSRCS)))) +XTEST_SRCS := src/xtest.c $(COMMON) +XTEST_OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XTEST_SRCS)))) -XDEBUGSRCS := src/xdebug.c src/commands.c $(COMMON) -XDEBUGSRCS += tui/tui.c termbox/termbox.c termbox/utf8.c -XDEBUGOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XDEBUGSRCS)))) +XDEBUG_SRCS := src/xdebug.c src/commands.c $(COMMON) +XDEBUG_SRCS += tui/tui.c termbox/termbox.c termbox/utf8.c gen/builtins.c +XDEBUG_OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XDEBUG_SRCS)))) -out/xtest: $(XTESTOBJS) +out/xtest: $(XTEST_OBJS) @mkdir -p $(dir $@) - gcc -o $@ -Wall -g -O1 $(XTESTOBJS) $(LIBS) + gcc -o $@ -Wall -g -O1 $(XTEST_OBJS) $(LIBS) -out/xdebug: $(XDEBUGOBJS) +out/xdebug: $(XDEBUG_OBJS) @mkdir -p $(dir $@) - gcc -o $@ -Wall -g -O1 $(XDEBUGOBJS) $(LIBS) + gcc -o $@ -Wall -g -O1 $(XDEBUG_OBJS) $(LIBS) # remove dups -OBJS := $(sort $(XTESTOBJS) $(XDEBUGOBJS)) +OBJS := $(sort $(XTEST_OBJS) $(XDEBUG_OBJS)) $(OBJS): out/%.o: %.c $(XDEPS) @mkdir -p $(dir $@) diff --git a/agents/cc13xx-romapi.h b/agents/cc13xx-romapi.h @@ -0,0 +1,35 @@ + +#define ROM_API_TABLE ((uint32_t*) 0x10000180) +#define ROM_API_FLASH_TABLE ((uint32_t*) (ROM_API_TABLE[10])) + +#define ROM_FlashPowerModeGet \ + ((uint32_t (*)(void)) \ + ROM_API_FLASH_TABLE[1]) + +#define ROM_FlashProtectionSet \ + ((void (*)(uint32_t ui32SectorAddress, uint32_t ui32ProtectMode)) \ + ROM_API_FLASH_TABLE[2]) + +#define ROM_FlashProtectionGet \ + ((uint32_t (*)(uint32_t ui32SectorAddress)) \ + ROM_API_FLASH_TABLE[3]) + +#define ROM_FlashProtectionSave \ + ((uint32_t (*)(uint32_t ui32SectorAddress)) \ + ROM_API_FLASH_TABLE[4]) + +#define ROM_FlashSectorErase \ + ((uint32_t (*)(uint32_t ui32SectorAddress)) \ + ROM_API_FLASH_TABLE[5]) + +#define ROM_FlashProgram \ + ((uint32_t (*)(const void *pui8DataBuffer, uint32_t ui32Address, uint32_t ui32Count)) \ + ROM_API_FLASH_TABLE[6]) + +#define ROM_FlashEfuseReadRow \ + ((uint32_t (*)(uint32_t* pui32EfuseData, uint32_t ui32RowAddress)) \ + ROM_API_FLASH_TABLE[8]) + +#define ROM_FlashDisableSectorsForWrite \ + ((void (*)(void)) \ + ROM_API_FLASH_TABLE[9]) diff --git a/agents/cc13xx.c b/agents/cc13xx.c @@ -0,0 +1,70 @@ +// agent-lpc15xx/main.c +// +// Copyright 2016 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <agent/flash.h> +#include "cc13xx-romapi.h" + +int flash_agent_setup(flash_agent *agent) { + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + while (length > 0) { + if (ROM_FlashSectorErase(flash_addr)) { + return ERR_FAIL; + } + if (length > 4096) { + length -= 4096; + flash_addr += 4096; + } else { + break; + } + } + return 0; +} + +int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) { + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + if (ROM_FlashProgram(data, flash_addr, length)) { + return ERR_FAIL; + } + return 0; +} + + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = 0x20000400, + .data_addr = 0x20001000, + .data_size = 0x1000, + .flash_addr = 0x00000000, + .flash_size = 0x00020000, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/efr32bg2x.c b/agents/efr32bg2x.c @@ -0,0 +1,167 @@ +// agents/efr32bg2x.c +// +// Copyright 2022 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x00000000 + +#include <agent/flash.h> +#include <fw/io.h> + +#define CMU_CLKEN1_SET 0x40009068 +#define CMU_CLKEN1_MSC (1U<<17) + +#define MSC_WRITECTRL 0x4003000C +#define MSC_WRITECTRL_SET 0x4003100C +#define MSC_WRITECTRL_CLR 0x4003200C +#define MSC_WRITECMD 0x40030010 +#define MSC_WRITECMD_SET 0x40031010 +#define MSC_WRITECMD_CLR 0x40032010 +#define MSC_ADDRB 0x40030014 +#define MSC_WDATA 0x40030018 +#define MSC_STATUS 0x4003001C + +#define MSC_WRITECTRL_WREN 1 + +#define MSC_WRITECMD_WRITEND (1U<<2) +#define MSC_WRITECMD_ERASEPAGE (1U<<1) + +#define MSC_STATUS_WREADY (1U<<27) +#define MSC_STATUS_PWRON (1U<<24) +#define MSC_STATUS_REGLOCK (1U<<16) +#define MSC_STATUS_TIMEOUT (1U<<6) +#define MSC_STATUS_PENDING (1U<<5) +#define MSC_STATUS_ERASEABORTYED (1U<<4) +#define MSC_STATUS_WDATAREADY (1U<<3) +#define MSC_STATUS_INVADDR (1U<<2) +#define MSC_STATUS_LOCKED (1U<<1) +#define MSC_STATUS_BUSY (1U<<0) + +static unsigned FLASH_PAGE_SIZE = 8192; +static unsigned FLASH_SIZE = 352 * 1024; + +int flash_agent_setup(flash_agent *agent) { + // TODO - validate part ID + if (0) { + // unknown part + return ERR_INVALID; + } + + // TODO: read from userdata + agent->flash_size = FLASH_SIZE; + + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + unsigned v; + int status = ERR_NONE; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if (flash_addr & (FLASH_PAGE_SIZE - 1)) { + return ERR_ALIGNMENT; + } + + writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); + while (length > 0) { + writel(flash_addr, MSC_ADDRB); + v = readl(MSC_STATUS); + if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { + status = ERR_INVALID; + break; + } + if (!(v & MSC_STATUS_WREADY)) { + status = ERR_FAIL; + break; + } + if (length > FLASH_PAGE_SIZE) { + length -= FLASH_PAGE_SIZE; + } else { + length = 0; + } + writel(MSC_WRITECMD_ERASEPAGE, MSC_WRITECMD_SET); + while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; + for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) { + if (readl(flash_addr + n) != 0xFFFFFFFF) { + status = ERR_FAIL; + goto done; + } + } + flash_addr += FLASH_PAGE_SIZE; + } +done: + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); + return status; +} + +int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) { + int status = ERR_NONE; + const unsigned *data = _data; + unsigned v; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if ((flash_addr & 3) || (length & 3)) { + return ERR_ALIGNMENT; + } + writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); + while (length > 0) { + writel(flash_addr, MSC_ADDRB); + v = readl(MSC_STATUS); + if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { + status = ERR_INVALID; + break; + } + if (!(v & MSC_STATUS_WREADY)) { + status = ERR_FAIL; + break; + } + writel(*data, MSC_WDATA); + while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; + if (readl(flash_addr) != *data) { + status = ERR_FAIL; + goto done; + } + data++; + length -= 4; + flash_addr += 4; + } +done: + writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); + return status; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x4000, + .flash_addr = FLASH_BASE, + .flash_size = 0, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/lpc13xx.c b/agents/lpc13xx.c @@ -0,0 +1,5 @@ +#define LOADADDR 0x10000400 +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x00008000 + +#include "lpc13xx_lpc15xx.c" diff --git a/agents/lpc13xx_lpc15xx.c b/agents/lpc13xx_lpc15xx.c @@ -0,0 +1,119 @@ +// agent-lpc15xx/main.c +// +// Copyright 2015 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <agent/flash.h> + +#ifdef ARCH_LPC15XX +#define LPC_IAP_FUNC 0x03000205 +#else +#define LPC_IAP_FUNC 0x1fff1ff1 +#endif + +#define LPC_IAP_PREPARE 50 +#define LPC_IAP_WRITE 51 +#define LPC_IAP_ERASE 52 + +// Note that while the databook claims you can reuse the same array +// for both parameters and results, this is a lie. Attempting to +// do so causes an invalid command failure. + + +int flash_agent_setup(flash_agent *agent) { + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + void (*romcall)(uint32_t *, uint32_t *) = (void*) LPC_IAP_FUNC; + uint32_t p[5],r[4]; + uint32_t page = flash_addr >> 12; + uint32_t last = page + ((length - 1) >> 12); + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + + p[0] = LPC_IAP_PREPARE; + p[1] = page; + p[2] = last; + romcall(p,r); + if (r[0]) { + return ERR_FAIL; + } + + p[0] = LPC_IAP_ERASE; + p[1] = page; + p[2] = last; + p[3] = 0x2ee0; + romcall(p,r); + if (r[0]) { + return ERR_FAIL; + } + return ERR_NONE; +} + +int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) { + void (*romcall)(uint32_t *,uint32_t *) = (void*) LPC_IAP_FUNC; + uint32_t p[5],r[4]; + uint32_t page = flash_addr >> 12; + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + + p[0] = LPC_IAP_PREPARE; + p[1] = page; + p[2] = page; + romcall(p,r); + if (r[0]) { + return ERR_FAIL; + } + + // todo: smaller writes, etc + if (length != 4096) { + int n; + for (n = length; n < 4096; n++) { + ((char*) data)[n] = 0; + } + } + p[0] = LPC_IAP_WRITE; + p[1] = flash_addr; + p[2] = (uint32_t) data; + p[3] = 0x1000; + p[4] = 0x2ee0; + romcall(p,r); + if (r[0]) { + return ERR_FAIL; + } + + return ERR_NONE; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = FLAG_BOOT_ROM_HACK, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x1000, + .flash_addr = FLASH_BASE, + .flash_size = FLASH_SIZE, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/lpc15xx.c b/agents/lpc15xx.c @@ -0,0 +1,7 @@ +#define ARCH_LPC15XX 1 + +#define LOADADDR 0x02000400 +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x00010000 + +#include "lpc13xx_lpc15xx.c" diff --git a/agents/lpc43xx-spifi.c b/agents/lpc43xx-spifi.c @@ -0,0 +1,226 @@ +// agent-lpc15xx/main.c +// +// Copyright 2015 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <agent/flash.h> +#include <fw/io.h> + +// ---- pinmux + +#define PIN_CFG(m,n) (0x40086000 + ((m) * 0x80) + ((n) * 4)) +#define PIN_MODE(n) ((n) & 3) +#define PIN_PULLUP (0 << 3) // pull-up, no pull-down +#define PIN_REPEATER (1 << 3) // repeater mode +#define PIN_PLAIN (2 << 3) // no pull-up, no pull-down +#define PIN_PULLDOWN (3 << 3) // pull-down, no pull-up +#define PIN_SLOW (0 << 5) // slow slew rate (low noise, medium speed) +#define PIN_FAST (1 << 5) // fast slew rate (medium noise, fast speed) +#define PIN_INPUT (1 << 6) // enable input buffer, required for inputs +#define PIN_FILTER (1 << 7) // enable glitch filter, not for >30MHz signals + +// ---- spifi serial flash controller + +#define SPIFI_CTRL 0x40003000 // Control +#define SPIFI_CMD 0x40003004 // Command +#define SPIFI_ADDR 0x40003008 // Address +#define SPIFI_IDATA 0x4000300C // Intermediate Data +#define SPIFI_CLIMIT 0x40003010 // Cache Limit +#define SPIFI_DATA 0x40003014 // Data +#define SPIFI_MCMD 0x40003018 // Memory Command +#define SPIFI_STAT 0x4000301C // Status + +#define CTRL_TIMEOUT(n) ((n) & 0xFFFF) +#define CTRL_CSHIGH(n) (((n) & 0xF) << 16) // Minimum /CS high time (serclks - 1) +#define CTRL_D_PRFTCH_DIS (1 << 21) // Disable Prefetch of Data +#define CTRL_INTEN (1 << 22) // Enable IRQ on end of command +#define CTRL_MODE3 (1 << 23) // 0=SCK low after +edge of last bit, 1=high +#define CTRL_PRFTCH_DIS (1 << 27) // Disable Prefetch +#define CTRL_DUAL (1 << 28) // 0=Quad 1=Dual (bits in "wide" ops) +#define CTRL_QUAD (0 << 28) +#define CTRL_RFCLK (1 << 29) // 1=sample read data on -edge clock +#define CTRL_FBCLK (1 << 30) // use feedback clock from SCK pin for sampling +#define CTRL_DMAEN (1 << 31) // enable DMA request output + +#define CMD_DATALEN(n) ((n) & 0x3FFF) +#define CMD_POLL (1 << 14) // if set, read byte repeatedly until condition +#define CMD_POLLBIT(n) ((n) & 7) // which bit# to check +#define CMD_POLLSET (1 << 3) // condition is bit# set +#define CMD_POLLCLR (0 << 3) // condition is bit# clear +#define CMD_DOUT (1 << 15) // 1=data phase output, 0=data phase input +#define CMD_DIN (0 << 15) +#define CMD_INTLEN(n) (((n) & 7) << 16) // count of intermediate bytes +#define CMD_FF_SERIAL (0 << 19) // all command fields serial +#define CMD_FF_WIDE_DATA (1 << 19) // data is wide, all other fields serial +#define CMD_FF_SERIAL_OPCODE (2 << 19) // opcode is serial, all other fields wide +#define CMD_FF_WIDE (3 << 19) // all command fields wide +#define CMD_FR_OP (1 << 21) // frame format: opcode only +#define CMD_FR_OP_1B (2 << 21) // opcode, lsb addr +#define CMD_FR_OP_2B (3 << 21) // opcode, 2 lsb addr +#define CMD_FR_OP_3B (4 << 21) // opcode, 3 lsb addr +#define CMD_FR_OP_4B (5 << 21) // opcode, 4b address +#define CMD_FR_3B (6 << 21) // 3 lsb addr +#define CMD_FR_4B (7 << 21) // 4 lsb addr +#define CMD_OPCODE(n) ((n) << 24) + +#define STAT_MCINIT (1 << 0) // set on sw write to MCMD, clear on RST, wr(0) +#define STAT_CMD (1 << 1) // set when CMD written, clear on CS, RST +#define STAT_RESET (1 << 4) // write 1 to abort current txn or memory mode +#define STAT_INTRQ (1 << 5) // read IRQ status, wr(1) to clear + +#define CMD_PAGE_PROGRAM 0x02 +#define CMD_READ_DATA 0x03 +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 +#define CMD_SECTOR_ERASE 0x20 + +static void spifi_write_enable(void) { + writel(CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_WRITE_ENABLE), + SPIFI_CMD); + while (readl(SPIFI_STAT) & STAT_CMD) ; +} + +static void spifi_wait_busy(void) { + while (readl(SPIFI_STAT) & STAT_CMD) ; + writel(CMD_POLLBIT(0) | CMD_POLLCLR | CMD_POLL | + CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_READ_STATUS), + SPIFI_CMD); + while (readl(SPIFI_STAT) & STAT_CMD) ; + // discard matching status byte from fifo + readb(SPIFI_DATA); +} + +static void spifi_page_program(uint32_t addr, uint32_t *ptr, uint32_t count) { + spifi_write_enable(); + writel(addr, SPIFI_ADDR); + writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | + CMD_DOUT | CMD_OPCODE(CMD_PAGE_PROGRAM), SPIFI_CMD); + while (count-- > 0) { + writel(*ptr++, SPIFI_DATA); + } + spifi_wait_busy(); +} + +static void spifi_sector_erase(uint32_t addr) { + spifi_write_enable(); + writel(addr, SPIFI_ADDR); + writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_SECTOR_ERASE), + SPIFI_CMD); + spifi_wait_busy(); +} + +static int verify_erased(uint32_t addr, uint32_t count) { + int err = 0; + writel(addr, SPIFI_ADDR); + writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | + CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD); + while (count-- > 0) { + if (readl(SPIFI_DATA) != 0xFFFFFFFF) err = -1; + } + while (readl(SPIFI_STAT) & STAT_CMD) ; + return err; +} + +static int verify_page(uint32_t addr, uint32_t *ptr) { + int count = 256 / 4; + int err = 0; + writel(addr, SPIFI_ADDR); + writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | + CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD); + while (count-- > 0) { + if (readl(SPIFI_DATA) != *ptr++) err = -1; + } + while (readl(SPIFI_STAT) & STAT_CMD) ; + return err; +} + +// at reset-stop, all clocks are running from 12MHz internal osc +// todo: run SPIFI_CLK at a much higher rate +// todo: use 4bit modes +int flash_agent_setup(flash_agent *agent) { + // configure pinmux + writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3,3)); // SPIFI_SCK + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 4)); // SPIFI_SIO3 + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 5)); // SPIFI_SIO2 + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 6)); // SPIFI_MISO + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 7)); // SPIFI_MOSI + writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3, 8)); // SPIFI_CS + + // reset spifi controller + writel(STAT_RESET, SPIFI_STAT); + while (readl(SPIFI_STAT) & STAT_RESET) ; + writel(0xFFFFF, SPIFI_CTRL); + + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + while (length != 0) { + spifi_sector_erase(flash_addr); + if (verify_erased(flash_addr, 0x1000/4)) { + return ERR_FAIL; + } + if (length < 0x1000) break; + length -= 0x1000; + flash_addr += 0x1000; + } + return ERR_NONE; +} + +int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) { + char *x = (void*) data; + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + while (length != 0) { + if (length < 256) { + int n; + for (n = length; n < 256; n++) { + x[n] = 0; + } + } + spifi_page_program(flash_addr, (void*) x, 256 / 4); + if (verify_page(flash_addr, (void*) x)) { + return ERR_FAIL; + } + if (length < 256) break; + length -= 256; + flash_addr += 256; + x += 256; + } + writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_READ_DATA), SPIFI_MCMD); + return ERR_NONE; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x8000, + .flash_addr = FLASH_BASE, + .flash_size = FLASH_SIZE, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/lpclink2.c b/agents/lpclink2.c @@ -0,0 +1,5 @@ +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x00100000 +#define LOADADDR 0x10080400 + +#include "lpc43xx-spifi.c" diff --git a/agents/nrf528xx.c b/agents/nrf528xx.c @@ -0,0 +1,127 @@ +// agents/nrf528xx.c +// +// Copyright 2019 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x00000000 + +#include <agent/flash.h> +#include <fw/io.h> + +#define NVMC_READY 0x4001E400 +#define NVMC_CONFIG 0x4001E504 +#define NVMC_CONFIG_READ 0 +#define NVMC_CONFIG_WRITE 1 +#define NVMC_CONFIG_ERASE 2 +#define NVMC_ERASEPAGE 0x4001E508 + +#define FICR_CODEPAGESIZE 0x10000010 +#define FICR_CODESIZE 0x10000014 + +static unsigned FLASH_PAGE_SIZE = 1024; +static unsigned FLASH_SIZE = 192 * 1024; + +int flash_agent_setup(flash_agent *agent) { + + // TODO - validate part ID + if (0) { + // unknown part + return ERR_INVALID; + } + + // check flash size + FLASH_PAGE_SIZE = readl(FICR_CODEPAGESIZE); + FLASH_SIZE = FLASH_PAGE_SIZE * readl(FICR_CODESIZE); + + agent->flash_size = FLASH_SIZE; + + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + int status = ERR_NONE; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if (flash_addr & (FLASH_PAGE_SIZE - 1)) { + return ERR_ALIGNMENT; + } + writel(NVMC_CONFIG_ERASE, NVMC_CONFIG); + while (length > 0) { + if (length > FLASH_PAGE_SIZE) { + length -= FLASH_PAGE_SIZE; + } else { + length = 0; + } + writel(flash_addr, NVMC_ERASEPAGE); + while (readl(NVMC_READY) != 1) ; + for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) { + if (readl(flash_addr + n) != 0xFFFFFFFF) { + status = ERR_FAIL; + goto done; + } + } + flash_addr += FLASH_PAGE_SIZE; + } +done: + writel(NVMC_CONFIG_READ, NVMC_CONFIG); + return status; +} + +int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) { + int status = ERR_NONE; + const unsigned *data = _data; + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if ((flash_addr & 3) || (length & 3)) { + return ERR_ALIGNMENT; + } + writel(NVMC_CONFIG_WRITE, NVMC_CONFIG); + while (length > 0) { + writel(*data, flash_addr); + while (readl(NVMC_READY) != 1) ; + if (readl(flash_addr) != *data) { + status = ERR_FAIL; + goto done; + } + data++; + length -= 4; + flash_addr += 4; + } +done: + writel(NVMC_CONFIG_READ, NVMC_CONFIG); + return status; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x4000, + .flash_addr = FLASH_BASE, + .flash_size = 0, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/pico.c b/agents/pico.c @@ -0,0 +1,147 @@ +// agents/pico.c +// +// Copyright 2020 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x00000000 + +#include <stdint.h> +#include <agent/flash.h> +#include <fw/io.h> + +static unsigned FLASH_BLOCK_SIZE = 256; +static unsigned FLASH_PAGE_SIZE = 4096; +static unsigned FLASH_SIZE = 4 * 1024 * 1024; + +#define FLASH_XIP_BASE 0x10000000 + +#define CODE(c1, c2) (((c2) << 8) | (c1)) + +#define ROM_LOOKUP_FN_PTR 0x18 +#define ROM_FN_TABLE_PTR 0x14 + +// lookup fn for code using ROM lookup helper and ROM fn table +void* lookup_fn(uint32_t code) { + void* (*lookup)(uint32_t table, uint32_t code) = + (void*) (uintptr_t) *((uint16_t*) ROM_LOOKUP_FN_PTR); + + return lookup(*((uint16_t*)ROM_FN_TABLE_PTR), code); +} + +static void (*_flash_connect)(void); +static void (*_flash_exit_xip)(void); +static void (*_flash_erase)(uint32_t addr, uint32_t len, + uint32_t block_size, uint32_t block_cmd); +static void (*_flash_write)(uint32_t addr, const void* data, uint32_t len); +static void (*_flash_flush_cache)(void); +static void (*_flash_enter_xip)(void); + +// erase: addr and count must be 4096 aligned +// write: addr and len must be 256 aligned + +int flash_agent_setup(flash_agent *agent) { + // TODO - validate part ID + if (0) { + // unknown part + return ERR_INVALID; + } + + _flash_connect = lookup_fn(CODE('I','F')); + _flash_exit_xip = lookup_fn(CODE('E','X')); + _flash_erase = lookup_fn(CODE('R','E')); + _flash_write = lookup_fn(CODE('R','P')); + _flash_flush_cache = lookup_fn(CODE('F','C')); + _flash_enter_xip = lookup_fn(CODE('C','X')); + + // TODO: obtain from spi flash + agent->flash_size = FLASH_SIZE; + + return ERR_NONE; +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if (flash_addr & (FLASH_PAGE_SIZE - 1)) { + return ERR_ALIGNMENT; + } + if (length & (FLASH_PAGE_SIZE-1)) { + length = (length & (~(FLASH_PAGE_SIZE-1))) + FLASH_PAGE_SIZE; + } + + _flash_connect(); + _flash_exit_xip(); + _flash_erase(flash_addr, length, 65536, 0xD8); + _flash_flush_cache(); + _flash_enter_xip(); + + uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE); + for (uint32_t n = 0; n < length; n+= 4) { + if (*flash++ != 0xFFFFFFFF) { + return ERR_FAIL; + } + } + + return ERR_NONE; +} + +int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) { + if (flash_addr > FLASH_SIZE) { + return ERR_INVALID; + } + if (flash_addr & (FLASH_BLOCK_SIZE - 1)) { + return ERR_ALIGNMENT; + } + if (length & (FLASH_BLOCK_SIZE-1)) { + length = (length & (~(FLASH_BLOCK_SIZE-1))) + FLASH_BLOCK_SIZE; + } + + _flash_connect(); + _flash_exit_xip(); + _flash_write(flash_addr, data, length); + _flash_flush_cache(); + _flash_enter_xip(); + + uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE); + const uint32_t* xdata = data; + for (uint32_t n = 0; n < length; n += 4) { + if (*flash++ != *xdata++) { + return ERR_FAIL; + } + } + + return ERR_NONE; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x4000, + .flash_addr = FLASH_BASE, + .flash_size = 0, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/stm32f0xx.c b/agents/stm32f0xx.c @@ -0,0 +1,154 @@ +// agents/stm-main.c +// +// Copyright 2015 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x08000000 +#define FLASH_SIZE 0x00004000 + +#include <agent/flash.h> +#include <fw/io.h> + +#define _FLASH_BASE 0x40022000 +#define FLASH_ACR (_FLASH_BASE + 0x00) + +#define FLASH_KEYR (_FLASH_BASE + 0x04) +#define FLASH_KEYR_KEY1 0x45670123 +#define FLASH_KEYR_KEY2 0xCDEF89AB + +#define FLASH_SR (_FLASH_BASE + 0x0C) +#define FLASH_SR_EOP (1 << 5) // end of operation +#define FLASH_SR_WP_ERR (1 << 4) // write protect error +#define FLASH_SR_PG_ERR (1 << 2) // programming error +#define FLASH_SR_BSY (1 << 0) // busy +#define FLASH_SR_ERR_MASK (FLASH_SR_WP_ERR | FLASH_SR_PG_ERR) + +#define FLASH_CR (_FLASH_BASE + 0x10) +#define FLASH_CR_OBL_LAUNCH (1 << 13) // reload option byte & reset system +#define FLASH_CR_EOPIE (1 << 12) // enable end-of-op irq +#define FLASH_CR_ERRIE (1 << 10) // enable error irq +#define FLASH_CR_OPTWRE (1 << 9) // option byte write enable +#define FLASH_CR_LOCK (1 << 7) // indicates flash is locked +#define FLASH_CR_STRT (1 << 6) // start erase operation +#define FLASH_CR_OPTER (1 << 5) // option byte erase +#define FLASH_CR_OPTPG (1 << 4) // option byte program +#define FLASH_CR_MER (1 << 2) // mass erase +#define FLASH_CR_PER (1 << 1) // page erase +#define FLASH_CR_PG (1 << 0) // programming +#define FLASH_CR_MASK (~0x000036F7) // bits to not modify + +#define FLASH_AR (_FLASH_BASE + 0x14) + +static unsigned FLASH_PAGE_SIZE = 1024; + +int flash_agent_setup(flash_agent *agent) { + + // check MCU ID + switch (readl(0x40015800) & 0xFFF) { + case 0x444: // F03x + case 0x445: // F04x + case 0x440: // F05x + break; + case 0x448: // F07x + case 0x442: // F09x + FLASH_PAGE_SIZE = 2048; + break; + default: + // unknown part + return ERR_INVALID; + } + + // check flash size + agent->flash_size = readw(0x1FFFF7CC) * 1024; + + writel(FLASH_KEYR_KEY1, FLASH_KEYR); + writel(FLASH_KEYR_KEY2, FLASH_KEYR); + if (readl(FLASH_CR) & FLASH_CR_LOCK) { + return ERR_FAIL; + } else { + return ERR_NONE; + } +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + uint32_t cr; + int n; + if (flash_addr & (FLASH_PAGE_SIZE - 1)) { + return ERR_ALIGNMENT; + } + cr = readl(FLASH_CR) & FLASH_CR_MASK; + + while (length > 0) { + if (length > FLASH_PAGE_SIZE) { + length -= FLASH_PAGE_SIZE; + } else { + length = 0; + } + writel(cr | FLASH_CR_PER, FLASH_CR); + writel(flash_addr, FLASH_AR); + writel(cr | FLASH_CR_PER | FLASH_CR_STRT, FLASH_CR); + while (readl(FLASH_SR) & FLASH_SR_BSY) ; + for (n = 0; n < FLASH_PAGE_SIZE; n += 4) { + if (readl(flash_addr + n) != 0xFFFFFFFF) { + return ERR_FAIL; + } + } + flash_addr += FLASH_PAGE_SIZE; + } + return ERR_NONE; +} + +int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) { + const unsigned short *data = _data; + uint32_t v, cr; + if ((flash_addr & 3) || (length & 3)) { + return ERR_ALIGNMENT; + } + cr = readl(FLASH_CR) & FLASH_CR_MASK; + writel(cr | FLASH_CR_PG, FLASH_CR); + while (length > 0) { + writew(*data, flash_addr); + while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ; + if (readw(flash_addr) != *data) { + writel(cr, FLASH_CR); + return ERR_FAIL; + } + data++; + length -= 2; + flash_addr += 2; + } + writel(cr, FLASH_CR); + return ERR_NONE; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x1000, + .flash_addr = FLASH_BASE, + .flash_size = FLASH_SIZE, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/stm32f4xx.c b/agents/stm32f4xx.c @@ -0,0 +1,6 @@ +#define LOADADDR 0x20000400 + +#define FLASH_BASE 0x00000000 +#define FLASH_SIZE 0x00100000 + +#include "stm32fxxx.c" diff --git a/agents/stm32fxxx.c b/agents/stm32fxxx.c @@ -0,0 +1,141 @@ +// agents/stm-main.c +// +// Copyright 2015 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <agent/flash.h> +#include <fw/io.h> + +#define _FLASH_BASE 0x40023C00 +#define FLASH_ACR (_FLASH_BASE + 0x00) + +#define FLASH_KEYR (_FLASH_BASE + 0x04) +#define FLASH_KEYR_KEY1 0x45670123 +#define FLASH_KEYR_KEY2 0xCDEF89AB + +#define FLASH_SR (_FLASH_BASE + 0x0C) +#define FLASH_SR_BSY (1 << 16) +#define FLASH_SR_PGSERR (1 << 7) // sequence error +#define FLASH_SR_PGPERR (1 << 6) // parallelism error +#define FLASH_SR_PGAERR (1 << 5) // alignment error +#define FLASH_SR_WRPERR (1 << 4) // write-protect error +#define FLASH_SR_OPERR (1 << 1) // operation error +#define FLASH_SR_ERRMASK 0xF2 +#define FLASH_SR_EOP (1 << 0) // end of operation + +#define FLASH_CR (_FLASH_BASE + 0x10) +#define FLASH_CR_LOCK (1 << 31) +#define FLASH_CR_ERRIE (1 << 25) // error irq en +#define FLASH_CR_EOPIE (1 << 24) // end of op irq en +#define FLASH_CR_STRT (1 << 16) // start +#define FLASH_CR_PSIZE_8 (0 << 8) +#define FLASH_CR_PSIZE_16 (1 << 8) +#define FLASH_CR_PSIZE_32 (2 << 8) +#define FLASH_CR_PSIZE_64 (3 << 8) +#define FLASH_CR_SNB(n) (((n) & 15) << 3) // sector number +#define FLASH_CR_MER (1 << 2) // mass erase +#define FLASH_CR_SER (1 << 1) // sector erase +#define FLASH_CR_PG (1 << 0) // programming + + +#define SECTORS 12 + +static uint32_t sectors[SECTORS + 1] = { + 0x00000000, + 0x00004000, + 0x00008000, + 0x0000C000, + 0x00010000, + 0x00020000, + 0x00040000, + 0x00060000, + 0x00080000, + 0x000A0000, + 0x000C0000, + 0x000E0000, + 0x00100000, +}; + +int flash_agent_setup(flash_agent *agent) { + writel(FLASH_KEYR_KEY1, FLASH_KEYR); + writel(FLASH_KEYR_KEY2, FLASH_KEYR); + if (readl(FLASH_CR) & FLASH_CR_LOCK) { + return ERR_FAIL; + } else { + return ERR_NONE; + } +} + +int flash_agent_erase(uint32_t flash_addr, uint32_t length) { + uint32_t v; + int n; + for (n = 0; n < SECTORS; n++) { + if (flash_addr == sectors[n]) goto ok; + } + return ERR_ALIGNMENT; +ok: + for (;;) { + writel(FLASH_CR_SER | FLASH_CR_SNB(n), FLASH_CR); + writel(FLASH_CR_STRT | FLASH_CR_SER | FLASH_CR_SNB(n), FLASH_CR); + while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ; + if (v & FLASH_SR_ERRMASK) { + return ERR_FAIL; + } + n++; + if (n == SECTORS) break; + if ((sectors[n] - flash_addr) >= length) break; + } + return ERR_NONE; +} + +int flash_agent_write(uint32_t flash_addr, const void *_data, uint32_t length) { + const uint32_t *data = _data; + uint32_t v; + if ((flash_addr & 3) || (length & 3)) { + return ERR_ALIGNMENT; + } + writel(FLASH_CR_PG | FLASH_CR_PSIZE_32, FLASH_CR); + while (length > 0) { + writel(*data, flash_addr); + data++; + length -= 4; + flash_addr += 4; + while ((v = readl(FLASH_SR)) & FLASH_SR_BSY) ; + if (v & FLASH_SR_ERRMASK) { + writel(0, FLASH_CR); + return ERR_FAIL; + } + } + writel(0, FLASH_CR); + return ERR_NONE; +} + +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { + return ERR_INVALID; +} + +const flash_agent __attribute((section(".vectors"))) FlashAgent = { + .magic = AGENT_MAGIC, + .version = AGENT_VERSION, + .flags = 0, + .load_addr = LOADADDR, + .data_addr = LOADADDR + 0x400, + .data_size = 0x8000, + .flash_addr = FLASH_BASE, + .flash_size = FLASH_SIZE, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/gen/builtins.c b/gen/builtins.c @@ -0,0 +1,248 @@ +/* this file is machine-generated by mkbuiltins -- do not modify */ + +#include <string.h> +#include <stdint.h> + +static struct { + const char *name; + size_t size; + void *data; +} files[] = { + { "lpclink2.bin", 488, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x08\x10" + "\x00\x08\x08\x10\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x61\x04\x08\x10\xA5\x04\x08\x10\x25\x05\x08\x10\x9D\x04\x08\x10" + "\x05\x4B\xDA\x69\x91\x07\xFC\xD4\x04\x4A\x5A\x60\xDA\x69\x92\x07" + "\xFC\xD4\x1B\x7D\x70\x47\x00\xBF\x00\x30\x00\x40\x00\x40\x20\x05" + "\x53\x22\x13\x21\x0B\x4B\xC3\xF8\x8C\x11\xC3\xF8\x90\x21\xC3\xF8" + "\x94\x21\xC3\xF8\x98\x21\xC3\xF8\x9C\x21\x10\x22\xC3\xF8\xA0\x11" + "\xA3\xF5\x03\x23\xDA\x61\xD8\x69\x10\xF0\x10\x00\xFB\xD1\x02\x4A" + "\x1A\x60\x70\x47\x00\x60\x08\x40\xFF\xFF\x0F\x00\x6F\xF0\x01\x00" + "\x70\x47\x00\x00\x2D\xE9\xF8\x43\xC0\xF3\x0B\x03\x88\x46\x73\xBB" + "\x0E\x46\x1A\x4C\xDF\xF8\x68\x90\x00\xEB\x08\x07\xBF\x1B\xD6\xB1" + "\x4F\xF0\xC4\x63\x63\x60\xE5\x69\x15\xF0\x02\x05\xFB\xD1\x4F\xF0" + "\x02\x53\xA7\x60\x63\x60\xFF\xF7\xB3\xFF\x40\xF2\x01\x42\xA7\x60" + "\xC4\xF8\x04\x90\x01\x3A\x09\xD1\xE2\x69\x93\x07\xFC\xD4\x8D\xB9" + "\xB6\xF5\x80\x5F\x08\xD2\x00\x20\xBD\xE8\xF8\x83\x61\x69\x01\x31" + "\x18\xBF\x4F\xF0\xFF\x35\xED\xE7\xA6\xF5\x80\x56\xD4\xE7\x6F\xF0" + "\x02\x00\xF1\xE7\x4F\xF0\xFF\x30\xEE\xE7\x00\xBF\x00\x30\x00\x40" + "\x00\x10\x80\x03\xC0\xF3\x0B\x03\x2D\xE9\xF0\x47\x91\x46\x00\x2B" + "\x4E\xD1\x15\x46\xDF\xF8\xA4\x80\xDF\xF8\xA4\xA0\x01\xF5\x80\x74" + "\x00\xEB\x09\x07\x7F\x1B\xA4\xF5\x80\x76\x4D\xB3\xFF\x2D\x05\xD8" + "\x00\x22\x73\x19\x03\xF8\x01\x2B\xA3\x42\xFB\xD1\x4F\xF0\xC4\x63" + "\xC8\xF8\x04\x30\xD8\xF8\x1C\x30\x99\x07\xFB\xD4\x33\x46\xC8\xF8" + "\x08\x70\xC8\xF8\x04\xA0\xA3\x42\x19\xD1\xFF\xF7\x61\xFF\x19\x4B" + "\xC8\xF8\x08\x70\xC8\xF8\x04\x30\x00\x23\xA6\x42\x14\xD1\xD8\xF8" + "\x1C\x20\x92\x07\xFB\xD4\xF3\xB9\xFF\x2D\x04\xF5\x80\x74\x14\xD8" + "\x4F\xF0\x60\x72\x00\x20\x0D\x4B\x9A\x61\xBD\xE8\xF0\x87\x53\xF8" + "\x04\x2B\xC8\xF8\x14\x20\xDE\xE7\xD8\xF8\x14\x10\x56\xF8\x04\x2B" + "\x91\x42\x18\xBF\x4F\xF0\xFF\x33\xDF\xE7\xA5\xF5\x80\x75\xB7\xE7" + "\x6F\xF0\x02\x00\xE9\xE7\x4F\xF0\xFF\x30\xE6\xE7\x00\x30\x00\x40" + "\x00\x81\x80\x02\x00\x01\x80\x03" + }, + { "stm32f4xx.bin", 340, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x08\x00\x20\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x20\x61\x04\x00\x20\xD1\x04\x00\x20\xC9\x04\x00\x20" + "\x05\x4B\x06\x4A\xC3\xF8\x04\x2C\x02\xF1\x88\x32\xC3\xF8\x04\x2C" + "\xD3\xF8\x10\x0C\xC0\x17\x70\x47\x00\x30\x02\x40\x23\x01\x67\x45" + "\x16\x4B\xF0\xB5\x00\x22\x04\x46\x1E\x46\x53\xF8\x04\x0B\xA0\x42" + "\x1B\xD1\x13\x4D\x13\x4F\xD3\x00\x03\xF0\x78\x03\x43\xF0\x02\x00" + "\x3B\x43\xC5\xF8\x10\x0C\xC5\xF8\x10\x3C\xD5\xF8\x0C\x0C\xC3\x03" + "\xFB\xD4\x10\xF0\xF2\x00\x0E\xD1\x01\x32\x0C\x2A\x0A\xD0\x56\xF8" + "\x22\x30\x1B\x1B\x8B\x42\xE6\xD3\x04\xE0\x01\x32\x0C\x2A\xDC\xD1" + "\x6F\xF0\x02\x00\xF0\xBD\x4F\xF0\xFF\x30\xFB\xE7\x20\x05\x00\x20" + "\x00\x30\x02\x40\x02\x00\x01\x00\x6F\xF0\x01\x00\x70\x47\x00\x00" + "\x40\xEA\x02\x03\x9B\x07\x30\xB5\x1C\xD1\x40\xF2\x01\x24\x0F\x4B" + "\x0A\x44\xC3\xF8\x10\x4C\x40\x1A\x8A\x42\x03\xD1\x00\x20\xC3\xF8" + "\x10\x0C\x0E\xE0\x0C\x68\x44\x50\x04\x31\xD3\xF8\x0C\x4C\x14\xF4" + "\x80\x35\xFA\xD1\x14\xF0\xF2\x0F\xEE\xD0\x4F\xF0\xFF\x30\xC3\xF8" + "\x10\x5C\x30\xBD\x6F\xF0\x02\x00\xFB\xE7\x00\xBF\x00\x30\x02\x40" + "\x00\x00\x00\x00\x00\x40\x00\x00\x00\x80\x00\x00\x00\xC0\x00\x00" + "\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x06\x00" + "\x00\x00\x08\x00\x00\x00\x0A\x00\x00\x00\x0C\x00\x00\x00\x0E\x00" + "\x00\x00\x10\x00" + }, + { "stm32f0xx.bin", 432, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x08\x00\x20\x00\x10\x00\x00\x00\x00\x00\x08\x00\x40\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x05\x00\x20\x55\x04\x00\x20\xD9\x04\x00\x20\x39\x05\x00\x20" + "\x02\xB4\x71\x46\x49\x08\x49\x00\x09\x5C\x49\x00\x8E\x44\x02\xBC" + "\x70\x47\xC0\x46\xF7\xB5\x1B\x4A\x13\x68\x01\x3B\x18\x42\x2B\xD1" + "\x19\x4C\x1A\x4B\x25\x68\x1D\x40\x02\x23\x2B\x43\x01\x93\x42\x23" + "\x1D\x43\x00\x29\x01\xD1\x08\x00\xFE\xBD\x13\x68\x8B\x42\x13\xD2" + "\xC9\x1A\x01\x9B\x01\x26\x23\x60\x11\x4B\x18\x60\x11\x4B\x25\x60" + "\x9C\x46\x63\x46\x1F\x68\x3B\x00\x33\x40\x37\x42\xF9\xD1\x16\x68" + "\x9E\x42\x03\xD8\x80\x19\xE4\xE7\x00\x21\xEA\xE7\xC7\x18\x3F\x68" + "\x01\x37\x04\xD1\x04\x33\xF3\xE7\x03\x20\x40\x42\xDC\xE7\x01\x20" + "\xFB\xE7\xC0\x46\xAC\x05\x00\x20\x10\x20\x02\x40\x08\xC9\xFF\xFF" + "\x14\x20\x02\x40\x0C\x20\x02\x40\x03\x00\x13\x43\xF7\xB5\x9B\x07" + "\x22\xD1\x12\x4C\x12\x4B\x25\x68\x8A\x18\x2B\x40\x01\x25\x2E\x00" + "\x1E\x43\x26\x60\x0F\x4F\x00\x92\x42\x1A\x01\x92\x00\x9A\x8A\x42" + "\x02\xD1\x00\x20\x23\x60\xFE\xBD\x01\x9A\x56\x18\x0A\x88\x32\x80" + "\x38\x68\x28\x42\xFC\xD1\x36\x88\xB2\x42\x03\xD0\x01\x20\x23\x60" + "\x40\x42\xF0\xE7\x02\x31\xE9\xE7\x03\x20\xF9\xE7\x10\x20\x02\x40" + "\x08\xC9\xFF\xFF\x0C\x20\x02\x40\x02\x20\x40\x42\x70\x47\x00\x00" + "\x12\x4A\x03\x00\x10\x68\x12\x4A\x00\x05\x00\x0D\x80\x18\x00\xB5" + "\x08\x28\x18\xD8\xFF\xF7\x74\xFF\x09\x17\x05\x17\x09\x09\x17\x17" + "\x05\x00\x80\x21\x0B\x4A\x09\x01\x11\x60\x0B\x4A\x12\x88\x92\x02" + "\xDA\x61\x0A\x4B\x0A\x4A\x1A\x60\x0A\x4A\x1A\x60\x0A\x4B\x18\x68" + "\x00\x06\xC0\x17\x00\xBD\x02\x20\x40\x42\xFB\xE7\x00\x58\x01\x40" + "\xC0\xFB\xFF\xFF\xAC\x05\x00\x20\xCC\xF7\xFF\x1F\x04\x20\x02\x40" + "\x23\x01\x67\x45\xAB\x89\xEF\xCD\x10\x20\x02\x40\x00\x04\x00\x00" + }, + { "lpc13xx.bin", 284, + "\x66\x61\x77\x42\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x00\x10" + "\x00\x08\x00\x10\x00\x10\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x10\x45\x04\x00\x10\xA1\x04\x00\x10\x15\x05\x00\x10" + "\x00\x20\x70\x47\x70\xB5\x4C\x1E\x24\x0B\x06\x0B\x04\xEB\x10\x34" + "\xC0\xF3\x0B\x00\x8A\xB0\xD0\xB9\x32\x23\x10\x4D\xCD\xE9\x05\x36" + "\x07\x94\x01\xA9\x05\xA8\xA8\x47\x01\x9B\x9B\xB9\x34\x23\xCD\xE9" + "\x05\x36\x42\xF6\xE0\x63\x05\xA8\x07\x94\x08\x93\x01\xA9\xA8\x47" + "\x01\x98\x00\x38\x18\xBF\x01\x20\x40\x42\x0A\xB0\x70\xBD\x6F\xF0" + "\x02\x00\xFA\xE7\x4F\xF0\xFF\x30\xF7\xE7\x00\xBF\xF1\x1F\xFF\x1F" + "\x70\xB5\x14\x46\xC0\xF3\x0B\x02\x05\x46\x0E\x46\x8A\xB0\x03\x0B" + "\x42\xBB\x32\x22\x07\x93\xCD\xE9\x05\x23\x01\xA9\x14\x4B\x05\xA8" + "\x98\x47\x01\x9B\x0B\xBB\xB4\xF5\x80\x5F\x14\xD1\x33\x23\x4F\xF4" + "\x80\x52\xCD\xE9\x05\x35\x42\xF6\xE0\x63\x05\xA8\xCD\xE9\x08\x23" + "\x07\x96\x0B\x4B\x01\xA9\x98\x47\x01\x98\x00\x38\x18\xBF\x01\x20" + "\x40\x42\x0A\xB0\x70\xBD\x22\x46\xB2\xF5\x80\x5F\xE6\xDA\xB3\x54" + "\x01\x32\xF9\xE7\x6F\xF0\x02\x00\xF3\xE7\x4F\xF0\xFF\x30\xF0\xE7" + "\xF1\x1F\xFF\x1F\x6F\xF0\x01\x00\x70\x47\x00\x00" + }, + { "lpc15xx.bin", 284, + "\x66\x61\x77\x42\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x00\x02" + "\x00\x08\x00\x02\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x02\x45\x04\x00\x02\xA1\x04\x00\x02\x15\x05\x00\x02" + "\x00\x20\x70\x47\x70\xB5\x4C\x1E\x24\x0B\x06\x0B\x04\xEB\x10\x34" + "\xC0\xF3\x0B\x00\x8A\xB0\xD0\xB9\x32\x23\x10\x4D\xCD\xE9\x05\x36" + "\x07\x94\x01\xA9\x05\xA8\xA8\x47\x01\x9B\x9B\xB9\x34\x23\xCD\xE9" + "\x05\x36\x42\xF6\xE0\x63\x05\xA8\x07\x94\x08\x93\x01\xA9\xA8\x47" + "\x01\x98\x00\x38\x18\xBF\x01\x20\x40\x42\x0A\xB0\x70\xBD\x6F\xF0" + "\x02\x00\xFA\xE7\x4F\xF0\xFF\x30\xF7\xE7\x00\xBF\x05\x02\x00\x03" + "\x70\xB5\x14\x46\xC0\xF3\x0B\x02\x05\x46\x0E\x46\x8A\xB0\x03\x0B" + "\x42\xBB\x32\x22\x07\x93\xCD\xE9\x05\x23\x01\xA9\x14\x4B\x05\xA8" + "\x98\x47\x01\x9B\x0B\xBB\xB4\xF5\x80\x5F\x14\xD1\x33\x23\x4F\xF4" + "\x80\x52\xCD\xE9\x05\x35\x42\xF6\xE0\x63\x05\xA8\xCD\xE9\x08\x23" + "\x07\x96\x0B\x4B\x01\xA9\x98\x47\x01\x98\x00\x38\x18\xBF\x01\x20" + "\x40\x42\x0A\xB0\x70\xBD\x22\x46\xB2\xF5\x80\x5F\xE6\xDA\xB3\x54" + "\x01\x32\xF9\xE7\x6F\xF0\x02\x00\xF3\xE7\x4F\xF0\xFF\x30\xF0\xE7" + "\x05\x02\x00\x03\x6F\xF0\x01\x00\x70\x47\x00\x00" + }, + { "cc13xx.bin", 176, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x10\x00\x20\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x20\x75\x04\x00\x20\x45\x04\x00\x20\x6F\x04\x00\x20" + "\x00\x20\x70\x47\x03\x46\x08\x46\xC3\xF3\x0B\x01\x10\xB5\x59\xB9" + "\x4F\xF0\x80\x51\xD1\xF8\xA8\x11\x8C\x69\x19\x46\xA0\x47\x00\x38" + "\x18\xBF\x01\x20\x40\x42\x10\xBD\x6F\xF0\x02\x00\xFB\xE7\x6F\xF0" + "\x01\x00\x70\x47\xC0\xF3\x0B\x03\x70\xB5\x0C\x46\x8B\xB9\x4F\xF0" + "\x80\x56\x45\x18\x28\x1B\x3C\xB1\xD6\xF8\xA8\x31\x5B\x69\x98\x47" + "\x50\xB9\xB4\xF5\x80\x5F\x01\xD8\x00\x20\x70\xBD\xA4\xF5\x80\x54" + "\xF0\xE7\x6F\xF0\x02\x00\xF8\xE7\x4F\xF0\xFF\x30\xF5\xE7\x00\x00" + }, + { "nrf528xx.bin", 324, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x20\x69\x04\x00\x20\xDD\x04\x00\x20\x61\x04\x00\x20" + "\x4F\xF0\x80\x52\x04\x49\x13\x69\x0B\x60\x52\x69\x53\x43\x03\x4A" + "\xC3\x61\x13\x60\x00\x20\x70\x47\x3C\x05\x00\x20\x40\x05\x00\x20" + "\x6F\xF0\x01\x00\x70\x47\x00\x00\x19\x4B\x70\xB5\x1B\x68\x83\x42" + "\x28\xD3\x18\x4A\x13\x68\x01\x3B\x03\x42\x26\xD1\x02\x23\x16\x4C" + "\xC4\xF8\x04\x35\x29\xB9\x08\x46\x00\x22\x13\x4B\xC3\xF8\x04\x25" + "\x70\xBD\x13\x68\xC4\xF8\x08\x05\x8B\x42\x2C\xBF\x00\x21\xC9\x1A" + "\xD4\xF8\x00\x34\x01\x2B\xFB\xD1\x00\x23\x15\x68\xAB\x42\x01\xD3" + "\x28\x44\xE7\xE7\xC6\x58\x01\x36\x01\xD1\x04\x33\xF6\xE7\x4F\xF0" + "\xFF\x30\xE1\xE7\x6F\xF0\x01\x00\xE2\xE7\x6F\xF0\x02\x00\xDF\xE7" + "\x40\x05\x00\x20\x3C\x05\x00\x20\x00\xE0\x01\x40\x15\x4B\x70\xB5" + "\x1B\x68\x83\x42\x1F\xD3\x40\xEA\x02\x03\x9B\x07\x1E\xD1\x01\x24" + "\x11\x4B\x0A\x44\xC3\xF8\x04\x45\x40\x1A\x91\x42\x05\xD1\x00\x20" + "\x00\x22\x0D\x4B\xC3\xF8\x04\x25\x70\xBD\x0C\x68\x45\x18\x44\x50" + "\xD3\xF8\x00\x64\x01\x2E\xFB\xD1\x2D\x68\x04\x31\xAC\x42\xEC\xD0" + "\x4F\xF0\xFF\x30\xEC\xE7\x6F\xF0\x01\x00\xED\xE7\x6F\xF0\x02\x00" + "\xEA\xE7\x00\xBF\x40\x05\x00\x20\x00\xE0\x01\x40\x00\x04\x00\x00" + "\x00\x00\x03\x00" + }, + { "efr32bg2x.bin", 344, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x41\x04\x00\x20\x51\x04\x00\x20\xDD\x04\x00\x20\x4B\x04\x00\x20" + "\x4F\xF4\xB0\x23\xC3\x61\x00\x20\x70\x47\x6F\xF0\x01\x00\x70\x47" + "\x03\x46\xB3\xF5\xB0\x2F\x08\x46\x70\xB5\x31\xD8\xC3\xF3\x0C\x02" + "\x8A\xBB\x4F\xF4\x00\x31\x19\x4A\x02\x26\x91\x66\x01\x22\x18\x4C" + "\x18\x49\xE2\x60\x40\xB1\x4B\x61\xCA\x69\x12\xF0\x06\x05\x1C\xD1" + "\x12\x01\x05\xD4\x4F\xF0\xFF\x30\x01\x22\x13\x4B\xDA\x60\x70\xBD" + "\xB0\xF5\x00\x5F\x88\xBF\xA0\xF5\x00\x55\x26\x61\xCA\x69\x12\xF0" + "\x01\x02\xFB\xD1\xD0\x58\x01\x30\xEC\xD1\x04\x32\xB2\xF5\x00\x5F" + "\xF8\xD1\x28\x46\x03\xF5\x00\x53\xDC\xE7\x6F\xF0\x01\x00\xE3\xE7" + "\x6F\xF0\x01\x00\xE3\xE7\x6F\xF0\x02\x00\xE0\xE7\x00\x90\x00\x40" + "\x00\x10\x03\x40\x00\x00\x03\x40\x00\x20\x03\x40\xB0\xF5\xB0\x2F" + "\x30\xB5\x2F\xD8\x40\xEA\x02\x03\x9B\x07\x2E\xD1\x4F\xF4\x00\x34" + "\x17\x4B\x04\x39\x9C\x66\x01\x24\x03\xF5\x20\x33\xDC\x60\x02\x44" + "\xA3\xF5\x80\x53\x90\x42\x01\xD1\x00\x20\x08\xE0\x58\x61\xDC\x69" + "\x14\xF0\x06\x0F\x13\xD1\x25\x01\x05\xD4\x4F\xF0\xFF\x30\x01\x22" + "\x0C\x4B\xDA\x60\x30\xBD\x4C\x68\x9C\x61\xDC\x69\xE4\x07\xFC\xD4" + "\x05\x68\x51\xF8\x04\x4F\xA5\x42\xEF\xD1\x04\x30\xE2\xE7\x6F\xF0" + "\x01\x00\xEC\xE7\x6F\xF0\x01\x00\xEC\xE7\x6F\xF0\x02\x00\xE9\xE7" + "\x00\x90\x00\x40\x00\x20\x03\x40" + }, + { "pico.bin", 484, + "\x66\x61\x77\x42\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x00\x20" + "\x00\x08\x00\x20\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x69\x05\x00\x20\x41\x04\x00\x20\xC9\x04\x00\x20\x51\x05\x00\x20" + "\x80\x23\x70\xB5\xDB\x03\x05\x00\x0C\x00\x98\x42\x2C\xD8\x03\x05" + "\x2D\xD1\x0B\x05\x04\xD0\x80\x23\x0C\x0B\x24\x03\x5B\x01\xE4\x18" + "\x14\x4B\x1B\x68\x98\x47\x14\x4B\x1B\x68\x98\x47\x80\x22\x13\x4B" + "\x28\x00\x21\x00\x52\x02\x1E\x68\xD8\x23\xB0\x47\x10\x4B\x1B\x68" + "\x98\x47\x10\x4B\x1B\x68\x98\x47\x80\x23\xF0\x20\x5B\x05\x00\x06" + "\xEB\x18\x45\x1B\x5A\x19\xA2\x42\x01\xD3\x00\x20\x70\xBD\x04\xCB" + "\x01\x32\xF7\xD0\x01\x20\x00\xE0\x02\x20\x40\x42\xF6\xE7\x03\x20" + "\xFB\xE7\xC0\x46\xE4\x05\x00\x20\xF0\x05\x00\x20\xEC\x05\x00\x20" + "\xF4\x05\x00\x20\xE8\x05\x00\x20\xF8\xB5\x80\x23\x05\x00\x0F\x00" + "\x14\x00\xDB\x03\x98\x42\x29\xD8\xFF\x23\x06\x00\x1E\x40\x18\x42" + "\x27\xD1\x1A\x42\x02\xD0\x9C\x43\x01\x34\xFF\x34\x13\x4B\x1B\x68" + "\x98\x47\x13\x4B\x1B\x68\x98\x47\x12\x4B\x28\x00\x22\x00\x39\x00" + "\x1B\x68\x98\x47\x10\x4B\x1B\x68\x98\x47\x10\x4B\x1B\x68\x98\x47" + "\x80\x23\x5B\x05\xED\x18\xAB\x19\xB4\x42\x01\xD8\x00\x20\xF8\xBD" + "\x1B\x68\xBA\x59\x93\x42\x06\xD1\x04\x36\xF4\xE7\x02\x20\x40\x42" + "\xF5\xE7\x03\x20\xFB\xE7\x01\x20\xF9\xE7\xC0\x46\xE4\x05\x00\x20" + "\xF0\x05\x00\x20\xF8\x05\x00\x20\xF4\x05\x00\x20\xE8\x05\x00\x20" + "\x02\x20\x40\x42\x70\x47\x14\x23\x10\xB5\x01\x00\x18\x88\x04\x33" + "\x1B\x88\x98\x47\x10\xBD\x00\x00\x10\xB5\x04\x00\x11\x48\xFF\xF7" + "\xF2\xFF\x11\x4B\x18\x60\x11\x48\xFF\xF7\xED\xFF\x10\x4B\x18\x60" + "\x10\x48\xFF\xF7\xE8\xFF\x10\x4B\x18\x60\x10\x48\xFF\xF7\xE3\xFF" + "\x0F\x4B\x18\x60\x0F\x48\xFF\xF7\xDE\xFF\x0F\x4B\x18\x60\x0F\x48" + "\xFF\xF7\xD9\xFF\x0E\x4B\x18\x60\x80\x23\xDB\x03\x00\x20\xE3\x61" + "\x10\xBD\xC0\x46\x49\x46\x00\x00\xE4\x05\x00\x20\x45\x58\x00\x00" + "\xF0\x05\x00\x20\x52\x45\x00\x00\xEC\x05\x00\x20\x52\x50\x00\x00" + "\xF8\x05\x00\x20\x46\x43\x00\x00\xF4\x05\x00\x20\x43\x58\x00\x00" + "\xE8\x05\x00\x20" + }, +}; + +void *get_builtin_file(const char *name, size_t *sz) { + int n; + for (n = 0; n < (sizeof(files)/sizeof(files[0])); n++) { + if (!strcmp(name, files[n].name)) { + *sz = files[n].size; + return files[n].data; + } + } + return NULL; +} + +const char *get_builtin_filename(unsigned n) { + if (n >= (sizeof(files)/sizeof(files[0]))) { + return NULL; + } + return files[n].name; +} diff --git a/include/agent.ld b/include/agent.ld @@ -0,0 +1,32 @@ + +/* RAM only binary layout */ + +SECTIONS { + .text : { + . = ALIGN(4); + KEEP (*(.vectors)) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + . = ALIGN(4); + __data_init__ = . ; + } /* >RAM */ + .data : { + . = ALIGN(4); + __data_start__ = . ; + *(.data) + *(.data.*) + . = ALIGN(4); + __data_end__ = . ; + } /* >RAM */ + .bss : { + . = ALIGN(4); + __bss_start__ = . ; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = . ; + } /*>RAM */ +} diff --git a/include/agent/flash.h b/include/agent/flash.h @@ -0,0 +1,140 @@ +// agent/flash.h +// +// Copyright 2015 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _AGENT_FLASH_H_ +#define _AGENT_FLASH_H_ + +#include <stdint.h> + +#define AGENT_MAGIC 0x42776166 +#define AGENT_VERSION 0x00010000 + +typedef struct flash_agent { + uint32_t magic; + uint32_t version; + uint32_t flags; + uint32_t load_addr; + + uint32_t data_addr; + uint32_t data_size; // bytes + uint32_t flash_addr; + uint32_t flash_size; // bytes + + uint32_t reserved0; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + +#ifdef _AGENT_HOST_ + uint32_t setup; + uint32_t erase; + uint32_t write; + uint32_t ioctl; +#else + int (*setup)(struct flash_agent *agent); + int (*erase)(uint32_t flash_addr, uint32_t length); + int (*write)(uint32_t flash_addr, const void *data, uint32_t length); + int (*ioctl)(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1); +#endif +} flash_agent; + +#ifndef _AGENT_HOST_ +int flash_agent_setup(flash_agent *agent); +int flash_agent_erase(uint32_t flash_addr, uint32_t length); +int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length); +int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1); +#endif + +#define ERR_NONE 0 +#define ERR_FAIL -1 +#define ERR_INVALID -2 +#define ERR_ALIGNMENT -3 + +#define FLAG_WSZ_256B 0x00000100 +#define FLAG_WSZ_512B 0x00000200 +#define FLAG_WSZ_1K 0x00000400 +#define FLAG_WSZ_2K 0x00000800 +#define FLAG_WSZ_4K 0x00001000 +// optional hints as to underlying write block sizes + +#define FLAG_BOOT_ROM_HACK 0x00000001 +// Allow a boot ROM to run after RESET by setting a watchpoint +// at 0 and running until the watchpoint is hit. Necessary on +// some parts which require boot ROM initialization of Flash +// timing registers, etc. + + +// Flash agent binaries will be downloaded to device memory at +// fa.load_addr. The memory below this address will be used as +// the stack for method calls. It should be sized appropriately. +// +// The fa.magic field will be replaced with 0xbe00be00 (two +// Thumb BKPT instructions) before download to device. +// +// Calling convention for flash_agent methods: +// 1. SP will be set to fa.load_addr - 4 +// 2. LR will be set to fa.load_addr +// 3. PC will be set to the method address +// 4. R0..R3 will be loaded with method arguments +// 5. Processor will be resumed (in Privileged Thread mode) +// 6. Upon processor entry to debug mode +// a. if PC == fa.base_addr, status read from R0 +// b. else status = fatal error + + +// setup() must be invoked after processor reset and before any +// other methods are invoked. The fields data_addr, data_size, +// flash_addr, and flash_size are read back after this method +// returns success (to allow it to dynamically size flash based +// on part ID, etc). +// - ERR_INVALID indicates an unsupported part + +// fa.data_size must be a multiple of the minimum block size that +// fa.write requires, so that if the host has to issue a series +// of fa.write calls to do a larger-than-data-buffer-sized flash write, +// subsequent write calls will have appropriate alignment. +// +// fa.write() may round writes up the the minimum write block size +// as necessary, and should fill with 0s in that case.* +// +// fa.write() behaviour is undefined if the underlying flash has not +// been erased first. It may fail (ERR_FAIL) or it may appear to +// succeed, but flash contents may be incorrect. +// +// fa.write() may fail (ERR_ALIGN) if the start address is not aligned +// with a flash page or block.* +// +// fa.erase() may round up to the next erasure block size if necessary +// to ensure the requested region is erased.* +// +// fa.erase(fa.flash_addr, fa.flash_size) should cause a full erase if +// possible. +// +// fa.ioctl() must return ERR_INVALID if op is unsupported. +// Currently no ops are defined, but OTP/EEPROM/Config bits are +// planned to be managed with ioctls. +// +// Bogus parameters may cause failure (ERR_INVALID) +// +// * In general, conveying the full complexity of embedded flash +// configuration (which could include various banks of various sizes, +// with differing write and erase block size requirements) is not +// attempted. The goal is to provide an agent that can reasonably +// handle reasonable flash requests (eg the user knows what a sane +// starting alignment, etc is, does not split logical "partitions" +// across physical erase block boundaries, etc) + +#endif diff --git a/include/fw/io.h b/include/fw/io.h @@ -0,0 +1,15 @@ +/* io.h */ + +#ifndef _IO_H_ +#define _IO_H_ + +#define readb(a) (*((volatile unsigned char *) (a))) +#define writeb(v, a) (*((volatile unsigned char *) (a)) = (v)) + +#define readw(a) (*((volatile unsigned short *) (a))) +#define writew(v, a) (*((volatile unsigned short *) (a)) = (v)) + +#define readl(a) (*((volatile unsigned int *) (a))) +#define writel(v, a) (*((volatile unsigned int *) (a)) = (v)) + +#endif