flash/nor: add cm32m4xxr/nuspi/custom flash driver

- cm32m4xxr flash driver is for cm32m4xxr devices
- nuspi flash driver is for nuclei evalsoc devices
- custom flash driver is for customized flash driver
  without modify openocd source code, see https://github.com/riscv-mcu/openflashloader

Change-Id: I86c4f0298707b5cfdfb77b6d8f4cbed3a189ddf0
Signed-off-by: wangyanwen <wangyanwen@nucleisys.com>
This commit is contained in:
wangyanwen 2023-10-09 11:37:52 +08:00 committed by Huaqi Fang
parent 285f810ce3
commit ef8184f193
12 changed files with 3028 additions and 0 deletions

View File

@ -0,0 +1,51 @@
BIN2C = ../../../../src/helper/bin2char.sh
CROSS_COMPILE ?= riscv-nuclei-elf-
RISCV_CC=$(CROSS_COMPILE)gcc
RISCV_OBJCOPY=$(CROSS_COMPILE)objcopy
RISCV_OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS = -nostdlib -nostartfiles -Wall -Werror -Os -fPIC -Wunused-result -g
RISCV32_CFLAGS = -march=rv32e -mabi=ilp32e $(CFLAGS)
RISCV64_CFLAGS = -march=rv64i -mabi=lp64 $(CFLAGS)
all: riscv32_nuspi.inc riscv64_nuspi.inc
.PHONY: clean
# .c -> .o
riscv32_%.o: riscv_%.c
$(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@
riscv64_%.o: riscv_%.c
$(RISCV_CC) -c $(RISCV64_CFLAGS) $< -o $@
# .S -> .o
riscv32_%.o: riscv_%.S
$(RISCV_CC) -c $(RISCV32_CFLAGS) $^ -o $@
riscv64_%.o: riscv_%.S
$(RISCV_CC) -c $(RISCV64_CFLAGS) $^ -o $@
# .o -> .elf
riscv32_%.elf: riscv32_%.o riscv32_wrapper.o
$(RISCV_CC) -T riscv.lds $(RISCV32_CFLAGS) $^ -o $@
riscv64_%.elf: riscv64_%.o riscv64_wrapper.o
$(RISCV_CC) -T riscv.lds $(RISCV64_CFLAGS) $^ -o $@
# .elf -> .bin
%.bin: %.elf
$(RISCV_OBJCOPY) -Obinary $< $@
# .bin -> .inc
%.inc: %.bin
$(BIN2C) < $< > $@
# utility
%.lst: %.elf
$(RISCV_OBJDUMP) -S $< > $@
clean:
-rm -f *.elf *.o *.lst *.bin *.inc

View File

@ -0,0 +1,17 @@
OUTPUT_ARCH( "riscv" )
SECTIONS
{
. = 0x12340000;
.text :
{
*(.text.entry)
*(.text)
}
.data :
{
*(.data)
}
}

View File

@ -0,0 +1,75 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0x01,0x00,0x00,0x13,0x01,0x01,0x4a,0xef,0x00,0x40,0x1d,0x73,0x00,0x10,0x00,
0x13,0x76,0x16,0x00,0x93,0x07,0x10,0x7d,0x63,0x18,0x06,0x02,0x93,0x87,0xf7,0xff,
0x63,0x88,0x07,0x02,0x03,0x27,0x85,0x04,0xe3,0x4a,0x07,0xfe,0x6f,0x00,0x00,0x01,
0x03,0x27,0xc5,0x07,0x13,0x77,0x07,0x01,0x63,0x18,0x07,0x00,0x23,0x24,0xb5,0x04,
0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x93,0x87,0xf7,0xff,0xe3,0x92,0x07,0xfe,
0x13,0x05,0x00,0x10,0x67,0x80,0x00,0x00,0x93,0xf5,0x15,0x00,0x93,0x07,0x10,0x7d,
0x63,0x98,0x05,0x02,0x93,0x87,0xf7,0xff,0x63,0x88,0x07,0x02,0x03,0x27,0x45,0x07,
0x13,0x77,0x17,0x00,0xe3,0x08,0x07,0xfe,0x6f,0x00,0x00,0x01,0x03,0x27,0xc5,0x07,
0x13,0x77,0x17,0x00,0x63,0x16,0x07,0x00,0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,
0x93,0x87,0xf7,0xff,0xe3,0x94,0x07,0xfe,0x13,0x05,0x00,0x01,0x67,0x80,0x00,0x00,
0x83,0x27,0x05,0x04,0x13,0x01,0x01,0xff,0x23,0x24,0x81,0x00,0x23,0x22,0x91,0x00,
0x23,0x26,0x11,0x00,0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,
0x23,0x2c,0xf5,0x00,0x03,0xa6,0x45,0x00,0x93,0x84,0x05,0x00,0x93,0x05,0x50,0x00,
0x13,0x04,0x05,0x00,0xef,0xf0,0xdf,0xf3,0xb7,0x07,0x01,0x00,0x63,0x18,0x05,0x08,
0x83,0xa7,0x44,0x00,0x93,0xf7,0x17,0x00,0x63,0x90,0x07,0x04,0x93,0x07,0x10,0x7d,
0x93,0x87,0xf7,0xff,0x63,0x80,0x07,0x04,0x03,0x27,0xc4,0x04,0xe3,0x4a,0x07,0xfe,
0x6f,0x00,0x40,0x01,0x03,0x27,0xc4,0x07,0x13,0x77,0x07,0x02,0x63,0x10,0x07,0x02,
0x83,0x27,0xc4,0x04,0x13,0x07,0x10,0x7d,0x13,0x07,0xf7,0xff,0x63,0x18,0x07,0x02,
0x37,0x05,0x05,0x00,0x6f,0x00,0x40,0x01,0x93,0x07,0x10,0x7d,0x93,0x87,0xf7,0xff,
0xe3,0x9a,0x07,0xfc,0x37,0x15,0x02,0x00,0x83,0x20,0xc1,0x00,0x03,0x24,0x81,0x00,
0x83,0x24,0x41,0x00,0x13,0x01,0x01,0x01,0x67,0x80,0x00,0x00,0x03,0xa6,0x44,0x00,
0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,0x23,0x20,0xe1,0x00,0xef,0xf0,0x5f,0xeb,
0x03,0x27,0x01,0x00,0x63,0x08,0x05,0x00,0xb7,0x07,0x03,0x00,0x33,0x65,0xf5,0x00,
0x6f,0xf0,0x9f,0xfc,0x83,0xa7,0x44,0x00,0x93,0x06,0x10,0x7d,0x93,0xf7,0x17,0x00,
0x63,0x88,0x07,0x04,0x93,0x07,0x10,0x7d,0x93,0x87,0xf7,0xff,0x63,0x96,0x07,0x00,
0x37,0x15,0x04,0x00,0x6f,0xf0,0x5f,0xfa,0x83,0x26,0xc4,0x07,0x93,0xf6,0x06,0x02,
0xe3,0x94,0x06,0xfe,0x83,0x27,0xc4,0x04,0x93,0xf7,0xf7,0x0f,0x93,0xf7,0x17,0x00,
0xe3,0x94,0x07,0xf6,0x23,0x2c,0x04,0x00,0x83,0x27,0x04,0x04,0x93,0xe7,0x87,0x00,
0x23,0x20,0xf4,0x04,0x6f,0xf0,0x5f,0xf7,0x83,0x27,0xc4,0x04,0xe3,0xde,0x07,0xfc,
0x93,0x86,0xf6,0xff,0xe3,0x9a,0x06,0xfe,0x6f,0xf0,0x9f,0xfb,0x13,0x01,0xc1,0xfc,
0x23,0x24,0xe1,0x00,0x03,0x27,0xc5,0x01,0x23,0x20,0xf1,0x02,0xb7,0x07,0x01,0x00,
0x23,0x26,0x81,0x02,0x23,0x24,0x91,0x02,0x23,0x28,0x11,0x02,0x23,0x28,0xb1,0x00,
0x23,0x26,0xc1,0x00,0x23,0x22,0x01,0x02,0x93,0x87,0xf7,0x0f,0x13,0x04,0x05,0x00,
0x93,0x84,0x06,0x00,0x63,0xf6,0xe7,0x00,0x93,0x07,0x10,0x00,0x23,0x22,0xf1,0x02,
0x83,0x25,0x41,0x02,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xe3,0x93,0x67,0x15,0x00,
0x63,0x12,0x05,0x02,0x93,0x07,0x01,0x02,0x93,0x85,0x07,0x00,0x13,0x05,0x04,0x00,
0x23,0x2a,0xf1,0x00,0xef,0xf0,0xdf,0xe5,0x23,0x20,0xa1,0x00,0x63,0x08,0x05,0x00,
0x93,0x67,0x25,0x00,0x23,0x20,0xf1,0x00,0x6f,0x00,0x80,0x01,0x83,0x27,0x01,0x01,
0x93,0x87,0xf7,0xff,0xb3,0xf7,0x97,0x00,0x03,0x27,0x81,0x00,0x63,0x1e,0x07,0x00,
0x83,0x20,0x01,0x03,0x03,0x24,0xc1,0x02,0x03,0x25,0x01,0x00,0x83,0x24,0x81,0x02,
0x13,0x01,0x41,0x03,0x67,0x80,0x00,0x00,0x83,0x26,0x81,0x00,0x03,0x27,0x81,0x00,
0x23,0x22,0xd1,0x00,0x83,0x26,0x01,0x01,0x33,0x07,0xf7,0x00,0x63,0xf6,0xe6,0x00,
0xb3,0x87,0xf6,0x40,0x23,0x22,0xf1,0x00,0x03,0x26,0x41,0x02,0x93,0x05,0x60,0x00,
0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xd5,0x63,0x0a,0x05,0x00,0xb7,0x04,0x10,0x00,
0xb3,0x64,0x95,0x00,0x93,0xe7,0x34,0x00,0x6f,0xf0,0xdf,0xf8,0x83,0x25,0x41,0x02,
0x13,0x05,0x04,0x00,0xef,0xf0,0x5f,0xd8,0x63,0x06,0x05,0x00,0xb7,0x04,0x20,0x00,
0x6f,0xf0,0x1f,0xfe,0x03,0x26,0x41,0x02,0x83,0x45,0x01,0x02,0x93,0x07,0x20,0x00,
0x23,0x2c,0xf4,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xd1,0x63,0x06,0x05,0x00,
0xb7,0x04,0x30,0x00,0x6f,0xf0,0xdf,0xfb,0x83,0x27,0x01,0x02,0x93,0xf7,0x07,0x10,
0x63,0x80,0x07,0x02,0x03,0x26,0x41,0x02,0x93,0xd5,0x84,0x01,0x13,0x05,0x04,0x00,
0xef,0xf0,0x1f,0xcf,0x63,0x06,0x05,0x00,0xb7,0x04,0x40,0x00,0x6f,0xf0,0x5f,0xf9,
0x03,0x26,0x41,0x02,0x93,0xd5,0x04,0x01,0x93,0xf5,0xf5,0x0f,0x13,0x05,0x04,0x00,
0xef,0xf0,0x1f,0xcd,0xe3,0x12,0x05,0xfe,0x03,0x26,0x41,0x02,0x93,0xd5,0x84,0x00,
0x93,0xf5,0xf5,0x0f,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xcb,0x63,0x06,0x05,0x00,
0xb7,0x04,0x50,0x00,0x6f,0xf0,0xdf,0xf5,0x03,0x26,0x41,0x02,0x93,0xf5,0xf4,0x0f,
0x13,0x05,0x04,0x00,0xef,0xf0,0xdf,0xc9,0x63,0x18,0x05,0x02,0x83,0x27,0xc1,0x00,
0x03,0x27,0x41,0x00,0x33,0x07,0xf7,0x00,0x03,0x26,0x41,0x02,0x63,0x12,0xf7,0x02,
0x93,0x05,0x06,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x1f,0xcc,0x63,0x00,0x05,0x04,
0xb7,0x04,0x80,0x00,0x6f,0xf0,0xdf,0xf1,0xb7,0x04,0x60,0x00,0x6f,0xf0,0x5f,0xf1,
0x83,0xc5,0x07,0x00,0x13,0x05,0x04,0x00,0x23,0x2e,0xe1,0x00,0x23,0x2c,0xf1,0x00,
0xef,0xf0,0x1f,0xc5,0x83,0x27,0x81,0x01,0x03,0x27,0xc1,0x01,0x93,0x87,0x17,0x00,
0xe3,0x0c,0x05,0xfa,0xb7,0x04,0x70,0x00,0x6f,0xf0,0x9f,0xee,0x83,0x25,0x41,0x01,
0x23,0x2c,0x04,0x00,0x13,0x05,0x04,0x00,0xef,0xf0,0x9f,0xcb,0x63,0x16,0x05,0x02,
0x03,0x27,0x41,0x00,0x83,0x27,0xc1,0x00,0xb3,0x84,0xe4,0x00,0xb3,0x87,0xe7,0x00,
0x23,0x26,0xf1,0x00,0x83,0x27,0x81,0x00,0xb3,0x87,0xe7,0x40,0x23,0x24,0xf1,0x00,
0x93,0x07,0x00,0x00,0x6f,0xf0,0x5f,0xe5,0xb7,0x04,0x90,0x00,0x6f,0xf0,0x5f,0xea,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,
0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,0x09,0x53,0x67,0x08,

View File

@ -0,0 +1,87 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x17,0x01,0x00,0x00,0x13,0x01,0x01,0x56,0xef,0x00,0x00,0x1f,0x73,0x00,0x10,0x00,
0x13,0x76,0x16,0x00,0x93,0x07,0x10,0x7d,0x63,0x1c,0x06,0x02,0x9b,0x87,0xf7,0xff,
0x63,0x8c,0x07,0x02,0x03,0x27,0x85,0x04,0x1b,0x07,0x07,0x00,0xe3,0x48,0x07,0xfe,
0x6f,0x00,0x00,0x01,0x03,0x27,0xc5,0x07,0x13,0x77,0x07,0x01,0x63,0x1a,0x07,0x00,
0x9b,0x85,0x05,0x00,0x23,0x24,0xb5,0x04,0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,
0x9b,0x87,0xf7,0xff,0xe3,0x90,0x07,0xfe,0x13,0x05,0x00,0x10,0x67,0x80,0x00,0x00,
0x93,0xf5,0x15,0x00,0x93,0x07,0x10,0x7d,0x63,0x98,0x05,0x02,0x9b,0x87,0xf7,0xff,
0x63,0x88,0x07,0x02,0x03,0x27,0x45,0x07,0x13,0x77,0x17,0x00,0xe3,0x08,0x07,0xfe,
0x6f,0x00,0x00,0x01,0x03,0x27,0xc5,0x07,0x13,0x77,0x17,0x00,0x63,0x16,0x07,0x00,
0x13,0x05,0x00,0x00,0x67,0x80,0x00,0x00,0x9b,0x87,0xf7,0xff,0xe3,0x94,0x07,0xfe,
0x13,0x05,0x00,0x01,0x67,0x80,0x00,0x00,0x83,0x27,0x05,0x04,0x13,0x01,0x01,0xfe,
0x23,0x38,0x81,0x00,0x9b,0x87,0x07,0x00,0x23,0x34,0x91,0x00,0x23,0x3c,0x11,0x00,
0x23,0x30,0x21,0x01,0x93,0xf7,0x77,0xff,0x23,0x20,0xf5,0x04,0x93,0x07,0x20,0x00,
0x23,0x2c,0xf5,0x00,0x03,0xa6,0x45,0x00,0x93,0x84,0x05,0x00,0x93,0x05,0x50,0x00,
0x13,0x04,0x05,0x00,0xef,0xf0,0xdf,0xf2,0xb7,0x07,0x01,0x00,0x63,0x18,0x05,0x08,
0x83,0xa7,0x44,0x00,0x93,0xf7,0x17,0x00,0x63,0x92,0x07,0x04,0x93,0x07,0x10,0x7d,
0x9b,0x87,0xf7,0xff,0x63,0x82,0x07,0x04,0x03,0x27,0xc4,0x04,0x1b,0x07,0x07,0x00,
0xe3,0x48,0x07,0xfe,0x6f,0x00,0x40,0x01,0x03,0x27,0xc4,0x07,0x13,0x77,0x07,0x02,
0x63,0x10,0x07,0x02,0x83,0x27,0xc4,0x04,0x13,0x09,0x10,0x7d,0x1b,0x09,0xf9,0xff,
0x63,0x1a,0x09,0x02,0x37,0x05,0x05,0x00,0x6f,0x00,0x40,0x01,0x93,0x07,0x10,0x7d,
0x9b,0x87,0xf7,0xff,0xe3,0x9a,0x07,0xfc,0x37,0x15,0x02,0x00,0x83,0x30,0x81,0x01,
0x03,0x34,0x01,0x01,0x83,0x34,0x81,0x00,0x03,0x39,0x01,0x00,0x13,0x01,0x01,0x02,
0x67,0x80,0x00,0x00,0x03,0xa6,0x44,0x00,0x93,0x05,0x00,0x00,0x13,0x05,0x04,0x00,
0xef,0xf0,0x1f,0xea,0x63,0x0a,0x05,0x00,0xb7,0x07,0x03,0x00,0x33,0x65,0xf5,0x00,
0x1b,0x05,0x05,0x00,0x6f,0xf0,0x9f,0xfc,0x83,0xa7,0x44,0x00,0x93,0x06,0x10,0x7d,
0x93,0xf7,0x17,0x00,0x63,0x8c,0x07,0x04,0x93,0x07,0x10,0x7d,0x9b,0x87,0xf7,0xff,
0x63,0x96,0x07,0x00,0x37,0x15,0x04,0x00,0x6f,0xf0,0x5f,0xfa,0x03,0x27,0xc4,0x07,
0x13,0x77,0x07,0x02,0xe3,0x14,0x07,0xfe,0x83,0x27,0xc4,0x04,0x93,0xf7,0xf7,0x0f,
0x93,0xf7,0x17,0x00,0xe3,0x94,0x07,0xf6,0x23,0x2c,0x04,0x00,0x83,0x27,0x04,0x04,
0x9b,0x87,0x07,0x00,0x93,0xe7,0x87,0x00,0x23,0x20,0xf4,0x04,0x6f,0xf0,0x1f,0xf7,
0x03,0x27,0xc4,0x04,0x9b,0x07,0x07,0x00,0xe3,0xda,0x07,0xfc,0x9b,0x86,0xf6,0xff,
0xe3,0x98,0x06,0xfe,0x6f,0xf0,0x1f,0xfb,0x13,0x01,0x01,0xf9,0x23,0x34,0x31,0x05,
0x93,0x09,0x07,0x00,0x03,0x27,0xc5,0x01,0x23,0x24,0xf1,0x00,0xb7,0x07,0x01,0x00,
0x23,0x3c,0x91,0x04,0x23,0x38,0x21,0x05,0x23,0x30,0x41,0x05,0x23,0x3c,0x51,0x03,
0x23,0x34,0x11,0x06,0x23,0x30,0x81,0x06,0x23,0x38,0x61,0x03,0x23,0x34,0x71,0x03,
0x23,0x30,0x81,0x03,0x23,0x3c,0x91,0x01,0x23,0x26,0x01,0x00,0x1b,0x07,0x07,0x00,
0x93,0x87,0xf7,0x0f,0x93,0x04,0x05,0x00,0x13,0x8a,0x05,0x00,0x93,0x0a,0x06,0x00,
0x13,0x89,0x06,0x00,0x63,0xf6,0xe7,0x00,0x93,0x07,0x10,0x00,0x23,0x26,0xf1,0x00,
0x83,0x25,0xc1,0x00,0x13,0x85,0x04,0x00,0xef,0xf0,0x9f,0xdf,0x63,0x02,0x05,0x04,
0x13,0x65,0x15,0x00,0x1b,0x04,0x05,0x00,0x83,0x30,0x81,0x06,0x13,0x05,0x04,0x00,
0x03,0x34,0x01,0x06,0x83,0x34,0x81,0x05,0x03,0x39,0x01,0x05,0x83,0x39,0x81,0x04,
0x03,0x3a,0x01,0x04,0x83,0x3a,0x81,0x03,0x03,0x3b,0x01,0x03,0x83,0x3b,0x81,0x02,
0x03,0x3c,0x01,0x02,0x83,0x3c,0x81,0x01,0x13,0x01,0x01,0x07,0x67,0x80,0x00,0x00,
0x93,0x0b,0x81,0x00,0x93,0x85,0x0b,0x00,0x13,0x85,0x04,0x00,0xef,0xf0,0xdf,0xde,
0x13,0x04,0x05,0x00,0x63,0x06,0x05,0x00,0x13,0x65,0x25,0x00,0x6f,0xf0,0x9f,0xfa,
0x9b,0x07,0xfa,0xff,0xb3,0x77,0xf9,0x00,0x9b,0x87,0x07,0x00,0x13,0x0c,0x20,0x00,
0xe3,0x8c,0x09,0xf8,0x3b,0x87,0xf9,0x00,0x13,0x8b,0x09,0x00,0x63,0x74,0xea,0x00,
0x3b,0x0b,0xfa,0x40,0x03,0x26,0xc1,0x00,0x93,0x05,0x60,0x00,0x13,0x85,0x04,0x00,
0xef,0xf0,0x1f,0xd1,0x63,0x0c,0x05,0x00,0xb7,0x07,0x10,0x00,0x33,0xe5,0xa7,0x00,
0x1b,0x05,0x05,0x00,0x13,0x64,0x35,0x00,0x6f,0xf0,0x1f,0xf6,0x83,0x25,0xc1,0x00,
0x13,0x85,0x04,0x00,0xef,0xf0,0xdf,0xd3,0x63,0x06,0x05,0x00,0xb7,0x07,0x20,0x00,
0x6f,0xf0,0xdf,0xfd,0x03,0x26,0xc1,0x00,0x83,0x45,0x81,0x00,0x23,0xac,0x84,0x01,
0x13,0x85,0x04,0x00,0xef,0xf0,0xdf,0xcc,0x63,0x06,0x05,0x00,0xb7,0x07,0x30,0x00,
0x6f,0xf0,0xdf,0xfb,0x83,0x27,0x81,0x00,0x93,0xf7,0x07,0x10,0x63,0x80,0x07,0x02,
0x03,0x26,0xc1,0x00,0x9b,0x55,0x89,0x01,0x13,0x85,0x04,0x00,0xef,0xf0,0x5f,0xca,
0x63,0x06,0x05,0x00,0xb7,0x07,0x40,0x00,0x6f,0xf0,0x5f,0xf9,0x03,0x26,0xc1,0x00,
0x9b,0x55,0x09,0x01,0x93,0xf5,0xf5,0x0f,0x13,0x85,0x04,0x00,0xef,0xf0,0x5f,0xc8,
0xe3,0x12,0x05,0xfe,0x03,0x26,0xc1,0x00,0x9b,0x55,0x89,0x00,0x93,0xf5,0xf5,0x0f,
0x13,0x85,0x04,0x00,0xef,0xf0,0xdf,0xc6,0x63,0x06,0x05,0x00,0xb7,0x07,0x50,0x00,
0x6f,0xf0,0xdf,0xf5,0x03,0x26,0xc1,0x00,0x93,0x75,0xf9,0x0f,0x13,0x85,0x04,0x00,
0xef,0xf0,0x1f,0xc5,0x63,0x08,0x05,0x02,0xb7,0x07,0x60,0x00,0x6f,0xf0,0x1f,0xf4,
0xb3,0x87,0x9a,0x01,0x83,0xc5,0x07,0x00,0x13,0x85,0x04,0x00,0x93,0x8c,0x1c,0x00,
0xef,0xf0,0x1f,0xc3,0x93,0x07,0x05,0x00,0x63,0x08,0x05,0x00,0x37,0x05,0x70,0x00,
0x6f,0xf0,0xdf,0xf1,0x93,0x0c,0x00,0x00,0x9b,0x87,0x0c,0x00,0x03,0x26,0xc1,0x00,
0xe3,0xe8,0x67,0xfd,0x93,0x05,0x06,0x00,0x13,0x85,0x04,0x00,0xef,0xf0,0x5f,0xc5,
0x93,0x07,0x05,0x00,0x63,0x06,0x05,0x00,0x37,0x05,0x80,0x00,0x6f,0xf0,0x1f,0xef,
0x23,0xac,0x04,0x00,0x93,0x85,0x0b,0x00,0x13,0x85,0x04,0x00,0xef,0xf0,0xdf,0xc7,
0x93,0x07,0x05,0x00,0x63,0x10,0x05,0x02,0x93,0x17,0x0b,0x02,0x93,0xd7,0x07,0x02,
0xb3,0x8a,0xfa,0x00,0x3b,0x09,0x69,0x01,0xbb,0x89,0x69,0x41,0x93,0x07,0x00,0x00,
0x6f,0xf0,0x1f,0xe9,0x37,0x05,0x90,0x00,0x6f,0xf0,0x5f,0xeb,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,
0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,0x09,0x53,0x67,0x08,0x00,0x00,0x00,0x00,

View File

@ -0,0 +1,349 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "../../../../src/flash/nor/spi.h"
/* Register offsets */
#define NUSPI_REG_SCKDIV (0x00)
#define NUSPI_REG_SCKMODE (0x04)
#define NUSPI_REG_SCKSAMPLE (0x08)
#define NUSPI_REG_FORCE (0x0C)
#define NUSPI_REG_CSID (0x10)
#define NUSPI_REG_CSDEF (0x14)
#define NUSPI_REG_CSMODE (0x18)
#define NUSPI_REG_VERSION (0x1C)
#define NUSPI_REG_DCSSCK (0x28)
#define NUSPI_REG_DSCKCS (0x2a)
#define NUSPI_REG_DINTERCS (0x2c)
#define NUSPI_REG_DINTERXFR (0x2e)
#define NUSPI_REG_FMT (0x40)
#define NUSPI_REG_TXDATA (0x48)
#define NUSPI_REG_RXDATA (0x4C)
#define NUSPI_REG_TXMARK (0x50)
#define NUSPI_REG_RXMARK (0x54)
#define NUSPI_REG_FCTRL (0x60)
#define NUSPI_REG_FFMT (0x64)
#define NUSPI_REG_IE (0x70)
#define NUSPI_REG_IP (0x74)
#define NUSPI_REG_FFMT1 (0x78)
#define NUSPI_REG_STATUS (0x7C)
#define NUSPI_REG_RXEDGE (0x80)
#define NUSPI_REG_CR (0x84)
/* Fields */
#define NUSPI_SCK_POL (0x1)
#define NUSPI_SCK_PHA (0x2)
#define NUSPI_FMT_PROTO(x) ((x) & 0x3)
#define NUSPI_FMT_ENDIAN(x) (((x) & 0x1) << 2)
#define NUSPI_FMT_DIR(x) (((x) & 0x1) << 3)
#define NUSPI_FMT_LEN(x) (((x) & 0xf) << 16)//TODO:
/* TXMARK register */
#define NUSPI_TXWM(x) ((x) & 0xFFFF)//TODO:
/* RXMARK register */
#define NUSPI_RXWM(x) ((x) & 0xFFFF)//TODO:
#define NUSPI_IP_TXWM (0x1)
#define NUSPI_IP_RXWM (0x2)
#define NUSPI_FCTRL_EN (0x1)
#define NUSPI_INSN_CMD_EN (0x1)
#define NUSPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1)
#define NUSPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4)
#define NUSPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8)
#define NUSPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10)
#define NUSPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12)
#define NUSPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16)
#define NUSPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24)
#define NUSPI_STAT_BUSY (0x1 << 0)
#define NUSPI_STAT_TXFULL (0x1 << 4)
#define NUSPI_STAT_RXEMPTY (0x1 << 5)
/* Values */
#define SPIFLASH_3BYTE_FAST_READ (0x03)
#define SPIFLASH_4BYTE_FAST_READ (0x13)
#define SPIFLASH_ENTER_4BYTE (0xB7)
#define SPIFLASH_EXIT_4BYTE (0xE9)
#define SPIFLASH_ENABLE_RESET (0x66)
#define SPIFLASH_RESET_DEVICE (0x99)
#define NUSPI_CSMODE_AUTO (0)
#define NUSPI_CSMODE_HOLD (2)
#define NUSPI_CSMODE_OFF (3)
#define NUSPI_DIR_RX (0)
#define NUSPI_DIR_TX (1)
#define NUSPI_PROTO_S (0)
#define NUSPI_PROTO_D (1)
#define NUSPI_PROTO_Q (2)
#define NUSPI_ENDIAN_MSB (0)
#define NUSPI_ENDIAN_LSB (1)
/* Timeouts we use, in number of status checks. */
#define TIMEOUT (2000)
#define NUSPI_FLAGS_32B_DAT (1 << 0)
/* #define DEBUG to make the return error codes provide enough information to
* reconstruct the stack from where the error occurred. This is not enabled
* usually to reduce the program size. */
#define ERROR_STACK(x) (x)
#define ERROR_NUSPI_TXWM_WAIT (0x10)
#define ERROR_NUSPI_TX (0x100)
#define ERROR_NUSPI_RX (0x1000)
#define ERROR_NUSPI_WIP (0x50000)
#define ERROR_OK (0)
typedef struct
{
uint32_t info;
uint32_t flags;
} nuspi_info_t;
static uint32_t nuspi_read_reg(volatile uint32_t *ctrl_base, uint32_t address);
static int nuspi_txwm_wait(volatile uint32_t *ctrl_base, nuspi_info_t* nuspi_info);
static int nuspi_wip(volatile uint32_t *ctrl_base, nuspi_info_t* nuspi_info);
static int nuspi_write_buffer(volatile uint32_t *ctrl_base,
const uint8_t *buffer, uint32_t offset, uint32_t len,
nuspi_info_t* nuspi_info);
/* Can set bits 3:0 in result. */
/* flash_info contains:
* bits 7:0 -- pprog_cmd
* bit 8 -- 0 means send 3 bytes after pprog_cmd, 1 means send 4 bytes
* after pprog_cmd
*/
int flash_nuspi(volatile uint32_t *ctrl_base, uint32_t page_size,
const uint8_t *buffer, uint32_t offset, uint32_t count,
uint32_t flash_info)
{
int result;
nuspi_info_t nuspi_info = {0};
nuspi_info.info = flash_info;
if(nuspi_read_reg(ctrl_base, NUSPI_REG_VERSION) >= 0x00010100)
nuspi_info.flags |= NUSPI_FLAGS_32B_DAT;
result = nuspi_txwm_wait(ctrl_base, &nuspi_info);
if (result != ERROR_OK)
return result | ERROR_STACK(0x1);
/* poll WIP */
result = nuspi_wip(ctrl_base, &nuspi_info);
if (result != ERROR_OK) {
result |= ERROR_STACK(0x2);
goto err;
}
/* Assume page_size is a power of two so we don't need the modulus code. */
uint32_t page_offset = offset & (page_size - 1);
/* central part, aligned words */
while (count > 0) {
uint32_t cur_count;
/* clip block at page boundary */
if (page_offset + count > page_size)
cur_count = page_size - page_offset;
else
cur_count = count;
result = nuspi_write_buffer(ctrl_base, buffer, offset, cur_count, &nuspi_info);
if (result != ERROR_OK) {
result |= ERROR_STACK(0x3);
goto err;
}
page_offset = 0;
buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
err:
return result;
}
static uint32_t nuspi_read_reg(volatile uint32_t *ctrl_base, uint32_t address)
{
return ctrl_base[address / 4];
}
static void nuspi_write_reg(volatile uint32_t *ctrl_base, uint32_t address, uint32_t value)
{
ctrl_base[address / 4] = value;
}
/* Can set bits 7:4 in result. */
static int nuspi_txwm_wait(volatile uint32_t *ctrl_base, nuspi_info_t* nuspi_info)
{
unsigned timeout = TIMEOUT;
if (nuspi_info->flags & NUSPI_FLAGS_32B_DAT) {
while (timeout--) {
uint32_t status = nuspi_read_reg(ctrl_base, NUSPI_REG_STATUS);
if (0 == (status & NUSPI_STAT_BUSY))
return ERROR_OK;
}
} else {
while (timeout--) {
uint32_t ip = nuspi_read_reg(ctrl_base, NUSPI_REG_IP);
if (ip & NUSPI_IP_TXWM)
return ERROR_OK;
}
}
return ERROR_NUSPI_TXWM_WAIT;
}
static void nuspi_set_dir(volatile uint32_t *ctrl_base, bool dir)
{
uint32_t fmt = nuspi_read_reg(ctrl_base, NUSPI_REG_FMT);
nuspi_write_reg(ctrl_base, NUSPI_REG_FMT,
(fmt & ~(NUSPI_FMT_DIR(0xFFFFFFFF))) | NUSPI_FMT_DIR(dir));
}
/* Can set bits 11:8 in result. */
static int nuspi_tx(volatile uint32_t *ctrl_base, uint8_t in, uint32_t flags)
{
unsigned timeout = TIMEOUT;
if (flags & NUSPI_FLAGS_32B_DAT) {
while (timeout--) {
if (!(nuspi_read_reg(ctrl_base, NUSPI_REG_STATUS) & NUSPI_STAT_TXFULL)) {
nuspi_write_reg(ctrl_base, NUSPI_REG_TXDATA, in);
return ERROR_OK;
}
}
} else {
while (timeout--) {
uint32_t txfifo = nuspi_read_reg(ctrl_base, NUSPI_REG_TXDATA);
if (!(txfifo >> 31)) {
nuspi_write_reg(ctrl_base, NUSPI_REG_TXDATA, in);
return ERROR_OK;
}
}
}
return ERROR_NUSPI_TX;
}
/* Can set bits 15:12 in result. */
static int nuspi_rx(volatile uint32_t *ctrl_base, uint8_t *out, uint32_t flags)
{
unsigned timeout = TIMEOUT;
if (flags & NUSPI_FLAGS_32B_DAT) {
while (timeout--) {
if (!(nuspi_read_reg(ctrl_base, NUSPI_REG_STATUS) & NUSPI_STAT_RXEMPTY)) {
uint32_t value = nuspi_read_reg(ctrl_base, NUSPI_REG_RXDATA);
if (out)
*out = value & 0xff;
return ERROR_OK;
}
}
} else {
while (timeout--) {
uint32_t value = nuspi_read_reg(ctrl_base, NUSPI_REG_RXDATA);
if (!(value >> 31)) {
if (out)
*out = value & 0xff;
return ERROR_OK;
}
}
}
return ERROR_NUSPI_RX;
}
/* Can set bits 19:16 in result. */
static int nuspi_wip(volatile uint32_t *ctrl_base, nuspi_info_t* nuspi_info)
{
nuspi_set_dir(ctrl_base, NUSPI_DIR_RX);
nuspi_write_reg(ctrl_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_HOLD);
int result = nuspi_tx(ctrl_base, SPIFLASH_READ_STATUS, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x10000);
result = nuspi_rx(ctrl_base, NULL, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x20000);
unsigned timeout = TIMEOUT;
while (timeout--) {
result = nuspi_tx(ctrl_base, 0, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x30000);
uint8_t rx;
result = nuspi_rx(ctrl_base, &rx, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x40000);
if ((rx & SPIFLASH_BSY_BIT) == 0) {
nuspi_write_reg(ctrl_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_AUTO);
nuspi_set_dir(ctrl_base, NUSPI_DIR_TX);
return ERROR_OK;
}
}
return ERROR_NUSPI_WIP;
}
/* Can set bits 23:20 in result. */
static int nuspi_write_buffer(volatile uint32_t *ctrl_base,
const uint8_t *buffer, uint32_t offset, uint32_t len,
nuspi_info_t* nuspi_info)
{
int result = nuspi_tx(ctrl_base, SPIFLASH_WRITE_ENABLE, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x100000);
result = nuspi_txwm_wait(ctrl_base, nuspi_info);
if (result != ERROR_OK)
return result | ERROR_STACK(0x200000);
nuspi_write_reg(ctrl_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_HOLD);
result = nuspi_tx(ctrl_base, nuspi_info->info & 0xff, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x300000);
if (nuspi_info->info & 0x100) {
result = nuspi_tx(ctrl_base, offset >> 24, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x400000);
}
result = nuspi_tx(ctrl_base, offset >> 16, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x400000);
result = nuspi_tx(ctrl_base, offset >> 8, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x500000);
result = nuspi_tx(ctrl_base, offset, nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x600000);
for (unsigned i = 0; i < len; i++) {
result = nuspi_tx(ctrl_base, buffer[i], nuspi_info->flags);
if (result != ERROR_OK)
return result | ERROR_STACK(0x700000);
}
result = nuspi_txwm_wait(ctrl_base, nuspi_info);
if (result != ERROR_OK)
return result | ERROR_STACK(0x800000);
nuspi_write_reg(ctrl_base, NUSPI_REG_CSMODE, NUSPI_CSMODE_AUTO);
result = nuspi_wip(ctrl_base, nuspi_info);
if (result != ERROR_OK)
return result | ERROR_STACK(0x900000);
return ERROR_OK;
}

View File

@ -0,0 +1,22 @@
#if __riscv_xlen == 64
# define LREG ld
# define SREG sd
# define REGBYTES 8
#else
# define LREG lw
# define SREG sw
# define REGBYTES 4
#endif
.section .text.entry
.global _start
_start:
lla sp, stack_end
jal flash_nuspi
ebreak
.section .data
.balign REGBYTES
stack:
.fill 32, REGBYTES, 0x8675309
stack_end:

View File

@ -25,6 +25,8 @@ NOR_DRIVERS = \
%D%/cc3220sf.c \
%D%/cc26xx.c \
%D%/cfi.c \
%D%/cm32m4xxr.c \
%D%/custom.c \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
%D%/em357.c \
@ -50,6 +52,7 @@ NOR_DRIVERS = \
%D%/npcx.c \
%D%/nrf5.c \
%D%/numicro.c \
%D%/nuspi.c \
%D%/ocl.c \
%D%/pic32mx.c \
%D%/psoc4.c \

781
src/flash/nor/cm32m4xxr.c Normal file
View File

@ -0,0 +1,781 @@
/***************************************************************************
*
* 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 2 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/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
/* CM32M4XXR register locations */
#define FLASH_REG_BASE (0x40000000 + 0x18000 + 0xA000)
#define FLASH_BASE (0x08000000)
#define FLASH_PAGE_SIZE (2048)
#define FLASH_TOTAL_KB (512)
#define FLASH_PG_UNIT (4)
#define FMC_AC 0x00
#define FMC_KEY 0x04
#define FMC_OPTKEY 0x08
#define FMC_STS 0x0C
#define FMC_CTRL 0x10
#define FMC_ADD 0x14
#define FMC_OB 0x1C
#define FMC_WRP 0X20
#define FMC_ECC 0x24
#define FMC_CAH 0x30
/* option byte location */
/****************** Bit definition for FLASH_STS register *******************/
#define FLASH_STS_BUSY_Pos (0U)
#define FLASH_STS_BUSY_Msk (0x1UL << FLASH_STS_BUSY_Pos)
#define FLASH_STS_BUSY FLASH_STS_BUSY_Msk /*!< Busy */
#define FLASH_STS_PGERR_Pos (2U)
#define FLASH_STS_PGERR_Msk (0x1UL << FLASH_STS_PGERR_Pos)
#define FLASH_STS_PGERR FLASH_STS_PGERR_Msk /*!< Programming Error */
#define FLASH_STS_PVERR_Pos (3U)
#define FLASH_STS_PVERR_Msk (0x1UL << FLASH_STS_PVERR_Pos)
#define FLASH_STS_PVERR FLASH_STS_PVERR_Msk /*!< Programming Verify ERROR after program */
#define FLASH_STS_WRPEER_Pos (4U)
#define FLASH_STS_WRPEER_Msk (0x1UL << FLASH_STS_WRPEER_Pos)
#define FLASH_STS_WRPEER FLASH_STS_WRPEER_Msk /*!< Write Protection Error */
#define FLASH_STS_EOP_Pos (5U)
#define FLASH_STS_EOP_Msk (0x1UL << FLASH_STS_EOP_Pos)
#define FLASH_STS_EOP FLASH_STS_EOP_Msk /*!< End of operation */
#define FLASH_STS_EVERR_Pos (6U)
#define FLASH_STS_EVERR_Msk (0x1UL << FLASH_STS_EVERR_Pos)
#define FLASH_STS_EVERR FLASH_STS_EVERR_Msk /*!< Erase Verify ERROR after page erase */
#define FLASH_STS_ECCERR_Pos (7U)
#define FLASH_STS_ECCERR_Msk (0x1UL << FLASH_STS_ECCERR_Pos)
#define FLASH_STS_ECCERR FLASH_STS_ECCERR_Msk /*!< ECC ERROR when Flash Reading */
/****************** Bit definition for FLASH_CTRL register ******************/
#define FLASH_CTRL_PG_Pos (0U)
#define FLASH_CTRL_PG_Msk (0x1UL << FLASH_CTRL_PG_Pos)
#define FLASH_CTRL_PG FLASH_CTRL_PG_Msk /*!< Programming */
#define FLASH_CTRL_PER_Pos (1U)
#define FLASH_CTRL_PER_Msk (0x1UL << FLASH_CTRL_PER_Pos)
#define FLASH_CTRL_PER FLASH_CTRL_PER_Msk /*!< Page Erase */
#define FLASH_CTRL_MER_Pos (2U)
#define FLASH_CTRL_MER_Msk (0x1UL << FLASH_CTRL_MER_Pos)
#define FLASH_CTRL_MER FLASH_CTRL_MER_Msk /*!< Mass Erase */
#define FLASH_CTRL_OPTPG_Pos (4U)
#define FLASH_CTRL_OPTPG_Msk (0x1UL << FLASH_CTRL_OPTPG_Pos)
#define FLASH_CTRL_OPTPG FLASH_CTRL_OPTPG_Msk /*!< Option Byte Programming */
#define FLASH_CTRL_OPTER_Pos (5U)
#define FLASH_CTRL_OPTER_Msk (0x1UL << FLASH_CTRL_OPTER_Pos)
#define FLASH_CTRL_OPTER FLASH_CTRL_OPTER_Msk /*!< Option Byte Erase */
#define FLASH_CTRL_START_Pos (6U)
#define FLASH_CTRL_START_Msk (0x1UL << FLASH_CTRL_START_Pos)
#define FLASH_CTRL_START FLASH_CTRL_START_Msk /*!< Start */
#define FLASH_CTRL_LOCK_Pos (7U)
#define FLASH_CTRL_LOCK_Msk (0x1UL << FLASH_CTRL_LOCK_Pos)
#define FLASH_CTRL_LOCK FLASH_CTRL_LOCK_Msk /*!< Lock */
#define FLASH_CTRL_SMPSEL_Pos (8U)
#define FLASH_CTRL_SMPSEL_Msk (0x1UL << FLASH_CTRL_SMPSEL_Pos)
#define FLASH_CTRL_SMPSEL FLASH_CTRL_SMPSEL_Msk /*!< Flash Program Option Select */
#define FLASH_CTRL_OPTWE_Pos (9U)
#define FLASH_CTRL_OPTWE_Msk (0x1UL << FLASH_CTRL_OPTWE_Pos)
#define FLASH_CTRL_OPTWE FLASH_CTRL_OPTWE_Msk /*!< Option Bytes Write Enable */
#define FLASH_CTRL_ERRITE_Pos (10U)
#define FLASH_CTRL_ERRITE_Msk (0x1UL << FLASH_CTRL_ERRITE_Pos)
#define FLASH_CTRL_ERRITE FLASH_CTRL_ERRITE_Msk /*!< Error Interrupt Enable */
#define FLASH_CTRL_FERRITE_Pos (11U)
#define FLASH_CTRL_FERRITE_Msk (0x1UL << FLASH_CTRL_FERRITE_Pos)
#define FLASH_CTRL_FERRITE FLASH_CTRL_FERRITE_Msk /*!< EVERR PVERR Error Interrupt Enable */
#define FLASH_CTRL_EOPITE_Pos (12U)
#define FLASH_CTRL_EOPITE_Msk (0x1UL << FLASH_CTRL_EOPITE_Pos)
#define FLASH_CTRL_EOPITE FLASH_CTRL_EOPITE_Msk /*!< End of operation Interrupt Enable */
#define FLASH_CTRL_ECCERRITE_Pos (13U)
#define FLASH_CTRL_ECCERRITE_Msk (0x1UL << FLASH_CTRL_ECCERRITE_Pos)
#define FLASH_CTRL_ECCERRITE FLASH_CTRL_ECCERRITE_Msk /*!< ECC Error Interrupt Enable */
#define FLASH_FLAG_BUSY ((uint32_t) 0x00000001) /*!< FLASH Busy flag */
#define FLASH_FLAG_PGERR ((uint32_t) 0x00000004) /*!< FLASH Program error flag */
#define FLASH_FLAG_PVERR ((uint32_t) 0x00000008) /*!< FLASH Program Verify ERROR flag after program */
#define FLASH_FLAG_WRPERR ((uint32_t) 0x00000010) /*!< FLASH Write protected error flag */
#define FLASH_FLAG_EOP ((uint32_t) 0x00000020) /*!< FLASH End of Operation flag */
#define FLASH_FLAG_EVERR ((uint32_t) 0x00000040) /*!< FLASH Erase Verify ERROR flag after page erase */
#define FLASH_FLAG_OBERR ((uint32_t) 0x00000001) /*!< FLASH Option Byte error flag */
#define FLASH_STS_CLRFLAG (FLASH_FLAG_PGERR | FLASH_FLAG_PVERR | FLASH_FLAG_WRPERR | FLASH_FLAG_EOP | FLASH_FLAG_EVERR)
/* FMC_OBSTAT bit definitions (reading) */
/* Flash Control Register bits */
#define CR_Set_PG FLASH_CTRL_PG
#define CR_Reset_PG (~FLASH_CTRL_PG)
#define CR_Set_PER FLASH_CTRL_PER
#define CR_Reset_PER (~FLASH_CTRL_PER)
#define CR_Set_MER FLASH_CTRL_MER
#define CR_Reset_MER (~FLASH_CTRL_MER)
#define CR_Set_OPTPG FLASH_CTRL_OPTPG
#define CR_Reset_OPTPG (~FLASH_CTRL_OPTPG)
#define CR_Set_OPTER FLASH_CTRL_OPTER
#define CR_Reset_OPTER (~FLASH_CTRL_OPTER)
#define CR_Set_START FLASH_CTRL_START
#define CR_Set_LOCK FLASH_CTRL_LOCK
#define CR_Reset_OPTWE (~FLASH_CTRL_OPTWE)
/* register unlock keys */
#define UNLOCK_KEY0 0x45670123
#define UNLOCK_KEY1 0xCDEF89AB
/* timeout values */
#define FLASH_WRITE_TIMEOUT 0x00002000
#define FLASH_ERASE_TIMEOUT 0x000B0000
struct cm32m4xxr_options {
uint16_t RDP;
uint16_t user_options;
uint16_t user_data;
uint16_t protection[4];
};
struct cm32m4xxr_flash_bank {
struct cm32m4xxr_options option_bytes;
int ppage_size;
int probed;
bool has_dual_banks;
/* used to access flash bank cm32m4xxr */
uint32_t register_base;
uint16_t default_rdp;
int user_data_offset;
int option_offset;
uint32_t user_bank_size;
};
static int cm32m4xxr_mass_erase(struct flash_bank *bank);
static int get_cm32m4xxr_info(struct flash_bank *bank, struct command_invocation *cmd);
static int cm32m4xxr_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count);
/* flash bank cm32m4xxr <base> <size> 0 0 <target#>
*/
FLASH_BANK_COMMAND_HANDLER(cm32m4xxr_flash_bank_command)
{
struct cm32m4xxr_flash_bank *cm32m4xxr_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
cm32m4xxr_info = malloc(sizeof(struct cm32m4xxr_flash_bank));
/* The flash write must be aligned to a word (4-bytes) boundary.
* Ask the flash infrastructure to ensure required alignment */
bank->write_start_alignment = bank->write_end_alignment = 4;
bank->driver_priv = cm32m4xxr_info;
cm32m4xxr_info->probed = 0;
cm32m4xxr_info->has_dual_banks = false;
cm32m4xxr_info->register_base = FLASH_REG_BASE;
cm32m4xxr_info->user_bank_size = bank->size;
return ERROR_OK;
}
static inline int cm32m4xxr_get_flash_reg(struct flash_bank *bank, uint32_t reg)
{
struct cm32m4xxr_flash_bank *cm32m4xxr_info = bank->driver_priv;
return reg + cm32m4xxr_info->register_base;
}
static inline int cm32m4xxr_get_flash_status(struct flash_bank *bank, uint32_t *status)
{
struct target *target = bank->target;
return target_read_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS), status);
}
static int cm32m4xxr_wait_status_busy(struct flash_bank *bank, int timeout)
{
struct target *target = bank->target;
uint32_t status;
int retval = ERROR_OK;
/* wait for busy to clear */
for (;;) {
retval = cm32m4xxr_get_flash_status(bank, &status);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%" PRIx32 "", status);
if ((status & FLASH_FLAG_BUSY) == 0)
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
if (status & FLASH_FLAG_WRPERR) {
LOG_ERROR("cm32m4xxr device protected");
retval = ERROR_FAIL;
}
if (status & FLASH_FLAG_PGERR) {
LOG_ERROR("cm32m4xxr device programming failed");
retval = ERROR_FAIL;
}
/* Clear but report errors */
if (status & (FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR)) {
/* If this operation fails, we ignore it and report the original
* retval
*/
target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS),
FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);
}
return retval;
}
static int cm32m4xxr_erase(struct flash_bank *bank, unsigned first, unsigned last)
{
struct target *target = bank->target;
// uint32_t optiondata;
// uint32_t obstat;
uint32_t ctrl_reg;
// struct cm32m4xxr_flash_bank *cm32m4xxr_info = NULL;
// cm32m4xxr_info = bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
//todo: write protect
if ((first == 0) && (last == (bank->num_sectors - 1)))
return cm32m4xxr_mass_erase(bank);
/* unlock flash registers */
int retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1);
if (retval != ERROR_OK)
return retval;
retval = cm32m4xxr_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
return retval;
for (unsigned i = first; i <= last; i++) {
//clear flash pending flags
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS), FLASH_STS_CLRFLAG);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_PER);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_ADD),
bank->base + bank->sectors[i].offset);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target,
cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_PER | CR_Set_START);
if (retval != ERROR_OK)
return retval;
retval = cm32m4xxr_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
return retval;
bank->sectors[i].is_erased = 1;
/* Disable the PER Bit */
retval = target_read_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), &ctrl_reg);
if (retval != ERROR_OK)
return retval;
ctrl_reg &= CR_Reset_PER;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), ctrl_reg);
if (retval != ERROR_OK)
return retval;
}
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_LOCK);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int cm32m4xxr_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct cm32m4xxr_flash_bank *cm32m4xxr_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 16384;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[5];
int retval = ERROR_OK;
static const uint8_t cm32m4xxr_flash_write_code[] = {
0x03,0x28,0x06,0x00,0x63,0x05,0x08,0x04,0x5c,0x42,0xe3,0x8b,0x07,0xff,0x05,0x48,
0x23,0x28,0x05,0x01,0x03,0xa8,0x07,0x00,0x23,0x20,0x07,0x01,0x91,0x07,0x11,0x07,
0x03,0x2e,0xc5,0x00,0x93,0x78,0x1e,0x00,0x05,0x48,0xe3,0x0b,0x18,0xff,0x03,0x28,
0x05,0x01,0x13,0x78,0xe8,0xff,0x23,0x28,0x05,0x01,0x63,0xc4,0xd7,0x00,0xb2,0x87,
0xa1,0x07,0x5c,0xc2,0xfd,0x15,0x81,0xc5,0x65,0xbf,0x01,0x45,0x48,0xc2,0x72,0x85,
0x02,0x90,
};
/* flash write code */
if (target_alloc_working_area(target, sizeof(cm32m4xxr_flash_write_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address,
sizeof(cm32m4xxr_flash_write_code), cm32m4xxr_flash_write_code);
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
buffer_size /= 2;
buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
if (buffer_size <= 256) {
/* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
target_free_working_area(target, write_algorithm);
LOG_WARNING("no large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}
init_reg_param(&reg_params[0], "a0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */
init_reg_param(&reg_params[2], "a2", 32, PARAM_OUT); /* buffer start */
init_reg_param(&reg_params[3], "a3", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[4], "a4", 32, PARAM_IN_OUT); /* target address */
uint32_t wp_addr = source->address;
uint32_t rp_addr = source->address + 4;
uint32_t fifo_start_addr = source->address + 8;
uint32_t fifo_end_addr = source->address + source->size;
uint32_t wp = fifo_start_addr;
uint32_t rp = fifo_start_addr;
uint32_t thisrun_bytes = fifo_end_addr-fifo_start_addr - 4; /* (2:block size) */
retval = target_write_u32(target, rp_addr, rp);
if (retval != ERROR_OK)
return retval;
while (count > 0) {
retval = target_read_u32(target, rp_addr, &rp);
if (retval != ERROR_OK) {
LOG_ERROR("failed to get read pointer");
break;
}
if (wp != rp) {
LOG_ERROR("Failed to write flash ;; rp = 0x%x ;;; wp = 0x%x", rp, wp);
break;
}
wp = fifo_start_addr;
rp = fifo_start_addr;
retval = target_write_u32(target, rp_addr, rp);
if (retval != ERROR_OK)
break;
/* Limit to the amount of data we actually want to write */
if (thisrun_bytes > count * 4)
thisrun_bytes = count * 4;
/* Write data to fifo */
retval = target_write_buffer(target, wp, thisrun_bytes, buffer);
if (retval != ERROR_OK)
break;
/* Update counters and wrap write pointer */
buffer += thisrun_bytes;
count -= thisrun_bytes / 4;
rp = fifo_start_addr;
wp = fifo_start_addr+thisrun_bytes;
/* Store updated write pointer to target */
retval = target_write_u32(target, wp_addr, wp);
if (retval != ERROR_OK)
break;
retval = target_write_u32(target, rp_addr, rp);
if (retval != ERROR_OK)
return retval;
buf_set_u32(reg_params[0].value, 0, 32, cm32m4xxr_info->register_base);
buf_set_u32(reg_params[1].value, 0, 32, thisrun_bytes/4);
buf_set_u32(reg_params[2].value, 0, 32, source->address);
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[4].value, 0, 32, address);
retval = target_run_algorithm(target, 0, NULL, 5, reg_params,
write_algorithm->address, 0,
10000, NULL);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d",
write_algorithm->address, retval);
return retval;
}
address += thisrun_bytes;
}
if (retval == ERROR_FLASH_OPERATION_FAILED) {
LOG_ERROR("flash write failed at address 0x%"PRIx32,
buf_get_u32(reg_params[4].value, 0, 32));
if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_FLAG_PGERR) {
LOG_ERROR("flash memory not erased before writing");
/* Clear but report errors */
target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS), FLASH_FLAG_PGERR);
}
if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_FLAG_WRPERR) {
LOG_ERROR("flash memory write protected");
/* Clear but report errors */
target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS), FLASH_FLAG_WRPERR);
}
}
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
return retval;
}
static int cm32m4xxr_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
uint8_t *new_buffer = NULL;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (offset & 0x1) {
LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
/* If there's an odd number of bytes, the data has to be padded. Duplicate
* the buffer and use the normal code path with a single block write since
* it's probably cheaper than to special case the last odd write using
* discrete accesses. */
if (count % 4) {
new_buffer = malloc(count + 3);
if (new_buffer == NULL) {
LOG_ERROR("odd number of bytes to write and no memory for padding buffer");
return ERROR_FAIL;
}
LOG_INFO("odd number of bytes to write, padding with 0xff");
buffer = memcpy(new_buffer, buffer, count);
new_buffer[count++] = 0xff;
new_buffer[count++] = 0xff;
new_buffer[count++] = 0xff;
}
uint32_t words_remaining = (count + 3) / 4;
int retval, retval2;
/* unlock flash registers */
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0);
if (retval != ERROR_OK)
goto cleanup;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1);
if (retval != ERROR_OK)
goto cleanup;
//clear flash pending flags
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_STS), FLASH_STS_CLRFLAG);
if (retval != ERROR_OK)
goto cleanup;
/* try using a block write */
retval = cm32m4xxr_write_block(bank, buffer, offset, words_remaining);
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* if block write failed (no sufficient working area),
* we use normal (slow) single halfword accesses */
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
while (words_remaining > 0) {
uint32_t value;
memcpy(&value, buffer, sizeof(uint32_t));
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_PG);
if (retval != ERROR_OK)
goto cleanup;
retval = target_write_u32(target, bank->base + offset, value);
if (retval != ERROR_OK)
goto reset_pg_and_lock;
retval = cm32m4xxr_wait_status_busy(bank, 100);
if (retval != ERROR_OK)
goto reset_pg_and_lock;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), 0);
if (retval != ERROR_OK)
goto cleanup;
words_remaining--;
buffer += 4;
offset += 4;
}
}
reset_pg_and_lock:
retval2 = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_LOCK);
if (retval == ERROR_OK)
retval = retval2;
cleanup:
if (new_buffer)
free(new_buffer);
return retval;
}
static int cm32m4xxr_get_device_id(struct flash_bank *bank, uint32_t *device_id)
{
struct target *target = bank->target;
uint32_t device_id_register = 0xE0040000;
/* read cm32m4xxr device id register */
int retval = target_read_u32(target, device_id_register, device_id);
if (retval != ERROR_OK)
return retval;
return retval;
}
static int cm32m4xxr_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb)
{
*flash_size_in_kb = FLASH_TOTAL_KB;
return ERROR_OK;
}
static int cm32m4xxr_probe(struct flash_bank *bank)
{
struct cm32m4xxr_flash_bank *cm32m4xxr_info = bank->driver_priv;
int i;
uint16_t flash_size_in_kb;
uint16_t max_flash_size_in_kb;
uint32_t device_id;
int page_size;
uint32_t base_address = FLASH_BASE;
cm32m4xxr_info->probed = 0;
cm32m4xxr_info->register_base = FLASH_REG_BASE;
cm32m4xxr_info->user_data_offset = 10;
cm32m4xxr_info->option_offset = 0;
/* default factory protection level */
cm32m4xxr_info->default_rdp = 0x5AA5;
/* read cm32m4xxr device id register */
int retval = cm32m4xxr_get_device_id(bank, &device_id);
if (retval != ERROR_OK)
return retval;
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
page_size = FLASH_PAGE_SIZE;
cm32m4xxr_info->ppage_size = FLASH_PG_UNIT;
max_flash_size_in_kb = FLASH_TOTAL_KB;
/* get flash size from target. */
retval = cm32m4xxr_get_flash_size(bank, &flash_size_in_kb);
LOG_INFO("flash_size_in_kb = 0x%08" PRIx32 "", flash_size_in_kb);
/* failed reading flash size or flash size invalid, default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
LOG_WARNING("cm32m4xxr flash size failed, probe inaccurate - assuming %dk flash",
max_flash_size_in_kb);
flash_size_in_kb = max_flash_size_in_kb;
}
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have a invalid flash size register value */
if (cm32m4xxr_info->user_bank_size) {
LOG_INFO("ignoring flash probed value, using configured bank size");
flash_size_in_kb = cm32m4xxr_info->user_bank_size / 1024;
}
LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
/* calculate numbers of pages */
int num_pages = flash_size_in_kb * 1024 / page_size;
/* check that calculation result makes sense */
assert(num_pages > 0);
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = base_address;
bank->size = (num_pages * page_size);
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
for (i = 0; i < num_pages; i++) {
bank->sectors[i].offset = i * page_size;
bank->sectors[i].size = page_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
cm32m4xxr_info->probed = 1;
return ERROR_OK;
}
static int cm32m4xxr_auto_probe(struct flash_bank *bank)
{
struct cm32m4xxr_flash_bank *cm32m4xxr_info = bank->driver_priv;
if (cm32m4xxr_info->probed)
return ERROR_OK;
return cm32m4xxr_probe(bank);
}
static int get_cm32m4xxr_info(struct flash_bank *bank, struct command_invocation *cmd)
{
uint32_t dbgmcu_idcode;
/* read cm32m4xxr device id register */
int retval = cm32m4xxr_get_device_id(bank, &dbgmcu_idcode);
if (retval != ERROR_OK)
return retval;
command_print_sameline(cmd, "%s - Rev: %s\n", "CM32M4xxR", "1.0");
return ERROR_OK;
}
static int cm32m4xxr_mass_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* unlock option flash registers */
int retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1);
if (retval != ERROR_OK)
return retval;
/* mass erase flash memory */
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_MER);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL),
CR_Set_MER | CR_Set_START);
if (retval != ERROR_OK)
return retval;
retval = cm32m4xxr_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, cm32m4xxr_get_flash_reg(bank, FMC_CTRL), CR_Set_LOCK);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
COMMAND_HANDLER(cm32m4xxr_handle_mass_erase_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
retval = cm32m4xxr_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
for (unsigned i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD, "cm32m4xxr mass erase complete");
} else
command_print(CMD, "cm32m4xxr mass erase failed");
return retval;
}
static const struct command_registration cm32m4xxr_exec_command_handlers[] = {
{
.name = "mass_erase",
.handler = cm32m4xxr_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Erase entire flash device.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration cm32m4xxr_command_handlers[] = {
{
.name = "cm32m4xxr",
.mode = COMMAND_ANY,
.help = "cm32m4xxr flash command group",
.usage = "",
.chain = cm32m4xxr_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
const struct flash_driver cm32m4xxr_flash = {
.name = "cm32m4xxr",
.commands = cm32m4xxr_command_handlers,
.flash_bank_command = cm32m4xxr_flash_bank_command,
.erase = cm32m4xxr_erase,
.write = cm32m4xxr_write,
.read = default_flash_read,
.probe = cm32m4xxr_probe,
.auto_probe = cm32m4xxr_auto_probe,
.erase_check = default_flash_blank_check,
.info = get_cm32m4xxr_info,
.free_driver_priv = default_flash_free_driver_priv,
};

469
src/flash/nor/custom.c Normal file
View File

@ -0,0 +1,469 @@
/***************************************************************************
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
* Modified by Yanwen Wang <wangyanwen@nucleisys.com> based on fespi.c *
* *
* 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 2 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/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include "imp.h"
#include "spi.h"
#include <jtag/jtag.h>
#include <helper/time_support.h>
#include <target/algorithm.h>
#include "target/riscv/riscv.h"
#include <helper/configuration.h>
#define ERASE_CMD (1)
#define WRITE_CMD (2)
#define READ_CMD (3)
#define PROBE_CMD (4)
struct flash_bank_msg {
bool probed;
const struct flash_device *dev;
target_addr_t ctrl_base;
char *loader_path;
uint8_t cs;
uint8_t *buffer;
uint32_t param_0;
uint32_t param_1;
bool simulation;
uint32_t sectorsize;
};
static int custom_run_algorithm(struct flash_bank *bank)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
struct target *target = bank->target;
int retval = ERROR_OK;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
int xlen = riscv_xlen(target);
struct working_area *algorithm_wa = NULL;
struct working_area *data_wa = NULL;
uint8_t* bin = (uint8_t*)malloc(target->working_area_size);
size_t bin_size;
FILE* fd = fopen((char*)bank_msg->loader_path, "rb");
if (NULL == fd) {
fd = fopen(find_file(strrchr((char*)bank_msg->loader_path, '/')), "rb");
}
if (fd) {
fseek(fd, 0, SEEK_END);
bin_size = ftell(fd);
rewind(fd);
if (target->working_area_size < bin_size) {
LOG_ERROR("working_area_size less than loader_bin_size");
goto err;
}
if (1 != fread(bin, bin_size, 1, fd)) {
LOG_ERROR("read loader error");
goto err;
}
fclose(fd);
} else {
LOG_ERROR("Failed to open loader:%s ", bank_msg->loader_path);
goto err;
}
unsigned data_wa_size = 0;
if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) {
retval = target_write_buffer(target, algorithm_wa->address, bin_size, bin);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
target_free_working_area(target, algorithm_wa);
algorithm_wa = NULL;
} else if ((bank_msg->cs == WRITE_CMD) || (bank_msg->cs == READ_CMD)) {
data_wa_size = MIN(target->working_area_size - algorithm_wa->size, bank_msg->param_0);
while (1) {
if (target_alloc_working_area_try(target, data_wa_size, &data_wa) == ERROR_OK)
break;
data_wa_size = data_wa_size * 3 / 4;
}
}
} else {
LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size);
algorithm_wa = NULL;
}
if (algorithm_wa) {
uint32_t count = 0;
uint32_t offset = 0;
uint32_t first_addr = 0;
uint32_t end_addr = 0;
uint32_t cur_count = 0;
int algorithm_result = 0;
struct reg_param reg_params[5];
init_reg_param(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
init_reg_param(&reg_params[2], "a2", xlen, PARAM_OUT);
init_reg_param(&reg_params[3], "a3", xlen, PARAM_OUT);
init_reg_param(&reg_params[4], "a4", xlen, PARAM_OUT);
switch (bank_msg->cs)
{
case ERASE_CMD:
first_addr = bank_msg->param_0;
end_addr = bank_msg->param_1;
buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs);
buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base);
buf_set_u64(reg_params[2].value, 0, xlen, first_addr);
buf_set_u64(reg_params[3].value, 0, xlen, end_addr);
buf_set_u64(reg_params[4].value, 0, xlen, 0);
if (bank_msg->simulation) {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, 0x7FFFFFFF, NULL);
} else {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, (end_addr - first_addr) * 2, NULL);
}
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto err;
}
algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen);
if (algorithm_result != 0) {
LOG_ERROR("Algorithm returned error %d", algorithm_result);
LOG_ERROR("erase command error");
retval = ERROR_FAIL;
goto err;
}
break;
case WRITE_CMD:
count = bank_msg->param_0;
offset = bank_msg->param_1;
cur_count = 0;
while (count > 0) {
cur_count = MIN(count, data_wa_size);
buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs);
buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base);
buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address);
buf_set_u64(reg_params[3].value, 0, xlen, offset);
buf_set_u64(reg_params[4].value, 0, xlen, cur_count);
retval = target_write_buffer(target, data_wa->address, cur_count, bank_msg->buffer);
if (retval != ERROR_OK) {
LOG_DEBUG("Failed to write %d bytes to " TARGET_ADDR_FMT ": %d",
cur_count, data_wa->address, retval);
goto err;
}
if (bank_msg->simulation) {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, 0x7FFFFFFF, NULL);
} else {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, cur_count * 2, NULL);
}
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto err;
}
algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen);
if (algorithm_result != 0) {
LOG_ERROR("Algorithm returned error %d", algorithm_result);
LOG_ERROR("write command error");
retval = ERROR_FAIL;
goto err;
}
bank_msg->buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
break;
case READ_CMD:
count = bank_msg->param_0;
offset = bank_msg->param_1;
cur_count = 0;
while (count > 0) {
cur_count = MIN(count, data_wa_size);
buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs);
buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base);
buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address);
buf_set_u64(reg_params[3].value, 0, xlen, offset);
buf_set_u64(reg_params[4].value, 0, xlen, cur_count);
if (bank_msg->simulation) {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, 0x7FFFFFFF, NULL);
} else {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, cur_count * 2, NULL);
}
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto err;
}
algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen);
if (algorithm_result != 0) {
LOG_ERROR("Algorithm returned error %d", algorithm_result);
LOG_ERROR("read command error");
retval = ERROR_FAIL;
goto err;
}
retval = target_read_buffer(target, data_wa->address, cur_count, bank_msg->buffer);
if (retval != ERROR_OK) {
LOG_DEBUG("Failed to read %d bytes from " TARGET_ADDR_FMT ": %d",
cur_count, data_wa->address, retval);
goto err;
}
bank_msg->buffer += cur_count;
offset += cur_count;
count -= cur_count;
}
break;
case PROBE_CMD:
buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs);
buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base);
buf_set_u64(reg_params[2].value, 0, xlen, 0);
buf_set_u64(reg_params[3].value, 0, xlen, 0);
buf_set_u64(reg_params[4].value, 0, xlen, 0);
if (bank_msg->simulation) {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, 0x7FFFFFFF, NULL);
} else {
retval = target_run_algorithm(target, 0, NULL,
ARRAY_SIZE(reg_params), reg_params,
algorithm_wa->address, 0, 10000, NULL);
}
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d",
algorithm_wa->address, retval);
goto err;
}
algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen);
retval = algorithm_result;
break;
default:
break;
}
target_free_working_area(target, data_wa);
target_free_working_area(target, algorithm_wa);
}
err:
if (bin) {
free(bin);
}
if (algorithm_wa) {
target_free_working_area(target, data_wa);
target_free_working_area(target, algorithm_wa);
}
return retval;
}
FLASH_BANK_COMMAND_HANDLER(custom_flash_bank_command)
{
struct flash_bank_msg *bank_msg;
LOG_DEBUG("%s", __func__);
if (CMD_ARGC < 8) {
LOG_ERROR("Parameter error:");
LOG_ERROR("flash bank $FLASHNAME custom 0x20000000 0 0 0 $TARGETNAME 0x10014000 ~/work/riscv.bin [simulation] [sectorsize=]");
return ERROR_COMMAND_SYNTAX_ERROR;
}
bank_msg = malloc(sizeof(struct flash_bank_msg));
if (bank_msg == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
bank->driver_priv = bank_msg;
bank_msg->probed = false;
bank_msg->ctrl_base = 0;
bank_msg->loader_path = NULL;
bank_msg->cs = 0;
bank_msg->buffer = NULL;
bank_msg->param_0 = 0;
bank_msg->param_1 = 0;
COMMAND_PARSE_ADDRESS(CMD_ARGV[6], bank_msg->ctrl_base);
LOG_DEBUG("ASSUMING CUSTOM device at ctrl_base = " TARGET_ADDR_FMT,
bank_msg->ctrl_base);
bank_msg->loader_path = malloc(strlen(CMD_ARGV[7]));
strcpy((char*)bank_msg->loader_path, CMD_ARGV[7]);
for (char *p = bank_msg->loader_path; *p; p++) {
if (*p == '\\')
*p = '/';
}
bank_msg->simulation = false;
bank_msg->sectorsize = 0;
for (unsigned int i = 8; i < CMD_ARGC; i++) {
if(strcmp(CMD_ARGV[i], "simulation") == 0) {
bank_msg->simulation = true;
LOG_DEBUG("Custom Simulation Mode");
}
if(strncmp(CMD_ARGV[i], "sectorsize=", strlen("sectorsize=")) == 0) {
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i]+strlen("sectorsize="), bank_msg->sectorsize);
LOG_DEBUG("Custom flash sectorsize is %x", bank_msg->sectorsize);
}
}
return ERROR_OK;
}
static int custom_erase(struct flash_bank *bank, unsigned int first,
unsigned int last)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
bank_msg->cs = ERASE_CMD;
bank_msg->buffer = NULL;
bank_msg->param_0 = bank->sectors[first].offset;
bank_msg->param_1 = bank->sectors[last].offset + bank_msg->sectorsize;
return custom_run_algorithm(bank);
}
static int custom_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
bank_msg->cs = WRITE_CMD;
bank_msg->buffer = (uint8_t*)buffer;
bank_msg->param_0 = count;
bank_msg->param_1 = offset;
return custom_run_algorithm(bank);
}
static int custom_read(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
bank_msg->cs = READ_CMD;
bank_msg->buffer = buffer;
bank_msg->param_0 = count;
bank_msg->param_1 = offset;
return custom_run_algorithm(bank);
}
static int custom_probe(struct flash_bank *bank)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
uint32_t id = 0x12345678;
struct flash_sector *sectors;
if (bank_msg->probed)
free(bank->sectors);
bank_msg->probed = false;
bank_msg->dev = NULL;
for (const struct flash_device *p = flash_devices; p->name ; p++) {
if (p->device_id == id) {
bank_msg->dev = p;
break;
}
}
/* if no sectors, treat whole bank as single sector */
if (0 == bank_msg->sectorsize) {
bank_msg->sectorsize = bank_msg->dev->sectorsize ?
bank_msg->dev->sectorsize : bank->size;
}
/* create and fill sectors array */
bank->num_sectors = bank->size / bank_msg->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * bank_msg->sectorsize;
sectors[sector].size = bank_msg->sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
bank->sectors = sectors;
bank_msg->cs = PROBE_CMD;
bank_msg->buffer = NULL;
bank_msg->param_0 = 0;
bank_msg->param_1 = 0;
id = custom_run_algorithm(bank);
LOG_INFO("Found custom flash device (ID 0x%08" PRIx32 ")", id);
bank_msg->probed = true;
return ERROR_OK;
}
static int custom_info(struct flash_bank *bank, struct command_invocation *command)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
if (!(bank_msg->probed)) {
return ERROR_OK;
}
return ERROR_OK;
}
static int custom_auto_probe(struct flash_bank *bank)
{
struct flash_bank_msg *bank_msg = bank->driver_priv;
if (bank_msg->probed)
return ERROR_OK;
return custom_probe(bank);
}
static int custom_protect(struct flash_bank *bank, int set,
unsigned int first, unsigned int last)
{
for (unsigned int sector = first; sector <= last; sector++)
bank->sectors[sector].is_protected = set;
return ERROR_OK;
}
static int custom_protect_check(struct flash_bank *bank)
{
/* Nothing to do. Protection is only handled in SW. */
return ERROR_OK;
}
const struct flash_driver custom_flash = {
.name = "custom",
.flash_bank_command = custom_flash_bank_command,
.erase = custom_erase,
.protect = custom_protect,
.write = custom_write,
.read = custom_read,
.probe = custom_probe,
.auto_probe = custom_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = custom_protect_check,
.info = custom_info,
.free_driver_priv = default_flash_free_driver_priv
};

View File

@ -253,6 +253,8 @@ extern const struct flash_driver bluenrgx_flash;
extern const struct flash_driver cc26xx_flash;
extern const struct flash_driver cc3220sf_flash;
extern const struct flash_driver cfi_flash;
extern const struct flash_driver cm32m4xxr_flash;
extern const struct flash_driver custom_flash;
extern const struct flash_driver dsp5680xx_flash;
extern const struct flash_driver efm32_flash;
extern const struct flash_driver em357_flash;
@ -278,6 +280,7 @@ extern const struct flash_driver npcx_flash;
extern const struct flash_driver nrf51_flash;
extern const struct flash_driver nrf5_flash;
extern const struct flash_driver numicro_flash;
extern const struct flash_driver nuspi_flash;
extern const struct flash_driver ocl_flash;
extern const struct flash_driver pic32mx_flash;
extern const struct flash_driver psoc4_flash;

View File

@ -31,6 +31,8 @@ static const struct flash_driver * const flash_drivers[] = {
&cc3220sf_flash,
&cc26xx_flash,
&cfi_flash,
&cm32m4xxr_flash,
&custom_flash,
&dsp5680xx_flash,
&efm32_flash,
&em357_flash,
@ -56,6 +58,7 @@ static const struct flash_driver * const flash_drivers[] = {
&nrf5_flash,
&nrf51_flash,
&numicro_flash,
&nuspi_flash,
&ocl_flash,
&pic32mx_flash,
&psoc4_flash,

1168
src/flash/nor/nuspi.c Normal file

File diff suppressed because it is too large Load Diff