| From 49378b6c185691faf0db7a9aa03dba77ed46e733 Mon Sep 17 00:00:00 2001 |
| From: Wealian Liao <WHLIAO@nuvoton.com> |
| Date: Thu, 26 Nov 2020 10:25:09 +0800 |
| Subject: [PATCH] flash/nor: add support for Nuvoton NPCX series flash |
| |
| Added NPCX flash driver to support the Nuvoton NPCX series |
| microcontrollers. Add config file for NPCX series. |
| |
| Change-Id: Ia10b019a3521f59ad1e10ccdc56827ba30c3eac8 |
| Signed-off-by: Wealian Liao <WHLIAO@nuvoton.com> |
| Signed-off-by: Mulin Chao <mlchao@nuvoton.com> |
| Reviewed-on: https://review.openocd.org/c/openocd/+/5950 |
| Tested-by: jenkins |
| Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> |
| --- |
| contrib/loaders/flash/npcx/Makefile | 65 +++ |
| contrib/loaders/flash/npcx/npcx_algo.inc | 60 ++ |
| contrib/loaders/flash/npcx/npcx_flash.c | 342 ++++++++++++ |
| contrib/loaders/flash/npcx/npcx_flash.h | 179 ++++++ |
| contrib/loaders/flash/npcx/npcx_flash.lds | 58 ++ |
| .../loaders/flash/npcx/npcx_flash_config.h | 31 ++ |
| doc/openocd.texi | 13 +- |
| src/flash/nor/Makefile.am | 1 + |
| src/flash/nor/drivers.c | 2 + |
| src/flash/nor/npcx.c | 524 ++++++++++++++++++ |
| tcl/board/npcx_evb.cfg | 8 + |
| tcl/target/npcx.cfg | 51 ++ |
| 12 files changed, 1333 insertions(+), 1 deletion(-) |
| create mode 100644 contrib/loaders/flash/npcx/Makefile |
| create mode 100644 contrib/loaders/flash/npcx/npcx_algo.inc |
| create mode 100644 contrib/loaders/flash/npcx/npcx_flash.c |
| create mode 100644 contrib/loaders/flash/npcx/npcx_flash.h |
| create mode 100644 contrib/loaders/flash/npcx/npcx_flash.lds |
| create mode 100644 contrib/loaders/flash/npcx/npcx_flash_config.h |
| create mode 100644 src/flash/nor/npcx.c |
| create mode 100644 tcl/board/npcx_evb.cfg |
| create mode 100644 tcl/target/npcx.cfg |
| |
| diff --git a/contrib/loaders/flash/npcx/Makefile b/contrib/loaders/flash/npcx/Makefile |
| new file mode 100644 |
| index 000000000..293bd02da |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/Makefile |
| @@ -0,0 +1,65 @@ |
| +# SPDX-License-Identifier: GPL-2.0-or-later |
| + |
| +BIN2C = ../../../../src/helper/bin2char.sh |
| + |
| +# Toolchain used in makefile |
| +CROSS_COMPILE ?= arm-none-eabi- |
| +CC = $(CROSS_COMPILE)gcc |
| +CPLUS = $(CROSS_COMPILE)g++ |
| +CPP = $(CROSS_COMPILE)cpp |
| +LD = $(CROSS_COMPILE)gcc |
| +AS = $(CROSS_COMPILE)as |
| +OBJCOPY = $(CROSS_COMPILE)objcopy |
| +OBJDUMP = $(CROSS_COMPILE)objdump |
| +OBJSIZE = $(CROSS_COMPILE)size |
| + |
| +TARGET = npcx_algo |
| +OBJS := npcx_flash.o |
| +FLAGS = -mthumb -Os -ffunction-sections -fdata-sections -g -gdwarf-3 --specs=nano.specs |
| +FLAGS += -gstrict-dwarf -Wall -fno-strict-aliasing --asm |
| + |
| +CFLAGS = -c -I. -mcpu=cortex-m4 -fpack-struct |
| + |
| +PRE_LD_FILE = npcx_flash.lds |
| +LD_FILE = npcx_flash_generated.lds |
| +LDFLAGS = -Wl,-Map,lfw.map -Wl,-T$(LD_FILE) -nostartfiles |
| + |
| +all: $(TARGET).inc |
| + |
| +# Implicit rules |
| +%.o: %.c |
| + -@ echo CC $@ from $< |
| + @$(CC) $< $(FLAGS) $(CFLAGS) -o $@ |
| + |
| + $(LD_FILE): $(PRE_LD_FILE) |
| + -@ echo Generate $@ from $< |
| + -@$(CPP) $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE) |
| + |
| +$(TARGET).elf: $(OBJS) $(LD_FILE) |
| + -@ echo LD $@ from $< |
| + @$(LD) -o $@ $< $(FLAGS) $(LDFLAGS) |
| + |
| +%.bin: %.elf |
| + -@ echo OBJCOPY $@ from $< |
| + -@ $(OBJCOPY) $< -O binary $@ |
| + -@ $(OBJSIZE) $< --format=berkeley |
| + |
| +%.inc: %.bin |
| + @echo 'Building target: $@' |
| + @echo 'Invoking Bin2Char Script' |
| + $(BIN2C) < $< > $@ |
| + rm $< $*.elf |
| + @echo 'Finished building target: $@' |
| + @echo ' ' |
| + |
| +clean: |
| + @echo 'Cleaning Targets and Build Artifacts' |
| + rm -rf *.inc *.bin *.elf *.map |
| + rm -rf *.o *.d |
| + rm -rf $(LD_FILE) |
| + @echo 'Finished clean' |
| + @echo ' ' |
| + |
| +.PRECIOUS: %.bin |
| + |
| +.PHONY: all clean |
| diff --git a/contrib/loaders/flash/npcx/npcx_algo.inc b/contrib/loaders/flash/npcx/npcx_algo.inc |
| new file mode 100644 |
| index 000000000..4312fdb1b |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/npcx_algo.inc |
| @@ -0,0 +1,60 @@ |
| +/* Autogenerated with ../../../../src/helper/bin2char.sh */ |
| +0x08,0xb5,0xdf,0xf8,0x08,0xd0,0x00,0xf0,0x2f,0xf9,0x00,0x00,0x48,0x15,0x0c,0x20, |
| +0x03,0x4b,0x18,0x70,0x19,0x72,0x08,0x33,0x1a,0x78,0xd2,0x09,0xfc,0xd1,0x70,0x47, |
| +0x16,0x00,0x02,0x40,0x70,0xb5,0x11,0x4c,0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70, |
| +0xc0,0x21,0x05,0x20,0xff,0xf7,0xec,0xff,0x0d,0x4a,0x0e,0x49,0x6f,0xf0,0x7f,0x43, |
| +0x6f,0xf0,0x2e,0x05,0x10,0x46,0x15,0x70,0x06,0x78,0xf6,0x09,0xfc,0xd1,0x0e,0x78, |
| +0xf6,0x07,0x01,0xd5,0x01,0x3b,0xf6,0xd1,0x22,0x78,0x42,0xf0,0x02,0x02,0x00,0x2b, |
| +0x22,0x70,0x0c,0xbf,0x03,0x20,0x00,0x20,0x70,0xbd,0x00,0xbf,0x1f,0x00,0x02,0x40, |
| +0x1e,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x08,0xb5,0xc0,0x21,0x06,0x20,0xff,0xf7, |
| +0xc7,0xff,0xff,0xf7,0xcf,0xff,0x28,0xb9,0x03,0x4b,0x1b,0x78,0x13,0xf0,0x02,0x0f, |
| +0x08,0xbf,0x02,0x20,0x08,0xbd,0x00,0xbf,0x1a,0x00,0x02,0x40,0xf8,0xb5,0x12,0x4c, |
| +0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70,0x10,0x4b,0x17,0x46,0xc0,0xf3,0x07,0x42, |
| +0x1a,0x70,0xc0,0xf3,0x07,0x22,0xc0,0xb2,0x03,0xf8,0x01,0x2c,0x0e,0x46,0x03,0xf8, |
| +0x02,0x0c,0xe8,0x21,0x02,0x20,0xff,0xf7,0xa3,0xff,0x00,0x25,0xae,0x42,0x04,0xd8, |
| +0x23,0x78,0x43,0xf0,0x02,0x03,0x23,0x70,0xf8,0xbd,0x78,0x5d,0xe0,0x21,0xff,0xf7, |
| +0x97,0xff,0x01,0x35,0xf2,0xe7,0x00,0xbf,0x1f,0x00,0x02,0x40,0x19,0x00,0x02,0x40, |
| +0x70,0x47,0x2d,0xe9,0xf0,0x41,0x00,0xf1,0xff,0x06,0x26,0xf0,0xff,0x06,0x34,0x1a, |
| +0x8c,0x42,0x28,0xbf,0x0c,0x46,0x80,0x46,0x0d,0x46,0x17,0x46,0x5c,0xb1,0xff,0xf7, |
| +0xb3,0xff,0x58,0xb9,0x3a,0x46,0xa1,0xb2,0x40,0x46,0xff,0xf7,0xbf,0xff,0xff,0xf7, |
| +0x81,0xff,0x18,0xb9,0x27,0x44,0x2c,0x1b,0x14,0xb9,0x20,0x46,0xbd,0xe8,0xf0,0x81, |
| +0xb4,0xf5,0x80,0x7f,0x25,0x46,0x28,0xbf,0x4f,0xf4,0x80,0x75,0xff,0xf7,0x9c,0xff, |
| +0x00,0x28,0xf3,0xd1,0x3a,0x46,0xa9,0xb2,0x30,0x46,0xff,0xf7,0xa7,0xff,0xff,0xf7, |
| +0x69,0xff,0x00,0x28,0xea,0xd1,0x2f,0x44,0x2e,0x44,0x64,0x1b,0xe4,0xe7,0x00,0x00, |
| +0x2d,0xe9,0xf0,0x47,0x14,0x4e,0x15,0x4f,0xdf,0xf8,0x54,0x80,0x05,0x46,0x0c,0x46, |
| +0x8a,0x46,0x05,0xeb,0x04,0x09,0xa9,0xeb,0x0a,0x09,0xba,0xf1,0x00,0x0f,0x02,0xd1, |
| +0x50,0x46,0xbd,0xe8,0xf0,0x87,0xff,0xf7,0x77,0xff,0x00,0x28,0xf9,0xd1,0xc9,0xf3, |
| +0x07,0x43,0x33,0x70,0xc9,0xf3,0x07,0x23,0x5f,0xfa,0x89,0xf9,0x3b,0x70,0xc8,0x21, |
| +0x20,0x20,0x88,0xf8,0x00,0x90,0xff,0xf7,0x33,0xff,0xff,0xf7,0x3b,0xff,0x00,0x28, |
| +0xe7,0xd1,0xaa,0xf5,0x80,0x5a,0xdc,0xe7,0x19,0x00,0x02,0x40,0x18,0x00,0x02,0x40, |
| +0x17,0x00,0x02,0x40,0x08,0xb5,0xff,0xf7,0x57,0xff,0x38,0xb9,0xc0,0x21,0xc7,0x20, |
| +0xff,0xf7,0x1e,0xff,0xbd,0xe8,0x08,0x40,0xff,0xf7,0x24,0xbf,0x08,0xbd,0x00,0x00, |
| +0x38,0xb5,0xff,0xf7,0x49,0xff,0x04,0x46,0xc0,0xb9,0x0d,0x4b,0x0d,0x4d,0xf2,0x21, |
| +0x28,0x70,0x18,0x70,0x01,0x20,0xff,0xf7,0x0b,0xff,0xff,0xf7,0x13,0xff,0x04,0x46, |
| +0x60,0xb9,0xc1,0x21,0x05,0x20,0xff,0xf7,0x03,0xff,0x2b,0x78,0x2b,0xb9,0xc1,0x21, |
| +0x35,0x20,0xff,0xf7,0xfd,0xfe,0x2b,0x78,0x03,0xb1,0x02,0x24,0x20,0x46,0x38,0xbd, |
| +0x1b,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x10,0xb5,0xc3,0x21,0x04,0x46,0x9f,0x20, |
| +0xff,0xf7,0xee,0xfe,0x06,0x4b,0x07,0x4a,0x19,0x78,0x01,0x33,0x00,0x20,0x1b,0x78, |
| +0x12,0x78,0x1b,0x02,0x43,0xea,0x01,0x43,0x13,0x43,0x23,0x60,0x10,0xbd,0x00,0xbf, |
| +0x1a,0x00,0x02,0x40,0x1c,0x00,0x02,0x40,0x08,0xb5,0x10,0x22,0x00,0x21,0x00,0xf0, |
| +0x4d,0xf8,0x00,0x20,0x08,0xbd,0x00,0x00,0x73,0xb5,0x21,0x48,0x20,0x4c,0xff,0xf7, |
| +0xf3,0xff,0x20,0x4a,0x13,0x78,0x43,0xf0,0x80,0x03,0x13,0x70,0xff,0xf7,0xb0,0xff, |
| +0x05,0x46,0x58,0xb9,0x1c,0x4e,0xe3,0x68,0x00,0x2b,0xfc,0xd0,0xa3,0x68,0x01,0x3b, |
| +0x03,0x2b,0x2a,0xd8,0xdf,0xe8,0x03,0xf0,0x04,0x18,0x20,0x23,0xe5,0x60,0xfd,0xe7, |
| +0x01,0xa8,0xff,0xf7,0xc1,0xff,0xa8,0xb9,0x01,0x9b,0x33,0x70,0x1a,0x0a,0x1b,0x0c, |
| +0x72,0x70,0xb3,0x70,0xf0,0x70,0x23,0x7b,0x25,0x73,0x63,0x7b,0x65,0x73,0xa3,0x7b, |
| +0xa5,0x73,0xe3,0x7b,0xe5,0x73,0xde,0xe7,0x20,0x68,0x61,0x68,0xff,0xf7,0x48,0xff, |
| +0x00,0x28,0xf0,0xd0,0xe0,0x60,0xfe,0xe7,0xff,0xf7,0x74,0xff,0xf8,0xe7,0x20,0x68, |
| +0x61,0x68,0x32,0x46,0xff,0xf7,0x05,0xff,0xf2,0xe7,0x01,0x20,0xf2,0xe7,0x00,0xbf, |
| +0x00,0x00,0x0c,0x20,0x10,0x30,0x0c,0x40,0x10,0x00,0x0c,0x20,0xf0,0xb5,0x05,0x00, |
| +0x83,0x07,0x4e,0xd0,0x54,0x1e,0x00,0x2a,0x46,0xd0,0x0a,0x06,0x12,0x0e,0x03,0x00, |
| +0x03,0x26,0x02,0xe0,0x01,0x35,0x01,0x3c,0x3e,0xd3,0x01,0x33,0x2a,0x70,0x33,0x42, |
| +0xf8,0xd1,0x03,0x2c,0x2f,0xd9,0xff,0x22,0x0a,0x40,0x15,0x02,0x15,0x43,0x2a,0x04, |
| +0x15,0x43,0x0f,0x2c,0x38,0xd9,0x27,0x00,0x10,0x3f,0x3f,0x09,0x3e,0x01,0xb4,0x46, |
| +0x1e,0x00,0x1a,0x00,0x10,0x36,0x66,0x44,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60, |
| +0x10,0x32,0xb2,0x42,0xf8,0xd1,0x0f,0x26,0x0c,0x22,0x01,0x37,0x3f,0x01,0x26,0x40, |
| +0xdb,0x19,0x37,0x00,0x22,0x42,0x1a,0xd0,0x3e,0x1f,0xb6,0x08,0xb4,0x00,0xa4,0x46, |
| +0x1a,0x00,0x1c,0x1d,0x64,0x44,0x20,0xc2,0xa2,0x42,0xfc,0xd1,0x03,0x24,0x01,0x36, |
| +0xb6,0x00,0x9b,0x19,0x3c,0x40,0x00,0x2c,0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e, |
| +0x19,0x70,0x01,0x33,0x9c,0x42,0xfb,0xd1,0xf0,0xbc,0x02,0xbc,0x08,0x47,0x34,0x00, |
| +0xf1,0xe7,0x14,0x00,0x03,0x00,0xbc,0xe7,0x27,0x00,0xdd,0xe7, |
| diff --git a/contrib/loaders/flash/npcx/npcx_flash.c b/contrib/loaders/flash/npcx/npcx_flash.c |
| new file mode 100644 |
| index 000000000..d60624ae8 |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/npcx_flash.c |
| @@ -0,0 +1,342 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| + |
| +/* |
| + * Copyright (C) 2020 by Nuvoton Technology Corporation |
| + * Mulin Chao <mlchao@nuvoton.com> |
| + * Wealian Liao <WHLIAO@nuvoton.com> |
| + */ |
| + |
| +#include <stdint.h> |
| +#include <string.h> |
| +#include "npcx_flash.h" |
| + |
| +/*---------------------------------------------------------------------------- |
| + * NPCX flash driver |
| + *----------------------------------------------------------------------------*/ |
| +static void flash_execute_cmd(uint8_t code, uint8_t cts) |
| +{ |
| + /* Set UMA code */ |
| + NPCX_UMA_CODE = code; |
| + /* Execute UMA flash transaction by CTS setting */ |
| + NPCX_UMA_CTS = cts; |
| + /* Wait for transaction completed */ |
| + while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) |
| + ; |
| +} |
| + |
| +static void flash_cs_level(uint8_t level) |
| +{ |
| + /* Program chip select pin to high/low level */ |
| + if (level) |
| + NPCX_SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); |
| + else |
| + NPCX_CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); |
| +} |
| + |
| +static void flash_set_address(uint32_t dest_addr) |
| +{ |
| + uint8_t *addr = (uint8_t *)&dest_addr; |
| + |
| + /* Set target flash address */ |
| + NPCX_UMA_AB2 = addr[2]; |
| + NPCX_UMA_AB1 = addr[1]; |
| + NPCX_UMA_AB0 = addr[0]; |
| +} |
| + |
| +void delay(uint32_t i) |
| +{ |
| + while (i--) |
| + ; |
| +} |
| + |
| +static int flash_wait_ready(uint32_t timeout) |
| +{ |
| + /* Chip Select down. -- Burst mode */ |
| + flash_cs_level(0); |
| + |
| + /* Command for Read status register */ |
| + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_ONLY); |
| + while (timeout > 0) { |
| + /* Read status register */ |
| + NPCX_UMA_CTS = NPCX_MASK_RD_1BYTE; |
| + while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) |
| + ; |
| + |
| + if (!(NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_BUSY)) |
| + break; |
| + |
| + if (--timeout > 0) |
| + delay(100); |
| + |
| + }; /* Wait for Busy clear */ |
| + |
| + /* Chip Select high. */ |
| + flash_cs_level(1); |
| + |
| + if (timeout == 0) |
| + return NPCX_FLASH_STATUS_FAILED_TIMEOUT; |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +static int flash_write_enable(void) |
| +{ |
| + /* Write enable command */ |
| + flash_execute_cmd(NPCX_CMD_WRITE_EN, NPCX_MASK_CMD_ONLY); |
| + |
| + /* Wait for flash is not busy */ |
| + int status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + if (NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_WEL) |
| + return NPCX_FLASH_STATUS_OK; |
| + else |
| + return NPCX_FLASH_STATUS_FAILED; |
| +} |
| + |
| +static void flash_burst_write(uint32_t dest_addr, uint16_t bytes, |
| + const uint8_t *data) |
| +{ |
| + /* Chip Select down -- Burst mode */ |
| + flash_cs_level(0); |
| + |
| + /* Set write address */ |
| + flash_set_address(dest_addr); |
| + /* Start programming */ |
| + flash_execute_cmd(NPCX_CMD_FLASH_PROGRAM, NPCX_MASK_CMD_WR_ADR); |
| + for (uint32_t i = 0; i < bytes; i++) { |
| + flash_execute_cmd(*data, NPCX_MASK_CMD_WR_ONLY); |
| + data++; |
| + } |
| + |
| + /* Chip Select up */ |
| + flash_cs_level(1); |
| +} |
| + |
| +/* The data to write cannot cross 256 Bytes boundary */ |
| +static int flash_program_write(uint32_t addr, uint32_t size, |
| + const uint8_t *data) |
| +{ |
| + int status = flash_write_enable(); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + flash_burst_write(addr, size, data); |
| + return flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); |
| +} |
| + |
| +int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) |
| +{ |
| + int status; |
| + uint32_t trunk_start = (offset + 0xff) & ~0xff; |
| + |
| + /* write head */ |
| + uint32_t dest_addr = offset; |
| + uint32_t write_len = ((trunk_start - offset) > size) ? size : (trunk_start - offset); |
| + |
| + if (write_len) { |
| + status = flash_program_write(dest_addr, write_len, data); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + data += write_len; |
| + } |
| + |
| + dest_addr = trunk_start; |
| + size -= write_len; |
| + |
| + /* write remaining data*/ |
| + while (size > 0) { |
| + write_len = (size > NPCX_FLASH_WRITE_SIZE) ? |
| + NPCX_FLASH_WRITE_SIZE : size; |
| + |
| + status = flash_program_write(dest_addr, write_len, data); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + data += write_len; |
| + dest_addr += write_len; |
| + size -= write_len; |
| + } |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +int flash_physical_erase(uint32_t offset, uint32_t size) |
| +{ |
| + /* Alignment has been checked in upper layer */ |
| + for (; size > 0; size -= NPCX_FLASH_ERASE_SIZE, |
| + offset += NPCX_FLASH_ERASE_SIZE) { |
| + /* Enable write */ |
| + int status = flash_write_enable(); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + /* Set erase address */ |
| + flash_set_address(offset); |
| + /* Start erase */ |
| + flash_execute_cmd(NPCX_CMD_SECTOR_ERASE, NPCX_MASK_CMD_ADR); |
| + /* Wait erase completed */ |
| + status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + } |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +int flash_physical_erase_all(void) |
| +{ |
| + /* Enable write */ |
| + int status = flash_write_enable(); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + /* Start erase */ |
| + flash_execute_cmd(NPCX_CMD_CHIP_ERASE, NPCX_MASK_CMD_ONLY); |
| + |
| + /* Wait erase completed */ |
| + status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +int flash_physical_clear_stsreg(void) |
| +{ |
| + /* Enable write */ |
| + int status = flash_write_enable(); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + NPCX_UMA_DB0 = 0x0; |
| + NPCX_UMA_DB1 = 0x0; |
| + |
| + /* Write status register 1/2 */ |
| + flash_execute_cmd(NPCX_CMD_WRITE_STATUS_REG, NPCX_MASK_CMD_WR_2BYTE); |
| + |
| + /* Wait writing completed */ |
| + status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); |
| + if (status != NPCX_FLASH_STATUS_OK) |
| + return status; |
| + |
| + /* Read status register 1/2 for checking */ |
| + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_RD_1BYTE); |
| + if (NPCX_UMA_DB0 != 0x00) |
| + return NPCX_FLASH_STATUS_FAILED; |
| + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG2, NPCX_MASK_CMD_RD_1BYTE); |
| + if (NPCX_UMA_DB0 != 0x00) |
| + return NPCX_FLASH_STATUS_FAILED; |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +int flash_get_id(uint32_t *id) |
| +{ |
| + flash_execute_cmd(NPCX_CMD_READ_ID, NPCX_MASK_CMD_RD_3BYTE); |
| + *id = NPCX_UMA_DB0 << 16 | NPCX_UMA_DB1 << 8 | NPCX_UMA_DB2; |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +/*---------------------------------------------------------------------------- |
| + * flash loader function |
| + *----------------------------------------------------------------------------*/ |
| +uint32_t flashloader_init(struct npcx_flash_params *params) |
| +{ |
| + /* Initialize params buffers */ |
| + memset(params, 0, sizeof(struct npcx_flash_params)); |
| + |
| + return NPCX_FLASH_STATUS_OK; |
| +} |
| + |
| +/*---------------------------------------------------------------------------- |
| + * Functions |
| + *----------------------------------------------------------------------------*/ |
| +/* flashloader parameter structure */ |
| +__attribute__ ((section(".buffers.g_cfg"))) |
| +volatile struct npcx_flash_params g_cfg; |
| +/* data buffer */ |
| +__attribute__ ((section(".buffers.g_buf"))) |
| +uint8_t g_buf[NPCX_FLASH_LOADER_BUFFER_SIZE]; |
| + |
| +int main(void) |
| +{ |
| + uint32_t id; |
| + |
| + /* set buffer */ |
| + flashloader_init((struct npcx_flash_params *)&g_cfg); |
| + |
| + /* Avoid F_CS0 toggles while programming the internal flash. */ |
| + NPCX_SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI); |
| + |
| + /* clear flash status registers */ |
| + int status = flash_physical_clear_stsreg(); |
| + if (status != NPCX_FLASH_STATUS_OK) { |
| + while (1) |
| + g_cfg.sync = status; |
| + } |
| + |
| + while (1) { |
| + /* wait command*/ |
| + while (g_cfg.sync == NPCX_FLASH_LOADER_WAIT) |
| + ; |
| + |
| + /* command handler */ |
| + switch (g_cfg.cmd) { |
| + case NPCX_FLASH_CMD_GET_FLASH_ID: |
| + status = flash_get_id(&id); |
| + if (status == NPCX_FLASH_STATUS_OK) { |
| + g_buf[0] = id & 0xff; |
| + g_buf[1] = (id >> 8) & 0xff; |
| + g_buf[2] = (id >> 16) & 0xff; |
| + g_buf[3] = 0x00; |
| + } |
| + break; |
| + case NPCX_FLASH_CMD_ERASE_SECTORS: |
| + status = flash_physical_erase(g_cfg.addr, g_cfg.len); |
| + break; |
| + case NPCX_FLASH_CMD_ERASE_ALL: |
| + status = flash_physical_erase_all(); |
| + break; |
| + case NPCX_FLASH_CMD_PROGRAM: |
| + status = flash_physical_write(g_cfg.addr, |
| + g_cfg.len, |
| + g_buf); |
| + break; |
| + default: |
| + status = NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND; |
| + break; |
| + } |
| + |
| + /* clear & set result for next command */ |
| + if (status != NPCX_FLASH_STATUS_OK) { |
| + g_cfg.sync = status; |
| + while (1) |
| + ; |
| + } else { |
| + g_cfg.sync = NPCX_FLASH_LOADER_WAIT; |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +__attribute__ ((section(".stack"))) |
| +__attribute__ ((used)) |
| +static uint32_t stack[NPCX_FLASH_LOADER_STACK_SIZE / 4]; |
| +extern uint32_t _estack; |
| +extern uint32_t _bss; |
| +extern uint32_t _ebss; |
| + |
| +__attribute__ ((section(".entry"))) |
| +void entry(void) |
| +{ |
| + /* set sp from end of stack */ |
| + __asm(" ldr sp, =_estack - 4"); |
| + |
| + main(); |
| + |
| + __asm(" bkpt #0x00"); |
| +} |
| diff --git a/contrib/loaders/flash/npcx/npcx_flash.h b/contrib/loaders/flash/npcx/npcx_flash.h |
| new file mode 100644 |
| index 000000000..cc4f1ad50 |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/npcx_flash.h |
| @@ -0,0 +1,179 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| + |
| +/* |
| + * Copyright (C) 2020 by Nuvoton Technology Corporation |
| + * Mulin Chao <mlchao@nuvoton.com> |
| + * Wealian Liao <WHLIAO@nuvoton.com> |
| + */ |
| + |
| +#ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H |
| +#define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H |
| + |
| +#include "npcx_flash_config.h" |
| + |
| +/* Bit functions */ |
| +#define NPCX_SET_BIT(reg, bit) ((reg) |= (0x1 << (bit))) |
| +#define NPCX_CLEAR_BIT(reg, bit) ((reg) &= (~(0x1 << (bit)))) |
| +#define NPCX_IS_BIT_SET(reg, bit) (((reg) >> (bit)) & (0x1)) |
| + |
| +/* Field functions */ |
| +#define NPCX_GET_POS_FIELD(pos, size) (pos) |
| +#define NPCX_GET_SIZE_FIELD(pos, size) (size) |
| +#define NPCX_FIELD_POS(field) NPCX_GET_POS_##field |
| +#define NPCX_FIELD_SIZE(field) NPCX_GET_SIZE_##field |
| +/* Read field functions */ |
| +#define NPCX_GET_FIELD(reg, field) \ |
| + _NPCX_GET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field)) |
| +#define _NPCX_GET_FIELD_(reg, f_pos, f_size) \ |
| + (((reg) >> (f_pos)) & ((1 << (f_size)) - 1)) |
| +/* Write field functions */ |
| +#define NPCX_SET_FIELD(reg, field, value) \ |
| + _NPCX_SET_FIELD_((reg), NPCX_FIELD_POS(field), NPCX_FIELD_SIZE(field), (value)) |
| +#define _NPCX_SET_FIELD_(reg, f_pos, f_size, value) \ |
| + ((reg) = ((reg) & (~(((1 << (f_size)) - 1) << (f_pos)))) | ((value) << (f_pos))) |
| + |
| +/* Register definitions */ |
| +#define NPCX_REG32_ADDR(addr) ((volatile uint32_t *)(addr)) |
| +#define NPCX_REG16_ADDR(addr) ((volatile uint16_t *)(addr)) |
| +#define NPCX_REG8_ADDR(addr) ((volatile uint8_t *)(addr)) |
| + |
| +#define NPCX_HW_BYTE(addr) (*NPCX_REG8_ADDR(addr)) |
| +#define NPCX_HW_WORD(addr) (*NPCX_REG16_ADDR(addr)) |
| +#define NPCX_HW_DWORD(addr) (*NPCX_REG32_ADDR(addr)) |
| + |
| +/* Devalt */ |
| +#define NPCX_SCFG_BASE_ADDR 0x400C3000 |
| +#define NPCX_DEVCNT NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x000) |
| +#define NPCX_DEVALT(n) NPCX_HW_BYTE(NPCX_SCFG_BASE_ADDR + 0x010 + (n)) |
| + |
| +#define NPCX_DEVCNT_HIF_TYP_SEL_FIELD FIELD(2, 2) |
| +#define NPCX_DEVCNT_JEN0_HEN 4 |
| +#define NPCX_DEVCNT_JEN1_HEN 5 |
| +#define NPCX_DEVCNT_F_SPI_TRIS 6 |
| + |
| +/* Pin-mux for SPI/FIU */ |
| +#define NPCX_DEVALT0_SPIP_SL 0 |
| +#define NPCX_DEVALT0_GPIO_NO_SPIP 3 |
| +#define NPCX_DEVALT0_F_SPI_CS1_2 4 |
| +#define NPCX_DEVALT0_F_SPI_CS1_1 5 |
| +#define NPCX_DEVALT0_F_SPI_QUAD 6 |
| +#define NPCX_DEVALT0_NO_F_SPI 7 |
| + |
| +/* Flash Interface Unit (FIU) registers */ |
| +#define NPCX_FIU_BASE_ADDR 0x40020000 |
| +#define NPCX_FIU_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x000) |
| +#define NPCX_BURST_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x001) |
| +#define NPCX_RESP_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x002) |
| +#define NPCX_SPI_FL_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x014) |
| +#define NPCX_UMA_CODE NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x016) |
| +#define NPCX_UMA_AB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x017) |
| +#define NPCX_UMA_AB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x018) |
| +#define NPCX_UMA_AB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x019) |
| +#define NPCX_UMA_DB0 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01A) |
| +#define NPCX_UMA_DB1 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01B) |
| +#define NPCX_UMA_DB2 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01C) |
| +#define NPCX_UMA_DB3 NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01D) |
| +#define NPCX_UMA_CTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01E) |
| +#define NPCX_UMA_ECTS NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x01F) |
| +#define NPCX_UMA_DB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x020) |
| +#define NPCX_FIU_RD_CMD NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x030) |
| +#define NPCX_FIU_DMM_CYC NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x032) |
| +#define NPCX_FIU_EXT_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x033) |
| +#define NPCX_FIU_UMA_AB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x034) |
| + |
| +/* FIU register fields */ |
| +#define NPCX_RESP_CFG_IAD_EN 0 |
| +#define NPCX_RESP_CFG_DEV_SIZE_EX 2 |
| +#define NPCX_UMA_CTS_A_SIZE 3 |
| +#define NPCX_UMA_CTS_C_SIZE 4 |
| +#define NPCX_UMA_CTS_RD_WR 5 |
| +#define NPCX_UMA_CTS_DEV_NUM 6 |
| +#define NPCX_UMA_CTS_EXEC_DONE 7 |
| +#define NPCX_UMA_ECTS_SW_CS0 0 |
| +#define NPCX_UMA_ECTS_SW_CS1 1 |
| +#define NPCX_UMA_ECTS_SEC_CS 2 |
| +#define NPCX_UMA_ECTS_UMA_LOCK 3 |
| + |
| +/* Flash UMA commands for npcx internal SPI flash */ |
| +#define NPCX_CMD_READ_ID 0x9F |
| +#define NPCX_CMD_READ_MAN_DEV_ID 0x90 |
| +#define NPCX_CMD_WRITE_EN 0x06 |
| +#define NPCX_CMD_WRITE_STATUS 0x50 |
| +#define NPCX_CMD_READ_STATUS_REG 0x05 |
| +#define NPCX_CMD_READ_STATUS_REG2 0x35 |
| +#define NPCX_CMD_WRITE_STATUS_REG 0x01 |
| +#define NPCX_CMD_FLASH_PROGRAM 0x02 |
| +#define NPCX_CMD_SECTOR_ERASE 0x20 |
| +#define NPCX_CMD_PROGRAM_UINT_SIZE 0x08 |
| +#define NPCX_CMD_PAGE_SIZE 0x00 |
| +#define NPCX_CMD_READ_ID_TYPE 0x47 |
| +#define NPCX_CMD_FAST_READ 0x0B |
| +#define NPCX_CMD_CHIP_ERASE 0xC7 |
| + |
| +/* |
| + * Status registers for SPI flash |
| + */ |
| +#define NPCX_SPI_FLASH_SR2_SUS (1 << 7) |
| +#define NPCX_SPI_FLASH_SR2_CMP (1 << 6) |
| +#define NPCX_SPI_FLASH_SR2_LB3 (1 << 5) |
| +#define NPCX_SPI_FLASH_SR2_LB2 (1 << 4) |
| +#define NPCX_SPI_FLASH_SR2_LB1 (1 << 3) |
| +#define NPCX_SPI_FLASH_SR2_QE (1 << 1) |
| +#define NPCX_SPI_FLASH_SR2_SRP1 (1 << 0) |
| +#define NPCX_SPI_FLASH_SR1_SRP0 (1 << 7) |
| +#define NPCX_SPI_FLASH_SR1_SEC (1 << 6) |
| +#define NPCX_SPI_FLASH_SR1_TB (1 << 5) |
| +#define NPCX_SPI_FLASH_SR1_BP2 (1 << 4) |
| +#define NPCX_SPI_FLASH_SR1_BP1 (1 << 3) |
| +#define NPCX_SPI_FLASH_SR1_BP0 (1 << 2) |
| +#define NPCX_SPI_FLASH_SR1_WEL (1 << 1) |
| +#define NPCX_SPI_FLASH_SR1_BUSY (1 << 0) |
| + |
| +#define NPCX_MASK_CMD_ONLY (0xC0) |
| +#define NPCX_MASK_CMD_ADR (0xC0 | 0x08) |
| +#define NPCX_MASK_CMD_ADR_WR (0xC0 | 0x20 | 0x08 | 0x01) |
| +#define NPCX_MASK_RD_1BYTE (0xC0 | 0x10 | 0x01) |
| +#define NPCX_MASK_RD_2BYTE (0xC0 | 0x10 | 0x02) |
| +#define NPCX_MASK_RD_3BYTE (0xC0 | 0x10 | 0x03) |
| +#define NPCX_MASK_RD_4BYTE (0xC0 | 0x10 | 0x04) |
| +#define NPCX_MASK_CMD_RD_1BYTE (0xC0 | 0x01) |
| +#define NPCX_MASK_CMD_RD_2BYTE (0xC0 | 0x02) |
| +#define NPCX_MASK_CMD_RD_3BYTE (0xC0 | 0x03) |
| +#define NPCX_MASK_CMD_RD_4BYTE (0xC0 | 0x04) |
| +#define NPCX_MASK_CMD_WR_ONLY (0xC0 | 0x20) |
| +#define NPCX_MASK_CMD_WR_1BYTE (0xC0 | 0x20 | 0x10 | 0x01) |
| +#define NPCX_MASK_CMD_WR_2BYTE (0xC0 | 0x20 | 0x10 | 0x02) |
| +#define NPCX_MASK_CMD_WR_ADR (0xC0 | 0x20 | 0x08) |
| + |
| +/* Flash loader parameters */ |
| +struct __attribute__((__packed__)) npcx_flash_params { |
| + uint32_t addr; /* Address in flash */ |
| + uint32_t len; /* Number of bytes */ |
| + uint32_t cmd; /* Command */ |
| + uint32_t sync; /* Handshake signal */ |
| +}; |
| + |
| +/* Flash trigger signal */ |
| +enum npcx_flash_handshake { |
| + NPCX_FLASH_LOADER_WAIT = 0x0, /* Idle */ |
| + NPCX_FLASH_LOADER_EXECUTE = 0xFFFFFFFF /* Execute Command */ |
| +}; |
| + |
| +/* Flash loader command */ |
| +enum npcx_flash_commands { |
| + NPCX_FLASH_CMD_NO_ACTION = 0, /* No action, default value */ |
| + NPCX_FLASH_CMD_GET_FLASH_ID, /* Get the internal flash ID */ |
| + NPCX_FLASH_CMD_ERASE_SECTORS, /* Erase unprotected sectors */ |
| + NPCX_FLASH_CMD_ERASE_ALL, /* Erase all */ |
| + NPCX_FLASH_CMD_PROGRAM, /* Program data */ |
| +}; |
| + |
| +/* Status */ |
| +enum npcx_flash_status { |
| + NPCX_FLASH_STATUS_OK = 0, |
| + NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND, |
| + NPCX_FLASH_STATUS_FAILED, |
| + NPCX_FLASH_STATUS_FAILED_TIMEOUT, |
| +}; |
| + |
| +#endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H */ |
| diff --git a/contrib/loaders/flash/npcx/npcx_flash.lds b/contrib/loaders/flash/npcx/npcx_flash.lds |
| new file mode 100644 |
| index 000000000..0d782523a |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/npcx_flash.lds |
| @@ -0,0 +1,58 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| + |
| +#include "npcx_flash_config.h" |
| + |
| +/* Application memory map */ |
| +MEMORY { |
| + /* buffer + parameters */ |
| + BUFFER (RWX) : ORIGIN = NPCX_FLASH_LOADER_PARAMS_ADDR, |
| + LENGTH = NPCX_FLASH_LOADER_PARAMS_SIZE + NPCX_FLASH_LOADER_BUFFER_SIZE |
| + |
| + PROGRAM (RWX) : ORIGIN = NPCX_FLASH_LOADER_PROGRAM_ADDR, |
| + LENGTH = NPCX_FLASH_LOADER_PROGRAM_SIZE |
| +} |
| + |
| +/* Sections used for flashing */ |
| +SECTIONS |
| +{ |
| + .buffers (NOLOAD) : |
| + { |
| + _buffers = .; |
| + *(.buffers.g_cfg) |
| + *(.buffers.g_buf) |
| + *(.buffers*) |
| + _ebuffers = .; |
| + } > BUFFER |
| + |
| + .text : |
| + { |
| + _text = .; |
| + *(.entry*) |
| + *(.text*) |
| + _etext = .; |
| + } > PROGRAM |
| + |
| + .data : |
| + { _data = .; |
| + *(.rodata*) |
| + *(.data*) |
| + _edata = .; |
| + } > PROGRAM |
| + |
| + .bss : |
| + { |
| + __bss_start__ = .; |
| + _bss = .; |
| + *(.bss*) |
| + *(COMMON) |
| + _ebss = .; |
| + __bss_end__ = .; |
| + } > PROGRAM |
| + |
| + .stack (NOLOAD) : |
| + { |
| + _stack = .; |
| + *(.stack*) |
| + _estack = .; |
| + } > PROGRAM |
| +} |
| diff --git a/contrib/loaders/flash/npcx/npcx_flash_config.h b/contrib/loaders/flash/npcx/npcx_flash_config.h |
| new file mode 100644 |
| index 000000000..9ec1c5e33 |
| --- /dev/null |
| +++ b/contrib/loaders/flash/npcx/npcx_flash_config.h |
| @@ -0,0 +1,31 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| + |
| +/* |
| + * Copyright (C) 2021 by Nuvoton Technology Corporation |
| + * Mulin Chao <mlchao@nuvoton.com> |
| + * Wealian Liao <WHLIAO@nuvoton.com> |
| + */ |
| + |
| +#ifndef OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H |
| +#define OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H |
| + |
| +#define NPCX_FLASH_ABORT_TIMEOUT 0xFFFFFF |
| + |
| +/* NPCX chip information */ |
| +#define NPCX_FLASH_WRITE_SIZE 256L /* One page size for write */ |
| +#define NPCX_FLASH_ERASE_SIZE 0x1000 |
| + |
| +/* NPCX flash loader information */ |
| +#define NPCX_FLASH_LOADER_WORKING_ADDR 0x200C0000 |
| +#define NPCX_FLASH_LOADER_PARAMS_ADDR NPCX_FLASH_LOADER_WORKING_ADDR |
| +#define NPCX_FLASH_LOADER_PARAMS_SIZE 16 |
| +#define NPCX_FLASH_LOADER_BUFFER_ADDR (NPCX_FLASH_LOADER_PARAMS_ADDR + NPCX_FLASH_LOADER_PARAMS_SIZE) |
| +#define NPCX_FLASH_LOADER_BUFFER_SIZE NPCX_FLASH_ERASE_SIZE |
| +#define NPCX_FLASH_LOADER_PROGRAM_ADDR (NPCX_FLASH_LOADER_BUFFER_ADDR + NPCX_FLASH_LOADER_BUFFER_SIZE) |
| +#define NPCX_FLASH_LOADER_PROGRAM_SIZE 0x1000 |
| + |
| +/* Stack size in byte. 4 byte size alignment */ |
| +#define NPCX_FLASH_LOADER_STACK_SIZE 400 |
| + |
| + |
| +#endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_CONFIG_H */ |
| diff --git a/doc/openocd.texi b/doc/openocd.texi |
| index a5b94362f..0c31f8a77 100644 |
| --- a/doc/openocd.texi |
| +++ b/doc/openocd.texi |
| @@ -6679,7 +6679,18 @@ Show information about flash driver. |
| |
| @end deffn |
| |
| -@deffn {Flash Driver} nrf5 |
| +@deffn {Flash Driver} {npcx} |
| +All versions of the NPCX microcontroller families from Nuvoton include internal |
| +flash. The NPCX flash driver supports the NPCX family of devices. The driver |
| +automatically recognizes the specific version's flash parameters and |
| +autoconfigures itself. The flash bank starts at address 0x64000000. |
| + |
| +@example |
| +flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME |
| +@end example |
| +@end deffn |
| + |
| +@deffn {Flash Driver} {nrf5} |
| All members of the nRF51 microcontroller families from Nordic Semiconductor |
| include internal flash and use ARM Cortex-M0 core. |
| Also, the nRF52832 microcontroller from Nordic Semiconductor, which include |
| diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am |
| index 8c9b2b7ab..5d86caff6 100644 |
| --- a/src/flash/nor/Makefile.am |
| +++ b/src/flash/nor/Makefile.am |
| @@ -44,6 +44,7 @@ NOR_DRIVERS = \ |
| %D%/mrvlqspi.c \ |
| %D%/niietcm4.c \ |
| %D%/non_cfi.c \ |
| + %D%/npcx.c \ |
| %D%/nrf5.c \ |
| %D%/numicro.c \ |
| %D%/ocl.c \ |
| diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c |
| index 570861ec5..217775af2 100644 |
| --- a/src/flash/nor/drivers.c |
| +++ b/src/flash/nor/drivers.c |
| @@ -56,6 +56,7 @@ extern const struct flash_driver mdr_flash; |
| extern const struct flash_driver mrvlqspi_flash; |
| extern const struct flash_driver msp432_flash; |
| extern const struct flash_driver niietcm4_flash; |
| +extern const struct flash_driver npcx_flash; |
| extern const struct flash_driver nrf5_flash; |
| extern const struct flash_driver nrf51_flash; |
| extern const struct flash_driver numicro_flash; |
| @@ -129,6 +130,7 @@ static const struct flash_driver * const flash_drivers[] = { |
| &mrvlqspi_flash, |
| &msp432_flash, |
| &niietcm4_flash, |
| + &npcx_flash, |
| &nrf5_flash, |
| &nrf51_flash, |
| &numicro_flash, |
| diff --git a/src/flash/nor/npcx.c b/src/flash/nor/npcx.c |
| new file mode 100644 |
| index 000000000..af623e577 |
| --- /dev/null |
| +++ b/src/flash/nor/npcx.c |
| @@ -0,0 +1,524 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| + |
| +/* |
| + * Copyright (C) 2020 by Nuvoton Technology Corporation |
| + * Mulin Chao <mlchao@nuvoton.com> |
| + * Wealian Liao <WHLIAO@nuvoton.com> |
| + */ |
| + |
| +#ifdef HAVE_CONFIG_H |
| +#include "config.h" |
| +#endif |
| + |
| +#include "imp.h" |
| +#include <helper/binarybuffer.h> |
| +#include <helper/time_support.h> |
| +#include <target/armv7m.h> |
| +#include "../../../contrib/loaders/flash/npcx/npcx_flash.h" |
| + |
| +/* NPCX flash loader */ |
| +const uint8_t npcx_algo[] = { |
| +#include "../../../contrib/loaders/flash/npcx/npcx_algo.inc" |
| +}; |
| + |
| +#define NPCX_FLASH_TIMEOUT_MS 8000 |
| +#define NPCX_FLASH_BASE_ADDR 0x64000000 |
| + |
| +/* flash list */ |
| +enum npcx_flash_device_index { |
| + NPCX_FLASH_256KB = 0, |
| + NPCX_FLASH_512KB = 1, |
| + NPCX_FLASH_1MB = 2, |
| + NPCX_FLASH_UNKNOWN, |
| +}; |
| + |
| +struct npcx_flash_bank { |
| + const char *family_name; |
| + uint32_t sector_length; |
| + bool probed; |
| + enum npcx_flash_device_index flash; |
| + struct working_area *working_area; |
| + struct armv7m_algorithm armv7m_info; |
| + const uint8_t *algo_code; |
| + uint32_t algo_size; |
| + uint32_t algo_working_size; |
| + uint32_t buffer_addr; |
| + uint32_t params_addr; |
| +}; |
| + |
| +struct npcx_flash_info { |
| + char *name; |
| + uint32_t id; |
| + uint32_t size; |
| +}; |
| + |
| +static const struct npcx_flash_info flash_info[] = { |
| + [NPCX_FLASH_256KB] = { |
| + .name = "256KB Flash", |
| + .id = 0xEF4012, |
| + .size = 256 * 1024, |
| + }, |
| + [NPCX_FLASH_512KB] = { |
| + .name = "512KB Flash", |
| + .id = 0xEF4013, |
| + .size = 512 * 1024, |
| + }, |
| + [NPCX_FLASH_1MB] = { |
| + .name = "1MB Flash", |
| + .id = 0xEF4014, |
| + .size = 1024 * 1024, |
| + }, |
| + [NPCX_FLASH_UNKNOWN] = { |
| + .name = "Unknown Flash", |
| + .size = 0xFFFFFFFF, |
| + }, |
| +}; |
| + |
| +static int npcx_init(struct flash_bank *bank) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + |
| + /* Check for working area to use for flash helper algorithm */ |
| + if (npcx_bank->working_area) { |
| + target_free_working_area(target, npcx_bank->working_area); |
| + npcx_bank->working_area = NULL; |
| + } |
| + |
| + int retval = target_alloc_working_area(target, npcx_bank->algo_working_size, |
| + &npcx_bank->working_area); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + /* Confirm the defined working address is the area we need to use */ |
| + if (npcx_bank->working_area->address != NPCX_FLASH_LOADER_WORKING_ADDR) { |
| + LOG_ERROR("%s: Invalid working address", npcx_bank->family_name); |
| + LOG_INFO("Hint: Use '-work-area-phys 0x%" PRIx32 "' in your target configuration", |
| + NPCX_FLASH_LOADER_WORKING_ADDR); |
| + target_free_working_area(target, npcx_bank->working_area); |
| + npcx_bank->working_area = NULL; |
| + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; |
| + } |
| + |
| + /* Write flash helper algorithm into target memory */ |
| + retval = target_write_buffer(target, NPCX_FLASH_LOADER_PROGRAM_ADDR, |
| + npcx_bank->algo_size, npcx_bank->algo_code); |
| + if (retval != ERROR_OK) { |
| + LOG_ERROR("%s: Failed to load flash helper algorithm", |
| + npcx_bank->family_name); |
| + target_free_working_area(target, npcx_bank->working_area); |
| + npcx_bank->working_area = NULL; |
| + return retval; |
| + } |
| + |
| + /* Initialize the ARMv7 specific info to run the algorithm */ |
| + npcx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; |
| + npcx_bank->armv7m_info.core_mode = ARM_MODE_THREAD; |
| + |
| + /* Begin executing the flash helper algorithm */ |
| + retval = target_start_algorithm(target, 0, NULL, 0, NULL, |
| + NPCX_FLASH_LOADER_PROGRAM_ADDR, 0, |
| + &npcx_bank->armv7m_info); |
| + if (retval != ERROR_OK) { |
| + LOG_ERROR("%s: Failed to start flash helper algorithm", |
| + npcx_bank->family_name); |
| + target_free_working_area(target, npcx_bank->working_area); |
| + npcx_bank->working_area = NULL; |
| + return retval; |
| + } |
| + |
| + /* |
| + * At this point, the algorithm is running on the target and |
| + * ready to receive commands and data to flash the target |
| + */ |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_quit(struct flash_bank *bank) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + |
| + /* Regardless of the algo's status, attempt to halt the target */ |
| + (void)target_halt(target); |
| + |
| + /* Now confirm target halted and clean up from flash helper algorithm */ |
| + int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, |
| + NPCX_FLASH_TIMEOUT_MS, &npcx_bank->armv7m_info); |
| + |
| + target_free_working_area(target, npcx_bank->working_area); |
| + npcx_bank->working_area = NULL; |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync); |
| + uint32_t status; |
| + int64_t start_ms = timeval_ms(); |
| + |
| + do { |
| + int retval = target_read_u32(target, status_addr, &status); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + keep_alive(); |
| + |
| + int64_t elapsed_ms = timeval_ms() - start_ms; |
| + if (elapsed_ms > NPCX_FLASH_TIMEOUT_MS) |
| + break; |
| + } while (status == NPCX_FLASH_LOADER_EXECUTE); |
| + |
| + if (status != NPCX_FLASH_LOADER_WAIT) { |
| + LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32, |
| + npcx_bank->family_name, |
| + status); |
| + return ERROR_FAIL; |
| + } |
| + |
| + return ERROR_OK; |
| +} |
| + |
| +static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, uint32_t *flash_id) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + struct npcx_flash_params algo_params; |
| + |
| + if (target->state != TARGET_HALTED) { |
| + LOG_ERROR("Target not halted"); |
| + return ERROR_TARGET_NOT_HALTED; |
| + } |
| + |
| + int retval = npcx_init(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + /* Set up algorithm parameters for get flash ID command */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_GET_FLASH_ID); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); |
| + |
| + /* Issue flash helper algorithm parameters for get flash ID */ |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + if (retval != ERROR_OK) { |
| + (void)npcx_quit(bank); |
| + return retval; |
| + } |
| + |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + |
| + /* If no error, wait for finishing */ |
| + if (retval == ERROR_OK) { |
| + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); |
| + if (retval == ERROR_OK) |
| + target_read_u32(target, NPCX_FLASH_LOADER_BUFFER_ADDR, flash_id); |
| + } |
| + |
| + /* Regardless of errors, try to close down algo */ |
| + (void)npcx_quit(bank); |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_get_flash(uint32_t flash_id) |
| +{ |
| + for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) { |
| + if (flash_info[i].id == flash_id) |
| + return i; |
| + } |
| + |
| + return NPCX_FLASH_UNKNOWN; |
| +} |
| + |
| +static int npcx_probe(struct flash_bank *bank) |
| +{ |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + uint32_t sector_length = NPCX_FLASH_ERASE_SIZE; |
| + uint32_t flash_id; |
| + |
| + /* Set up appropriate flash helper algorithm */ |
| + npcx_bank->algo_code = npcx_algo; |
| + npcx_bank->algo_size = sizeof(npcx_algo); |
| + npcx_bank->algo_working_size = NPCX_FLASH_LOADER_PARAMS_SIZE + |
| + NPCX_FLASH_LOADER_BUFFER_SIZE + |
| + NPCX_FLASH_LOADER_PROGRAM_SIZE; |
| + npcx_bank->buffer_addr = NPCX_FLASH_LOADER_BUFFER_ADDR; |
| + npcx_bank->params_addr = NPCX_FLASH_LOADER_PARAMS_ADDR; |
| + |
| + int retval = npcx_get_flash_id(bank, &flash_id); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + npcx_bank->flash = npcx_get_flash(flash_id); |
| + |
| + unsigned int num_sectors = flash_info[npcx_bank->flash].size / sector_length; |
| + |
| + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); |
| + if (!bank->sectors) { |
| + LOG_ERROR("Out of memory"); |
| + return ERROR_FAIL; |
| + } |
| + |
| + bank->base = NPCX_FLASH_BASE_ADDR; |
| + bank->num_sectors = num_sectors; |
| + bank->size = num_sectors * sector_length; |
| + bank->write_start_alignment = 0; |
| + bank->write_end_alignment = 0; |
| + npcx_bank->sector_length = sector_length; |
| + |
| + for (unsigned int i = 0; i < num_sectors; i++) { |
| + bank->sectors[i].offset = i * sector_length; |
| + bank->sectors[i].size = sector_length; |
| + bank->sectors[i].is_erased = -1; |
| + bank->sectors[i].is_protected = 0; |
| + } |
| + |
| + /* We've successfully determined the stats on the flash bank */ |
| + npcx_bank->probed = true; |
| + |
| + /* If we fall through to here, then all went well */ |
| + return ERROR_OK; |
| +} |
| + |
| +static int npcx_auto_probe(struct flash_bank *bank) |
| +{ |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + int retval = ERROR_OK; |
| + |
| + if (!npcx_bank->probed) |
| + retval = npcx_probe(bank); |
| + |
| + return retval; |
| +} |
| + |
| +FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command) |
| +{ |
| + struct npcx_flash_bank *npcx_bank; |
| + |
| + if (CMD_ARGC < 6) |
| + return ERROR_COMMAND_SYNTAX_ERROR; |
| + |
| + npcx_bank = calloc(1, sizeof(struct npcx_flash_bank)); |
| + if (!npcx_bank) { |
| + LOG_ERROR("Out of memory"); |
| + return ERROR_FAIL; |
| + } |
| + |
| + /* Initialize private flash information */ |
| + npcx_bank->family_name = "npcx"; |
| + npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE; |
| + |
| + /* Finish initialization of bank */ |
| + bank->driver_priv = npcx_bank; |
| + bank->next = NULL; |
| + |
| + return ERROR_OK; |
| +} |
| + |
| +static int npcx_chip_erase(struct flash_bank *bank) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + struct npcx_flash_params algo_params; |
| + |
| + if (target->state != TARGET_HALTED) { |
| + LOG_ERROR("Target not halted"); |
| + return ERROR_TARGET_NOT_HALTED; |
| + } |
| + |
| + /* Make sure we've probed the flash to get the device and size */ |
| + int retval = npcx_auto_probe(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + retval = npcx_init(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + /* Set up algorithm parameters for chip erase command */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); |
| + |
| + /* Set algorithm parameters */ |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + if (retval != ERROR_OK) { |
| + (void)npcx_quit(bank); |
| + return retval; |
| + } |
| + |
| + /* Issue flash helper algorithm parameters for chip erase */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + |
| + /* If no error, wait for chip erase finish */ |
| + if (retval == ERROR_OK) |
| + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); |
| + |
| + /* Regardless of errors, try to close down algo */ |
| + (void)npcx_quit(bank); |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_erase(struct flash_bank *bank, unsigned int first, |
| + unsigned int last) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + struct npcx_flash_params algo_params; |
| + |
| + if (target->state != TARGET_HALTED) { |
| + LOG_ERROR("Target not halted"); |
| + return ERROR_TARGET_NOT_HALTED; |
| + } |
| + |
| + if ((first == 0) && (last == (bank->num_sectors - 1))) { |
| + /* Request chip erase */ |
| + return npcx_chip_erase(bank); |
| + } |
| + |
| + uint32_t address = first * npcx_bank->sector_length; |
| + uint32_t length = (last - first + 1) * npcx_bank->sector_length; |
| + |
| + /* Make sure we've probed the flash to get the device and size */ |
| + int retval = npcx_auto_probe(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + retval = npcx_init(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + /* Set up algorithm parameters for erase command */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); |
| + |
| + /* Set algorithm parameters */ |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + if (retval != ERROR_OK) { |
| + (void)npcx_quit(bank); |
| + return retval; |
| + } |
| + |
| + /* Issue flash helper algorithm parameters for erase */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + |
| + /* If no error, wait for erase to finish */ |
| + if (retval == ERROR_OK) |
| + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); |
| + |
| + /* Regardless of errors, try to close down algo */ |
| + (void)npcx_quit(bank); |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_write(struct flash_bank *bank, const uint8_t *buffer, |
| + uint32_t offset, uint32_t count) |
| +{ |
| + struct target *target = bank->target; |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + struct npcx_flash_params algo_params; |
| + |
| + if (target->state != TARGET_HALTED) { |
| + LOG_ERROR("Target not halted"); |
| + return ERROR_TARGET_NOT_HALTED; |
| + } |
| + |
| + /* Make sure we've probed the flash to get the device and size */ |
| + int retval = npcx_auto_probe(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + retval = npcx_init(bank); |
| + if (retval != ERROR_OK) |
| + return retval; |
| + |
| + /* Initialize algorithm parameters to default values */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_PROGRAM); |
| + |
| + uint32_t address = offset; |
| + |
| + while (count > 0) { |
| + uint32_t size = (count > NPCX_FLASH_LOADER_BUFFER_SIZE) ? |
| + NPCX_FLASH_LOADER_BUFFER_SIZE : count; |
| + |
| + /* Put the data into buffer */ |
| + retval = target_write_buffer(target, npcx_bank->buffer_addr, |
| + size, buffer); |
| + if (retval != ERROR_OK) { |
| + LOG_ERROR("Unable to write data to target memory"); |
| + break; |
| + } |
| + |
| + /* Update algo parameters for flash write */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size); |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); |
| + |
| + /* Set algorithm parameters */ |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + if (retval != ERROR_OK) |
| + break; |
| + |
| + /* Issue flash helper algorithm parameters for flash write */ |
| + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_EXECUTE); |
| + retval = target_write_buffer(target, npcx_bank->params_addr, |
| + sizeof(algo_params), (uint8_t *)&algo_params); |
| + if (retval != ERROR_OK) |
| + break; |
| + |
| + /* Wait for flash write finish */ |
| + retval = npcx_wait_algo_done(bank, npcx_bank->params_addr); |
| + if (retval != ERROR_OK) |
| + break; |
| + |
| + count -= size; |
| + buffer += size; |
| + address += size; |
| + } |
| + |
| + /* Regardless of errors, try to close down algo */ |
| + (void)npcx_quit(bank); |
| + |
| + return retval; |
| +} |
| + |
| +static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd) |
| +{ |
| + struct npcx_flash_bank *npcx_bank = bank->driver_priv; |
| + |
| + command_print_sameline(cmd, "%s flash: %s\n", |
| + npcx_bank->family_name, |
| + flash_info[npcx_bank->flash].name); |
| + |
| + return ERROR_OK; |
| +} |
| + |
| +const struct flash_driver npcx_flash = { |
| + .name = "npcx", |
| + .flash_bank_command = npcx_flash_bank_command, |
| + .erase = npcx_erase, |
| + .write = npcx_write, |
| + .read = default_flash_read, |
| + .probe = npcx_probe, |
| + .auto_probe = npcx_auto_probe, |
| + .erase_check = default_flash_blank_check, |
| + .info = npcx_info, |
| + .free_driver_priv = default_flash_free_driver_priv, |
| +}; |
| diff --git a/tcl/board/npcx_evb.cfg b/tcl/board/npcx_evb.cfg |
| new file mode 100644 |
| index 000000000..4f28bc964 |
| --- /dev/null |
| +++ b/tcl/board/npcx_evb.cfg |
| @@ -0,0 +1,8 @@ |
| +# SPDX-License-Identifier: GPL-2.0-or-later |
| + |
| +# Nuvoton NPCX Evaluation Board |
| + |
| +source [find interface/jlink.cfg] |
| +transport select swd |
| + |
| +source [find target/npcx.cfg] |
| diff --git a/tcl/target/npcx.cfg b/tcl/target/npcx.cfg |
| new file mode 100644 |
| index 000000000..1a21e1f7f |
| --- /dev/null |
| +++ b/tcl/target/npcx.cfg |
| @@ -0,0 +1,51 @@ |
| +# SPDX-License-Identifier: GPL-2.0-or-later |
| + |
| +# script for Nuvoton NPCX Cortex-M4 Series |
| + |
| +# Adapt based on what transport is active. |
| +source [find target/swj-dp.tcl] |
| + |
| +# Set Chipname |
| +if { [info exists CHIPNAME] } { |
| + set _CHIPNAME $CHIPNAME |
| +} else { |
| + set _CHIPNAME NPCX_M4 |
| +} |
| + |
| +# SWD DAP ID of Nuvoton NPCX Cortex-M4. |
| +if { [info exists CPUDAPID ] } { |
| + set _CPUDAPID $CPUDAPID |
| +} else { |
| + set _CPUDAPID 0x4BA00477 |
| +} |
| + |
| +# Work-area is a space in RAM used for flash programming |
| +# By default use 32kB |
| +if { [info exists WORKAREASIZE] } { |
| + set _WORKAREASIZE $WORKAREASIZE |
| +} else { |
| + set _WORKAREASIZE 0x8000 |
| +} |
| + |
| +# Debug Adapter Target Settings |
| +swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID |
| +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu |
| +set _TARGETNAME $_CHIPNAME.cpu |
| +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap |
| + |
| +$_TARGETNAME configure -work-area-phys 0x200c0000 -work-area-size $_WORKAREASIZE -work-area-backup 0 |
| + |
| +# Initial JTAG/SWD speed |
| +# For safety purposes, set for the lowest cpu clock configuration |
| +# 4MHz / 6 = 666KHz, so use 600KHz for it |
| +adapter speed 600 |
| + |
| +# For safety purposes, set for the lowest cpu clock configuration |
| +$_TARGETNAME configure -event reset-start {adapter speed 600} |
| + |
| +# use sysresetreq to perform a system reset |
| +cortex_m reset_config sysresetreq |
| + |
| +# flash configuration |
| +set _FLASHNAME $_CHIPNAME.flash |
| +flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME |
| -- |
| 2.36.1.476.g0c4daa206d-goog |
| |