ite: drivers/flash: add flash driver for it8xxx2
Add flash driver for it8xxx2. The driver can implement flash read, write and erase that will be mapped to the ram section for executing. TEST="flash write 0x80000 0x10 0x20 0x30 0x40 ..." "flash read 0x80000 0x100" "flash erase 0x80000 0x1000" Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
parent
ab3a207baf
commit
ef3c8507a6
8 changed files with 673 additions and 4 deletions
|
@ -31,3 +31,4 @@ CONFIG_GPIO_ITE_IT8XXX2=y
|
||||||
CONFIG_I2C=y
|
CONFIG_I2C=y
|
||||||
CONFIG_I2C_ITE_IT8XXX2=y
|
CONFIG_I2C_ITE_IT8XXX2=y
|
||||||
CONFIG_ADC_ITE_IT8XXX2=y
|
CONFIG_ADC_ITE_IT8XXX2=y
|
||||||
|
CONFIG_SOC_FLASH_ITE_IT8XXX2=y
|
||||||
|
|
|
@ -6,6 +6,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_NOR spi_nor.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c)
|
zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_FLASH_SIMULATOR flash_simulator.c)
|
zephyr_library_sources_ifdef(CONFIG_FLASH_SIMULATOR flash_simulator.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c)
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RADIO_SYNC_TICKER soc_flash_nrf_ticker.c)
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RADIO_SYNC_TICKER soc_flash_nrf_ticker.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c)
|
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c)
|
||||||
|
|
|
@ -62,6 +62,8 @@ source "drivers/flash/Kconfig.at45"
|
||||||
|
|
||||||
source "drivers/flash/Kconfig.esp32"
|
source "drivers/flash/Kconfig.esp32"
|
||||||
|
|
||||||
|
source "drivers/flash/Kconfig.it8xxx2"
|
||||||
|
|
||||||
source "drivers/flash/Kconfig.nrf"
|
source "drivers/flash/Kconfig.nrf"
|
||||||
|
|
||||||
source "drivers/flash/Kconfig.lpc"
|
source "drivers/flash/Kconfig.lpc"
|
||||||
|
|
20
drivers/flash/Kconfig.it8xxx2
Normal file
20
drivers/flash/Kconfig.it8xxx2
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# FLASH configuration options
|
||||||
|
|
||||||
|
# Copyright (c) 2021 ITE Corporation. All Rights Reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config SOC_FLASH_ITE_IT8XXX2
|
||||||
|
bool "ITE IT8XXX2 flash driver"
|
||||||
|
depends on SOC_FAMILY_RISCV_ITE
|
||||||
|
select SOC_FLASH_RAMCODE_SECTION
|
||||||
|
help
|
||||||
|
The flash driver includes support for read, write and
|
||||||
|
erase flash operations. It also supports protection.
|
||||||
|
The it8xxx2 flash size is 1M byte.
|
||||||
|
|
||||||
|
config SOC_FLASH_RAMCODE_SECTION
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Enable this config to map the __ram_code section
|
||||||
|
operations of flash(flash_it8xxx2_erase,
|
||||||
|
flash_it8xxx2_write, flash_it8xxx2_read) to RAM.
|
597
drivers/flash/flash_ite_it8xxx2.c
Normal file
597
drivers/flash/flash_ite_it8xxx2.c
Normal file
|
@ -0,0 +1,597 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 ITE Corporation. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT ite_it8xxx2_flash_controller
|
||||||
|
#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
|
||||||
|
|
||||||
|
#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size)
|
||||||
|
#define FLASH_ERASE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/flash.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <linker/linker-defs.h>
|
||||||
|
#include <soc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(flash_ite_it8xxx2);
|
||||||
|
|
||||||
|
/* RAM code start address */
|
||||||
|
extern char _ram_code_start;
|
||||||
|
#define FLASH_RAMCODE_START ((uint32_t)&_ram_code_start)
|
||||||
|
#define FLASH_RAMCODE_START_BIT19 BIT(19)
|
||||||
|
/* RAM code section */
|
||||||
|
#define __ram_code __attribute__((section(".__ram_code")))
|
||||||
|
|
||||||
|
#define FLASH_IT8XXX2_REG_BASE \
|
||||||
|
((struct flash_it8xxx2_regs *)DT_INST_REG_ADDR(0))
|
||||||
|
|
||||||
|
#define DEV_DATA(dev) \
|
||||||
|
((struct flash_it8xxx2_dev_data *const)(dev)->data)
|
||||||
|
|
||||||
|
struct flash_it8xxx2_dev_data {
|
||||||
|
struct k_sem sem;
|
||||||
|
int all_protected;
|
||||||
|
int flash_static_cache_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One page program instruction allows maximum 256 bytes (a page) of data
|
||||||
|
* to be programmed.
|
||||||
|
*/
|
||||||
|
#define CHIP_FLASH_WRITE_PAGE_MAX_SIZE 256
|
||||||
|
/* Program is run directly from storage */
|
||||||
|
#define CHIP_MAPPED_STORAGE_BASE DT_REG_ADDR(DT_NODELABEL(flash0))
|
||||||
|
/* flash size */
|
||||||
|
#define CHIP_FLASH_SIZE_BYTES DT_REG_SIZE(DT_NODELABEL(flash0))
|
||||||
|
/* protect bank size */
|
||||||
|
#define CHIP_FLASH_BANK_SIZE 0x00001000
|
||||||
|
/* base+0000h~base+0FFF */
|
||||||
|
#define CHIP_RAMCODE_BASE 0x80100000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the block size of the ILM on the it8xxx2 chip.
|
||||||
|
* The ILM for static code cache, CPU fetch instruction from
|
||||||
|
* ILM(ILM -> CPU)instead of flash(flash -> I-Cache -> CPU) if enabled.
|
||||||
|
*/
|
||||||
|
#define IT8XXX2_ILM_BLOCK_SIZE 0x00001000
|
||||||
|
|
||||||
|
/* page program command */
|
||||||
|
#define FLASH_CMD_PAGE_WRITE 0x2
|
||||||
|
/* ector erase command (erase size is 4KB) */
|
||||||
|
#define FLASH_CMD_SECTOR_ERASE 0x20
|
||||||
|
/* command for flash write */
|
||||||
|
#define FLASH_CMD_WRITE FLASH_CMD_PAGE_WRITE
|
||||||
|
/* Write status register */
|
||||||
|
#define FLASH_CMD_WRSR 0x01
|
||||||
|
/* Write disable */
|
||||||
|
#define FLASH_CMD_WRDI 0x04
|
||||||
|
/* Write enable */
|
||||||
|
#define FLASH_CMD_WREN 0x06
|
||||||
|
/* Read status register */
|
||||||
|
#define FLASH_CMD_RS 0x05
|
||||||
|
|
||||||
|
/* Set FSCE# as high level by writing 0 to address xfff_fe00h */
|
||||||
|
#define FLASH_FSCE_HIGH_ADDRESS 0x0FFFFE00
|
||||||
|
/* Set FSCE# as low level by writing data to address xfff_fd00h */
|
||||||
|
#define FLASH_FSCE_LOW_ADDRESS 0x0FFFFD00
|
||||||
|
|
||||||
|
#define FWP_REG(bank) (bank / 8)
|
||||||
|
#define FWP_MASK(bank) (1 << (bank % 8))
|
||||||
|
|
||||||
|
enum flash_wp_interface {
|
||||||
|
FLASH_WP_HOST = 0x01,
|
||||||
|
FLASH_WP_DBGR = 0x02,
|
||||||
|
FLASH_WP_EC = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum flash_status_mask {
|
||||||
|
FLASH_SR_NO_BUSY = 0,
|
||||||
|
/* Internal write operation is in progress */
|
||||||
|
FLASH_SR_BUSY = 0x01,
|
||||||
|
/* Device is memory Write enabled */
|
||||||
|
FLASH_SR_WEL = 0x02,
|
||||||
|
|
||||||
|
FLASH_SR_ALL = (FLASH_SR_BUSY | FLASH_SR_WEL),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum flash_transaction_cmd {
|
||||||
|
CMD_CONTINUE,
|
||||||
|
CMD_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct flash_parameters flash_it8xxx2_parameters = {
|
||||||
|
.write_block_size = FLASH_WRITE_BLK_SZ,
|
||||||
|
.erase_value = 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
|
void __ram_code ramcode_reset_i_cache(void)
|
||||||
|
{
|
||||||
|
/* I-Cache tag sram reset */
|
||||||
|
IT83XX_GCTRL_MCCR |= IT83XX_GCTRL_ICACHE_RESET;
|
||||||
|
/* Make sure the I-Cache is reset */
|
||||||
|
__asm__ volatile ("fence.i" ::: "memory");
|
||||||
|
|
||||||
|
IT83XX_GCTRL_MCCR &= ~IT83XX_GCTRL_ICACHE_RESET;
|
||||||
|
__asm__ volatile ("fence.i" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_follow_mode(void)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
/*
|
||||||
|
* ECINDAR3-0 are EC-indirect memory address registers.
|
||||||
|
*
|
||||||
|
* Enter follow mode by writing 0xf to low nibble of ECINDAR3 register,
|
||||||
|
* and set high nibble as 0x4 to select internal flash.
|
||||||
|
*/
|
||||||
|
flash_regs->SMFI_ECINDAR3 = (EC_INDIRECT_READ_INTERNAL_FLASH |
|
||||||
|
((FLASH_FSCE_HIGH_ADDRESS >> 24) & GENMASK(3, 0)));
|
||||||
|
|
||||||
|
/* Set FSCE# as high level by writing 0 to address xfff_fe00h */
|
||||||
|
flash_regs->SMFI_ECINDAR2 = (FLASH_FSCE_HIGH_ADDRESS >> 16) & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_ECINDAR1 = (FLASH_FSCE_HIGH_ADDRESS >> 8) & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_ECINDAR0 = FLASH_FSCE_HIGH_ADDRESS & GENMASK(7, 0);
|
||||||
|
|
||||||
|
/* Writing 0 to EC-indirect memory data register */
|
||||||
|
flash_regs->SMFI_ECINDDR = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_follow_mode_exit(void)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
|
||||||
|
/* Exit follow mode, and keep the setting of selecting internal flash */
|
||||||
|
flash_regs->SMFI_ECINDAR3 = EC_INDIRECT_READ_INTERNAL_FLASH;
|
||||||
|
flash_regs->SMFI_ECINDAR2 = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_fsce_high(void)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
|
||||||
|
/* FSCE# high level */
|
||||||
|
flash_regs->SMFI_ECINDAR1 = (FLASH_FSCE_HIGH_ADDRESS >> 8) & GENMASK(7, 0);
|
||||||
|
|
||||||
|
/* Writing 0 to EC-indirect memory data register */
|
||||||
|
flash_regs->SMFI_ECINDDR = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_write_dat(uint8_t wdata)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
|
||||||
|
/* Write data to FMOSI */
|
||||||
|
flash_regs->SMFI_ECINDDR = wdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_transaction(int wlen, uint8_t *wbuf, int rlen,
|
||||||
|
uint8_t *rbuf,
|
||||||
|
enum flash_transaction_cmd cmd_end)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* FSCE# with low level */
|
||||||
|
flash_regs->SMFI_ECINDAR1 = (FLASH_FSCE_LOW_ADDRESS >> 8) & GENMASK(7, 0);
|
||||||
|
/* Write data to FMOSI */
|
||||||
|
for (i = 0; i < wlen; i++) {
|
||||||
|
flash_regs->SMFI_ECINDDR = wbuf[i];
|
||||||
|
}
|
||||||
|
/* Read data from FMISO */
|
||||||
|
for (i = 0; i < rlen; i++) {
|
||||||
|
rbuf[i] = flash_regs->SMFI_ECINDDR;
|
||||||
|
}
|
||||||
|
/* FSCE# high level if transaction done */
|
||||||
|
if (cmd_end == CMD_END) {
|
||||||
|
ramcode_flash_fsce_high();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_cmd_read_status(enum flash_status_mask mask,
|
||||||
|
enum flash_status_mask target)
|
||||||
|
{
|
||||||
|
uint8_t status[1];
|
||||||
|
uint8_t cmd_rs[] = {FLASH_CMD_RS};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We prefer no timeout here. We can always get the status
|
||||||
|
* we want, or wait for watchdog triggered to check
|
||||||
|
* e-flash's status instead of breaking loop.
|
||||||
|
* This will avoid fetching unknown instruction from e-flash
|
||||||
|
* and causing exception.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
/* read status */
|
||||||
|
ramcode_flash_transaction(sizeof(cmd_rs), cmd_rs, 1, status, CMD_END);
|
||||||
|
/* only bit[1:0] valid */
|
||||||
|
if ((status[0] & mask) == target) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_cmd_write_enable(void)
|
||||||
|
{
|
||||||
|
uint8_t cmd_we[] = {FLASH_CMD_WREN};
|
||||||
|
|
||||||
|
/* enter EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode();
|
||||||
|
/* send write enable command */
|
||||||
|
ramcode_flash_transaction(sizeof(cmd_we), cmd_we, 0, NULL, CMD_END);
|
||||||
|
/* read status and make sure busy bit cleared and write enabled. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_ALL, FLASH_SR_WEL);
|
||||||
|
/* exit EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_cmd_write_disable(void)
|
||||||
|
{
|
||||||
|
uint8_t cmd_wd[] = {FLASH_CMD_WRDI};
|
||||||
|
|
||||||
|
/* enter EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode();
|
||||||
|
/* send write disable command */
|
||||||
|
ramcode_flash_transaction(sizeof(cmd_wd), cmd_wd, 0, NULL, CMD_END);
|
||||||
|
/* make sure busy bit cleared. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_ALL, FLASH_SR_NO_BUSY);
|
||||||
|
/* exit EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int __ram_code ramcode_flash_verify(int addr, int size, const char *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t *wbuf = (uint8_t *)data;
|
||||||
|
uint8_t *flash = (uint8_t *)addr;
|
||||||
|
|
||||||
|
/* verify for erase */
|
||||||
|
if (data == NULL) {
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (flash[i] != 0xFF) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* verify for write */
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (flash[i] != wbuf[i]) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_cmd_write(int addr, int wlen, uint8_t *wbuf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t flash_write[] = {FLASH_CMD_WRITE, ((addr >> 16) & 0xFF),
|
||||||
|
((addr >> 8) & 0xFF), (addr & 0xFF)};
|
||||||
|
|
||||||
|
/* enter EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode();
|
||||||
|
/* send flash write command (aai word or page program) */
|
||||||
|
ramcode_flash_transaction(sizeof(flash_write), flash_write, 0, NULL, CMD_CONTINUE);
|
||||||
|
|
||||||
|
for (i = 0; i < wlen; i++) {
|
||||||
|
/* send data byte */
|
||||||
|
ramcode_flash_write_dat(wbuf[i]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we want to restart the write sequence every IDEAL_SIZE
|
||||||
|
* chunk worth of data.
|
||||||
|
*/
|
||||||
|
if (!(++addr % CHIP_FLASH_WRITE_PAGE_MAX_SIZE)) {
|
||||||
|
uint8_t w_en[] = {FLASH_CMD_WREN};
|
||||||
|
|
||||||
|
ramcode_flash_fsce_high();
|
||||||
|
/* make sure busy bit cleared. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_BUSY, FLASH_SR_NO_BUSY);
|
||||||
|
/* send write enable command */
|
||||||
|
ramcode_flash_transaction(sizeof(w_en), w_en, 0, NULL, CMD_END);
|
||||||
|
/* make sure busy bit cleared and write enabled. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_ALL, FLASH_SR_WEL);
|
||||||
|
/* re-send write command */
|
||||||
|
flash_write[1] = (addr >> 16) & GENMASK(7, 0);
|
||||||
|
flash_write[2] = (addr >> 8) & GENMASK(7, 0);
|
||||||
|
flash_write[3] = addr & GENMASK(7, 0);
|
||||||
|
ramcode_flash_transaction(sizeof(flash_write), flash_write,
|
||||||
|
0, NULL, CMD_CONTINUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ramcode_flash_fsce_high();
|
||||||
|
/* make sure busy bit cleared. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_BUSY, FLASH_SR_NO_BUSY);
|
||||||
|
/* exit EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_write(int addr, int wlen, const char *wbuf)
|
||||||
|
{
|
||||||
|
ramcode_flash_cmd_write_enable();
|
||||||
|
ramcode_flash_cmd_write(addr, wlen, (uint8_t *)wbuf);
|
||||||
|
ramcode_flash_cmd_write_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_cmd_erase(int addr, int cmd)
|
||||||
|
{
|
||||||
|
uint8_t cmd_erase[] = {cmd, ((addr >> 16) & 0xFF),
|
||||||
|
((addr >> 8) & 0xFF), (addr & 0xFF)};
|
||||||
|
|
||||||
|
/* enter EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode();
|
||||||
|
/* send erase command */
|
||||||
|
ramcode_flash_transaction(sizeof(cmd_erase), cmd_erase, 0, NULL, CMD_END);
|
||||||
|
/* make sure busy bit cleared. */
|
||||||
|
ramcode_flash_cmd_read_status(FLASH_SR_BUSY, FLASH_SR_NO_BUSY);
|
||||||
|
/* exit EC-indirect follow mode */
|
||||||
|
ramcode_flash_follow_mode_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __ram_code ramcode_flash_erase(int addr, int cmd)
|
||||||
|
{
|
||||||
|
ramcode_flash_cmd_write_enable();
|
||||||
|
ramcode_flash_cmd_erase(addr, cmd);
|
||||||
|
ramcode_flash_cmd_write_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protect flash banks until reboot.
|
||||||
|
*
|
||||||
|
* @param start_bank Start bank to protect
|
||||||
|
* @param bank_count Number of banks to protect
|
||||||
|
*/
|
||||||
|
static void flash_protect_banks(int start_bank, int bank_count,
|
||||||
|
enum flash_wp_interface wp_if)
|
||||||
|
{
|
||||||
|
int bank;
|
||||||
|
|
||||||
|
for (bank = start_bank; bank < start_bank + bank_count; bank++) {
|
||||||
|
if (wp_if & FLASH_WP_EC) {
|
||||||
|
IT83XX_GCTRL_EWPR0PFEC(FWP_REG(bank)) |= FWP_MASK(bank);
|
||||||
|
}
|
||||||
|
if (wp_if & FLASH_WP_HOST) {
|
||||||
|
IT83XX_GCTRL_EWPR0PFH(FWP_REG(bank)) |= FWP_MASK(bank);
|
||||||
|
}
|
||||||
|
if (wp_if & FLASH_WP_DBGR) {
|
||||||
|
IT83XX_GCTRL_EWPR0PFD(FWP_REG(bank)) |= FWP_MASK(bank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read data from flash */
|
||||||
|
static int __ram_code flash_it8xxx2_read(const struct device *dev, off_t offset,
|
||||||
|
void *data, size_t len)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
uint8_t *data_t = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
flash_regs->SMFI_ECINDAR3 = EC_INDIRECT_READ_INTERNAL_FLASH;
|
||||||
|
flash_regs->SMFI_ECINDAR2 = (offset >> 16) & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_ECINDAR1 = (offset >> 8) & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_ECINDAR0 = (offset & GENMASK(7, 0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read/Write to this register will access one byte on the
|
||||||
|
* flash with the 32-bit flash address defined in ECINDAR3-0
|
||||||
|
*/
|
||||||
|
data_t[i] = flash_regs->SMFI_ECINDDR;
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to the flash, page by page */
|
||||||
|
static int __ram_code flash_it8xxx2_write(const struct device *dev, off_t offset,
|
||||||
|
const void *src_data, size_t len)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_dev_data *data = DEV_DATA(dev);
|
||||||
|
int ret = -EINVAL;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the offset and length are multiples of the write
|
||||||
|
* block size.
|
||||||
|
*/
|
||||||
|
if ((offset % FLASH_WRITE_BLK_SZ) != 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if ((len % FLASH_WRITE_BLK_SZ) != 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (data->flash_static_cache_enabled == 0) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
if (data->all_protected) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
/*
|
||||||
|
* CPU can't fetch instruction from flash while use
|
||||||
|
* EC-indirect follow mode to access flash, interrupts need to be
|
||||||
|
* disabled.
|
||||||
|
*/
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
ramcode_flash_write(offset, len, src_data);
|
||||||
|
ramcode_reset_i_cache();
|
||||||
|
/* Get the ILM address of a flash offset. */
|
||||||
|
offset |= CHIP_MAPPED_STORAGE_BASE;
|
||||||
|
ret = ramcode_flash_verify(offset, len, src_data);
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Erase multiple blocks */
|
||||||
|
static int __ram_code flash_it8xxx2_erase(const struct device *dev,
|
||||||
|
off_t offset, size_t len)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_dev_data *data = DEV_DATA(dev);
|
||||||
|
int v_size = len, v_addr = offset, ret = -EINVAL;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the offset and length are multiples of the write
|
||||||
|
* erase block size.
|
||||||
|
*/
|
||||||
|
if ((offset % FLASH_ERASE_BLK_SZ) != 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if ((len % FLASH_ERASE_BLK_SZ) != 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (data->flash_static_cache_enabled == 0) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
if (data->all_protected) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
/*
|
||||||
|
* CPU can't fetch instruction from flash while use
|
||||||
|
* EC-indirect follow mode to access flash, interrupts need to be
|
||||||
|
* disabled.
|
||||||
|
*/
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
/* Always use sector erase command */
|
||||||
|
for (; len > 0; len -= FLASH_ERASE_BLK_SZ) {
|
||||||
|
ramcode_flash_erase(offset, FLASH_CMD_SECTOR_ERASE);
|
||||||
|
offset += FLASH_ERASE_BLK_SZ;
|
||||||
|
}
|
||||||
|
ramcode_reset_i_cache();
|
||||||
|
/* get the ILM address of a flash offset. */
|
||||||
|
v_addr |= CHIP_MAPPED_STORAGE_BASE;
|
||||||
|
ret = ramcode_flash_verify(v_addr, v_size, NULL);
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable or disable the write protection */
|
||||||
|
static int flash_it8xxx2_write_protection(const struct device *dev,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_dev_data *data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
/* Protect the entire flash */
|
||||||
|
flash_protect_banks(0, CHIP_FLASH_SIZE_BYTES /
|
||||||
|
CHIP_FLASH_BANK_SIZE, FLASH_WP_EC);
|
||||||
|
data->all_protected = 1;
|
||||||
|
} else {
|
||||||
|
data->all_protected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bit[0], eflash protect lock register which can only be write 1 and
|
||||||
|
* only be cleared by power-on reset.
|
||||||
|
*/
|
||||||
|
IT83XX_GCTRL_EPLR |= IT83XX_GCTRL_EPLR_ENABLE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct flash_parameters *
|
||||||
|
flash_it8xxx2_get_parameters(const struct device *dev)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
|
return &flash_it8xxx2_parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flash_code_static_cache(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
struct flash_it8xxx2_dev_data *data = DEV_DATA(dev);
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
/* Make sure no interrupt while enable static cache */
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
/* invalid static cache first */
|
||||||
|
IT83XX_GCTRL_RVILMCR0 &= ~ILMCR_ILM0_ENABLE;
|
||||||
|
|
||||||
|
flash_regs->SMFI_SCAR0H = IT8XXX2_SMFI_SCAR0H_ENABLE;
|
||||||
|
|
||||||
|
memcpy((void *)CHIP_RAMCODE_BASE, (const void *)FLASH_RAMCODE_START,
|
||||||
|
IT8XXX2_ILM_BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* RISCV ILM 0 Enable */
|
||||||
|
IT83XX_GCTRL_RVILMCR0 |= ILMCR_ILM0_ENABLE;
|
||||||
|
|
||||||
|
/* Enable ILM */
|
||||||
|
flash_regs->SMFI_SCAR0L = FLASH_RAMCODE_START & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_SCAR0M = (FLASH_RAMCODE_START >> 8) & GENMASK(7, 0);
|
||||||
|
flash_regs->SMFI_SCAR0H = (FLASH_RAMCODE_START >> 16) & GENMASK(2, 0);
|
||||||
|
|
||||||
|
if (FLASH_RAMCODE_START & FLASH_RAMCODE_START_BIT19) {
|
||||||
|
flash_regs->SMFI_SCAR0H |= IT8XXX2_SMFI_SC0A19;
|
||||||
|
} else {
|
||||||
|
flash_regs->SMFI_SCAR0H &= ~IT8XXX2_SMFI_SC0A19;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->flash_static_cache_enabled = 0x01;
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flash_it8xxx2_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct flash_it8xxx2_regs *const flash_regs = FLASH_IT8XXX2_REG_BASE;
|
||||||
|
struct flash_it8xxx2_dev_data *data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
/* By default, select internal flash for indirect fast read. */
|
||||||
|
flash_regs->SMFI_ECINDAR3 = EC_INDIRECT_READ_INTERNAL_FLASH;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the embedded flash's size of this part number is larger
|
||||||
|
* than 256K-byte, enable the page program cycle constructed
|
||||||
|
* by EC-Indirect Follow Mode.
|
||||||
|
*/
|
||||||
|
flash_regs->SMFI_FLHCTRL6R |= IT8XXX2_SMFI_MASK_ECINDPP;
|
||||||
|
|
||||||
|
/* Initialize mutex for flash controller */
|
||||||
|
k_sem_init(&data->sem, 1, 1);
|
||||||
|
|
||||||
|
flash_code_static_cache(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct flash_driver_api flash_it8xxx2_api = {
|
||||||
|
.write_protection = flash_it8xxx2_write_protection,
|
||||||
|
.erase = flash_it8xxx2_erase,
|
||||||
|
.write = flash_it8xxx2_write,
|
||||||
|
.read = flash_it8xxx2_read,
|
||||||
|
.get_parameters = flash_it8xxx2_get_parameters,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct flash_it8xxx2_dev_data flash_it8xxx2_data;
|
||||||
|
|
||||||
|
DEVICE_DT_INST_DEFINE(0, flash_it8xxx2_init, NULL,
|
||||||
|
&flash_it8xxx2_data, NULL,
|
||||||
|
PRE_KERNEL_1,
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||||
|
&flash_it8xxx2_api);
|
|
@ -30,9 +30,9 @@
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
ranges;
|
ranges;
|
||||||
|
|
||||||
flashctrl: flash-controller@80000000 {
|
flashctrl: flash-controller@f01000 {
|
||||||
compatible = "ite,it8xxx2-flash-controller";
|
compatible = "ite,it8xxx2-flash-controller";
|
||||||
reg = <0x80000000 0x100>;
|
reg = <0x00f01000 0x100>;
|
||||||
label = "fspi";
|
label = "fspi";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
@ -226,9 +226,9 @@
|
||||||
0 0 0 0 >;
|
0 0 0 0 >;
|
||||||
#pinctrl-cells = <2>;
|
#pinctrl-cells = <2>;
|
||||||
};
|
};
|
||||||
sram0: memory@80100000 {
|
sram0: memory@80101000 {
|
||||||
compatible = "mmio-sram";
|
compatible = "mmio-sram";
|
||||||
reg = <0x80100000 DT_SIZE_K(60)>;
|
reg = <0x80101000 DT_SIZE_K(56)>;
|
||||||
};
|
};
|
||||||
intc: interrupt-controller@f03f00 {
|
intc: interrupt-controller@f03f00 {
|
||||||
#interrupt-cells = <2>;
|
#interrupt-cells = <2>;
|
||||||
|
|
|
@ -140,6 +140,14 @@ SECTIONS
|
||||||
*(".text.*")
|
*(".text.*")
|
||||||
*(.gnu.linkonce.t.*)
|
*(.gnu.linkonce.t.*)
|
||||||
#include <linker/kobject-text.ld>
|
#include <linker/kobject-text.ld>
|
||||||
|
#ifdef CONFIG_SOC_FLASH_RAMCODE_SECTION
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
_ram_code_start = .;
|
||||||
|
KEEP(*(.__ram_code))
|
||||||
|
__ram_code_size = . - _ram_code_start;
|
||||||
|
ASSERT((__ram_code_size <= 0x1000),
|
||||||
|
"__ram_code_size <= 4k bytes");
|
||||||
|
#endif
|
||||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||||
|
|
||||||
_image_text_end = .;
|
_image_text_end = .;
|
||||||
|
|
|
@ -1672,6 +1672,44 @@ struct wdt_it8xxx2_regs {
|
||||||
#define CE_RNG ECREG(EC_REG_BASE_ADDR + 0x3C20)
|
#define CE_RNG ECREG(EC_REG_BASE_ADDR + 0x3C20)
|
||||||
|
|
||||||
|
|
||||||
|
/* Shared Memory Flash Interface Bridge (SMFI) registers */
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
struct flash_it8xxx2_regs {
|
||||||
|
volatile uint8_t reserved1[59];
|
||||||
|
/* 0x3B: EC-Indirect memory address 0 */
|
||||||
|
volatile uint8_t SMFI_ECINDAR0;
|
||||||
|
/* 0x3C: EC-Indirect memory address 1 */
|
||||||
|
volatile uint8_t SMFI_ECINDAR1;
|
||||||
|
/* 0x3D: EC-Indirect memory address 2 */
|
||||||
|
volatile uint8_t SMFI_ECINDAR2;
|
||||||
|
/* 0x3E: EC-Indirect memory address 3 */
|
||||||
|
volatile uint8_t SMFI_ECINDAR3;
|
||||||
|
/* 0x3F: EC-Indirect memory data */
|
||||||
|
volatile uint8_t SMFI_ECINDDR;
|
||||||
|
/* 0x40: Scratch SRAM 0 address low byte */
|
||||||
|
volatile uint8_t SMFI_SCAR0L;
|
||||||
|
/* 0x41: Scratch SRAM 0 address middle byte */
|
||||||
|
volatile uint8_t SMFI_SCAR0M;
|
||||||
|
/* 0x42: Scratch SRAM 0 address high byte */
|
||||||
|
volatile uint8_t SMFI_SCAR0H;
|
||||||
|
volatile uint8_t reserved2[95];
|
||||||
|
/* 0xA2: Flash control 6 */
|
||||||
|
volatile uint8_t SMFI_FLHCTRL6R;
|
||||||
|
};
|
||||||
|
#endif /* !__ASSEMBLER__ */
|
||||||
|
|
||||||
|
/* SMFI register fields */
|
||||||
|
|
||||||
|
/* EC-Indirect read internal flash */
|
||||||
|
#define EC_INDIRECT_READ_INTERNAL_FLASH BIT(6)
|
||||||
|
/* Enable EC-indirect page program command */
|
||||||
|
#define IT8XXX2_SMFI_MASK_ECINDPP BIT(3)
|
||||||
|
/* Scratch SRAM 0 address(BIT(19)) */
|
||||||
|
#define IT8XXX2_SMFI_SC0A19 BIT(7)
|
||||||
|
/* Scratch SRAM enable */
|
||||||
|
#define IT8XXX2_SMFI_SCAR0H_ENABLE BIT(3)
|
||||||
|
|
||||||
/* --- GPIO --- */
|
/* --- GPIO --- */
|
||||||
#define IT8XXX2_GPIO_BASE 0x00F01600
|
#define IT8XXX2_GPIO_BASE 0x00F01600
|
||||||
#define IT8XXX2_GPIO2_BASE 0x00F03E00
|
#define IT8XXX2_GPIO2_BASE 0x00F03E00
|
||||||
|
@ -1829,9 +1867,11 @@ struct adc_it8xxx2_regs {
|
||||||
#define IT83XX_GCTRL_SPISLVPFE BIT(6)
|
#define IT83XX_GCTRL_SPISLVPFE BIT(6)
|
||||||
#define IT83XX_GCTRL_RSTC5 ECREG(IT83XX_GCTRL_BASE + 0x21)
|
#define IT83XX_GCTRL_RSTC5 ECREG(IT83XX_GCTRL_BASE + 0x21)
|
||||||
#define IT83XX_GCTRL_MCCR ECREG(IT83XX_GCTRL_BASE + 0x30)
|
#define IT83XX_GCTRL_MCCR ECREG(IT83XX_GCTRL_BASE + 0x30)
|
||||||
|
#define IT83XX_GCTRL_ICACHE_RESET BIT(4)
|
||||||
#define IT83XX_GCTRL_PMER1 ECREG(IT83XX_GCTRL_BASE + 0x32)
|
#define IT83XX_GCTRL_PMER1 ECREG(IT83XX_GCTRL_BASE + 0x32)
|
||||||
#define IT83XX_GCTRL_PMER2 ECREG(IT83XX_GCTRL_BASE + 0x33)
|
#define IT83XX_GCTRL_PMER2 ECREG(IT83XX_GCTRL_BASE + 0x33)
|
||||||
#define IT83XX_GCTRL_EPLR ECREG(IT83XX_GCTRL_BASE + 0x37)
|
#define IT83XX_GCTRL_EPLR ECREG(IT83XX_GCTRL_BASE + 0x37)
|
||||||
|
#define IT83XX_GCTRL_EPLR_ENABLE BIT(0)
|
||||||
#define IT83XX_GCTRL_IVTBAR ECREG(IT83XX_GCTRL_BASE + 0x41)
|
#define IT83XX_GCTRL_IVTBAR ECREG(IT83XX_GCTRL_BASE + 0x41)
|
||||||
#define IT83XX_GCTRL_MCCR2 ECREG(IT83XX_GCTRL_BASE + 0x44)
|
#define IT83XX_GCTRL_MCCR2 ECREG(IT83XX_GCTRL_BASE + 0x44)
|
||||||
#define IT83XX_GCTRL_PIN_MUX0 ECREG(IT83XX_GCTRL_BASE + 0x46)
|
#define IT83XX_GCTRL_PIN_MUX0 ECREG(IT83XX_GCTRL_BASE + 0x46)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue