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:
parent
a098816a65
commit
385eedfc6f
|
@ -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
|
|
@ -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,
|
|
@ -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");
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
||||||
|
}
|
|
@ -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 */
|
|
@ -6777,6 +6777,17 @@ Show information about flash driver.
|
||||||
|
|
||||||
@end deffn
|
@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}
|
@deffn {Flash Driver} {nrf5}
|
||||||
All members of the nRF51 microcontroller families from Nordic Semiconductor
|
All members of the nRF51 microcontroller families from Nordic Semiconductor
|
||||||
include internal flash and use ARM Cortex-M0 core.
|
include internal flash and use ARM Cortex-M0 core.
|
||||||
|
|
|
@ -44,6 +44,7 @@ NOR_DRIVERS = \
|
||||||
%D%/mrvlqspi.c \
|
%D%/mrvlqspi.c \
|
||||||
%D%/niietcm4.c \
|
%D%/niietcm4.c \
|
||||||
%D%/non_cfi.c \
|
%D%/non_cfi.c \
|
||||||
|
%D%/npcx.c \
|
||||||
%D%/nrf5.c \
|
%D%/nrf5.c \
|
||||||
%D%/numicro.c \
|
%D%/numicro.c \
|
||||||
%D%/ocl.c \
|
%D%/ocl.c \
|
||||||
|
|
|
@ -56,6 +56,7 @@ extern const struct flash_driver mdr_flash;
|
||||||
extern const struct flash_driver mrvlqspi_flash;
|
extern const struct flash_driver mrvlqspi_flash;
|
||||||
extern const struct flash_driver msp432_flash;
|
extern const struct flash_driver msp432_flash;
|
||||||
extern const struct flash_driver niietcm4_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 nrf5_flash;
|
||||||
extern const struct flash_driver nrf51_flash;
|
extern const struct flash_driver nrf51_flash;
|
||||||
extern const struct flash_driver numicro_flash;
|
extern const struct flash_driver numicro_flash;
|
||||||
|
@ -130,6 +131,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&mrvlqspi_flash,
|
&mrvlqspi_flash,
|
||||||
&msp432_flash,
|
&msp432_flash,
|
||||||
&niietcm4_flash,
|
&niietcm4_flash,
|
||||||
|
&npcx_flash,
|
||||||
&nrf5_flash,
|
&nrf5_flash,
|
||||||
&nrf51_flash,
|
&nrf51_flash,
|
||||||
&numicro_flash,
|
&numicro_flash,
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
|
@ -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]
|
|
@ -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
|
Loading…
Reference in New Issue