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:
parent
285f810ce3
commit
ef8184f193
|
@ -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
|
|
@ -0,0 +1,17 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x12340000;
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.entry)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
}
|
|
@ -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,
|
|
@ -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,
|
|
@ -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;
|
||||
}
|
|
@ -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:
|
|
@ -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 \
|
||||
|
|
|
@ -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(®_params[0], "a0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
|
||||
init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */
|
||||
init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */
|
||||
init_reg_param(®_params[3], "a3", 32, PARAM_OUT); /* buffer end */
|
||||
init_reg_param(®_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(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_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,
|
||||
};
|
|
@ -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(®_params[0], "a0", xlen, PARAM_IN_OUT);
|
||||
init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "a2", xlen, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "a3", xlen, PARAM_OUT);
|
||||
init_reg_param(®_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
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue