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>
This commit is contained in:
Wealian Liao 2020-11-26 10:25:09 +08:00 committed by Oleksij Rempel
parent a098816a65
commit 385eedfc6f
12 changed files with 1332 additions and 0 deletions

View File

@ -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

View File

@ -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,

View File

@ -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");
}

View File

@ -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 */

View File

@ -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
}

View File

@ -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 */

View 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.

View 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 \

View 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,

524
src/flash/nor/npcx.c Normal file
View File

@ -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,
};

8
tcl/board/npcx_evb.cfg Normal file
View File

@ -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]

51
tcl/target/npcx.cfg Normal file
View File

@ -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