flash/nor: add support for Nuvoton NPCX series flash 50/5950/17
authorWealian Liao <WHLIAO@nuvoton.com>
Thu, 26 Nov 2020 02:25:09 +0000 (10:25 +0800)
committerOleksij Rempel <linux@rempel-privat.de>
Thu, 2 Sep 2021 06:42:54 +0000 (06:42 +0000)
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>
12 files changed:
contrib/loaders/flash/npcx/Makefile [new file with mode: 0644]
contrib/loaders/flash/npcx/npcx_algo.inc [new file with mode: 0644]
contrib/loaders/flash/npcx/npcx_flash.c [new file with mode: 0644]
contrib/loaders/flash/npcx/npcx_flash.h [new file with mode: 0644]
contrib/loaders/flash/npcx/npcx_flash.lds [new file with mode: 0644]
contrib/loaders/flash/npcx/npcx_flash_config.h [new file with mode: 0644]
doc/openocd.texi
src/flash/nor/Makefile.am
src/flash/nor/drivers.c
src/flash/nor/npcx.c [new file with mode: 0644]
tcl/board/npcx_evb.cfg [new file with mode: 0644]
tcl/target/npcx.cfg [new file with mode: 0644]

diff --git a/contrib/loaders/flash/npcx/Makefile b/contrib/loaders/flash/npcx/Makefile
new file mode 100644 (file)
index 0000000..293bd02
--- /dev/null
@@ -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 (file)
index 0000000..4312fdb
--- /dev/null
@@ -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 (file)
index 0000000..d60624a
--- /dev/null
@@ -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 (file)
index 0000000..cc4f1ad
--- /dev/null
@@ -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 (file)
index 0000000..0d78252
--- /dev/null
@@ -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 (file)
index 0000000..9ec1c5e
--- /dev/null
@@ -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 */
index 2759a39d33041e760c6adfa3c61379fd8c14f586..9c94c7168e98ddf98a16e28bd6635dc40a7d49f8 100644 (file)
@@ -6777,6 +6777,17 @@ Show information about flash driver.
 
 @end deffn
 
+@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.
index 5326704369e02e9ffc2c16cd82e7a517ee68ed9c..a5ef422104428dd2630c237721ea371526e23207 100644 (file)
@@ -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 \
index 6eadc756b31497391ac28a3aecf96fb9bb318692..3e35c0954dbb323b63eb8bd68658e0a3d795931f 100644 (file)
@@ -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;
@@ -130,6 +131,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 (file)
index 0000000..af623e5
--- /dev/null
@@ -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 (file)
index 0000000..4f28bc9
--- /dev/null
@@ -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 (file)
index 0000000..1a21e1f
--- /dev/null
@@ -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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)