diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 5de788d80a84d..96bf7501e9c26 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -49,6 +49,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc2 zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC23X0 soc_flash_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT51XXX_M1K flash_ite_it51xxx_m1k.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_LPC soc_flash_lpc.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MAX32 flash_max32.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 758a43287a20f..54e2cba5fa734 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -176,6 +176,7 @@ source "drivers/flash/Kconfig.esp32" source "drivers/flash/Kconfig.gd32" source "drivers/flash/Kconfig.gecko" source "drivers/flash/Kconfig.ifx_cat1" +source "drivers/flash/Kconfig.it51xxx_m1k" source "drivers/flash/Kconfig.it8xxx2" source "drivers/flash/Kconfig.lpc" source "drivers/flash/Kconfig.max32" diff --git a/drivers/flash/Kconfig.it51xxx_m1k b/drivers/flash/Kconfig.it51xxx_m1k new file mode 100644 index 0000000000000..f55f0d8c2873c --- /dev/null +++ b/drivers/flash/Kconfig.it51xxx_m1k @@ -0,0 +1,14 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FLASH_ITE_IT51XXX_M1K + bool "ITE IT51XXX manual flash 1k driver" + default y + depends on DT_HAS_ITE_IT51XXX_MANUAL_FLASH_1K_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select PINCTRL + help + The flash M1K driver supports read (up to 1K), write (1K), and erase (4K) + operations. Accessible flash regions include internal e-Flash or external + SPI flash via FSCE# or FSCE1# diff --git a/drivers/flash/flash_ite_it51xxx_m1k.c b/drivers/flash/flash_ite_it51xxx_m1k.c new file mode 100644 index 0000000000000..5b4932a990852 --- /dev/null +++ b/drivers/flash/flash_ite_it51xxx_m1k.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2025 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it51xxx_manual_flash_1k + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(flash_ite_it51xxx, CONFIG_FLASH_LOG_LEVEL); + +#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#define FLASH_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE) +#define FLASH_READ_MAX_SZ KB(1) +#define FLASH_WRITE_MAX_SZ KB(1) +#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) + +/* it51xxx SMFI registers definition */ +#define IT51XXX_M1K_REGS_BASE DT_INST_REG_ADDR_BY_IDX(0, 0) +#define IT51XXX_SMFI_REGS_BASE DT_INST_REG_ADDR_BY_IDX(0, 1) + +/* 0x63: Flash Control Register 3 */ +#define SMFI_FLHCTRL3R (IT51XXX_SMFI_REGS_BASE + 0x63) +#define SIFE BIT(3) +#define FFSPITRI BIT(0) +/* 0x64: Flash Control Register 4 */ +#define SMFI_FLHCTRL4R (IT51XXX_SMFI_REGS_BASE + 0x64) +#define EN2FLH BIT(7) +/* 0xa6: Manual Flash 1K Command Control 1 */ +#define SMFI_M1KFLHCTRL1 (IT51XXX_M1K_REGS_BASE + 0x00) +#define W1S_M1K_PE BIT(1) +#define W1S_READ BIT(0) +/* 0xa8: Manual Flash 1K Command Control 3 */ +#define SMFI_M1KFLHCTRL3 (IT51XXX_M1K_REGS_BASE + 0x02) +#define M1KPHY BIT(5) +/* 0xa9: Manual Flash 1K Command Control 4 */ +#define SMFI_M1KFLHCTRL4 (IT51XXX_M1K_REGS_BASE + 0x03) +/* 0xaa: Manual Flash 1K Command Control 5 */ +#define SMFI_M1KFLHCTRL5 (IT51XXX_M1K_REGS_BASE + 0x04) +#define M1K_READ_CMD(n) FIELD_PREP(GENMASK(7, 6), n) +#define M1K_READ 0x01 +#define M1K_FETCH 0x02 +#define M1K_SFDP 0x03 +#define M1K_READ_BCNT(n) FIELD_PREP(GENMASK(1, 0), n) +/* 0xab: Manual Flash 1K Command Control 6 */ +#define SMFI_M1KFLHCTRL6 (IT51XXX_M1K_REGS_BASE + 0x05) +/* 0xb9: Manual Flash 1K Command Control 7 */ +#define SMFI_M1KFLHCTRL7 (IT51XXX_M1K_REGS_BASE + 0x13) +#define M1K_PE_CMD(n) FIELD_PREP(GENMASK(7, 6), n) +#define M1K_PROG 0x01 +#define M1K_ERASE 0x02 +#define M1K_PROG_BCNT(n) FIELD_PREP(GENMASK(1, 0), n) +/* 0xac: M1K DLM BASE Address Byte 0 */ +#define SMFI_M1K_DLM_BA0 (IT51XXX_M1K_REGS_BASE + 0x06) +/* 0xad: M1K DLM BASE Address Byte 1 */ +#define SMFI_M1K_DLM_BA1 (IT51XXX_M1K_REGS_BASE + 0x07) +/* 0xae: M1K DLM BASE Address Byte 2 */ +#define SMFI_M1K_DLM_BA2 (IT51XXX_M1K_REGS_BASE + 0x08) +/* 0xaf: M1K Status Register 1 */ +#define SMFI_M1KSTS1 (IT51XXX_M1K_REGS_BASE + 0x09) +/* 0xbc: M1K Status Register 2 */ +#define SMFI_M1KSTS2 (IT51XXX_M1K_REGS_BASE + 0x16) +enum m1ksts2 { + DMA_FETCH_CYC = 3, + M1K_READ_DUTY, + M1K_RESERVED, + M1K_PE_CYC, +}; +/* 0xd0: M1K-PROG/M1K-ERASE Lower Bound Address Byte 0 */ +#define SMFI_M1K_PE_LBA0 (IT51XXX_M1K_REGS_BASE + 0x2a) +/* 0xd1: M1K-PROG/M1K-ERASE Lower Bound Address Byte 1 */ +#define SMFI_M1K_PE_LBA1 (IT51XXX_M1K_REGS_BASE + 0x2b) +/* 0xd2: M1K-PROG/M1K-ERASE Lower Bound Address Byte 2 */ +#define SMFI_M1K_PE_LBA2 (IT51XXX_M1K_REGS_BASE + 0x2c) +/* 0xd3: M1K-PROG/M1K-ERASE Lower Bound Address Byte 3 */ +#define SMFI_M1K_PE_LBA3 (IT51XXX_M1K_REGS_BASE + 0x2d) +#define M1K_PE_SEL_FSPI BIT(7) +#define M1K_PE_SEL_FSCE1 BIT(6) +/* 0xd5: M1K-ERASE Upper Bound Address Byte 1 */ +#define SMFI_M1K_ERASE_UBA1 (IT51XXX_M1K_REGS_BASE + 0x2f) +#define M1K_ERASE_UBA(n) FIELD_PREP(GENMASK(7, 2), n) +/* 0xd6: M1K-ERASE Lower Bound Address Byte 2 */ +#define SMFI_M1K_ERASE_UBA2 (IT51XXX_M1K_REGS_BASE + 0x30) +/* 0xd7: M1K-ERASE Lower Bound Address Byte 3 */ +#define SMFI_M1K_ERASE_UBA3 (IT51XXX_M1K_REGS_BASE + 0x31) +/* 0xd8: M1K-READ Lower Bound Address Byte 0 */ +#define SMFI_M1K_READ_LBA0 (IT51XXX_M1K_REGS_BASE + 0x32) +/* 0xd9: M1K-READ Lower Bound Address Byte 1 */ +#define SMFI_M1K_READ_LBA1 (IT51XXX_M1K_REGS_BASE + 0x33) +/* 0xda: M1K-READ Lower Bound Address Byte 2 */ +#define SMFI_M1K_READ_LBA2 (IT51XXX_M1K_REGS_BASE + 0x34) +/* 0xdb: M1K-READ Lower Bound Address Byte 3 */ +#define SMFI_M1K_READ_LBA3 (IT51XXX_M1K_REGS_BASE + 0x35) +#define M1K_READ_SEL_FSPI BIT(7) +#define M1K_READ_SEL_FSCE1 BIT(6) + +#define M1K_READ_BCNT_MASK GENMASK(9, 0) +#define M1K_PROG_BCNT_MASK GENMASK(9, 0) + +enum flash_select { + INTERNAL, + EXTERNAL_FSPI_CS0, + EXTERNAL_FSPI_CS1, +}; + +struct flash_it51xxx_dev_data { + struct k_sem sem; +}; + +struct flash_it51xxx_config { + const struct pinctrl_dev_config *pcfg; + enum flash_select m1k_sel_access_flash; +}; + +static bool is_valid_range(off_t offset, uint32_t len) +{ + return (offset >= 0) && ((offset + len) <= FLASH_SIZE); +} + +static void flash_set_m1k_read_lba(const struct device *dev, uint32_t lb_addr) +{ + uint8_t m1k_pe_lba3_value; + + m1k_pe_lba3_value = sys_read8(SMFI_M1K_READ_LBA3); + /* Start address of M1K-READ[27:24] */ + sys_write8(m1k_pe_lba3_value | FIELD_GET(GENMASK(27, 24), lb_addr), SMFI_M1K_READ_LBA3); + /* Start address of M1K-READ[23:16] */ + sys_write8(FIELD_GET(GENMASK(23, 16), lb_addr), SMFI_M1K_READ_LBA2); + /* Start address of M1K-READ[15:8] */ + sys_write8(FIELD_GET(GENMASK(15, 8), lb_addr), SMFI_M1K_READ_LBA1); + /* Start address of M1K-READ[7:0] */ + sys_write8(FIELD_GET(GENMASK(7, 0), lb_addr), SMFI_M1K_READ_LBA0); +} + +static void flash_set_m1k_pe_lba(const struct device *dev, uint32_t lb_addr) +{ + uint8_t m1k_pe_lba3_value; + + m1k_pe_lba3_value = sys_read8(SMFI_M1K_PE_LBA3); + /* Start address of M1K-PROG / Lower bound address of M1K-ERASE[27:24] */ + sys_write8(m1k_pe_lba3_value | FIELD_GET(GENMASK(27, 24), lb_addr), SMFI_M1K_PE_LBA3); + /* Start address of M1K-PROG / Lower bound address of M1K-ERASE[23:16] */ + sys_write8(FIELD_GET(GENMASK(23, 16), lb_addr), SMFI_M1K_PE_LBA2); + /* Start address of M1K-PROG / Lower bound address of M1K-ERASE[15:8] */ + sys_write8(FIELD_GET(GENMASK(15, 8), lb_addr), SMFI_M1K_PE_LBA1); + /* Start address of M1K-PROG / Lower bound address of M1K-ERASE[7:0] */ + sys_write8(FIELD_GET(GENMASK(7, 0), lb_addr), SMFI_M1K_PE_LBA0); +} + +static void flash_set_m1k_erase_uba(const struct device *dev, uint32_t ub_addr) +{ + /* Upper bound address of M1K-ERASE[27:24] */ + sys_write8(FIELD_GET(GENMASK(27, 24), ub_addr), SMFI_M1K_ERASE_UBA3); + /* Upper bound address of M1K-ERASE[23:16] */ + sys_write8(FIELD_GET(GENMASK(23, 16), ub_addr), SMFI_M1K_ERASE_UBA2); + /* Upper bound address of M1K-ERASE[15:10] */ + sys_write8(M1K_ERASE_UBA(FIELD_GET(GENMASK(15, 10), ub_addr)), SMFI_M1K_ERASE_UBA1); +} + +static void flash_set_m1k_dlm_ba(const struct device *dev, uint32_t dlm_addr) +{ + /* M1K DLM base address[17:16] */ + sys_write8(FIELD_GET(GENMASK(17, 16), dlm_addr), SMFI_M1K_DLM_BA2); + /* M1K DLM base address[15:8] */ + sys_write8(FIELD_GET(GENMASK(15, 8), dlm_addr), SMFI_M1K_DLM_BA1); + /* M1K DLM base address[7:0] */ + sys_write8(FIELD_GET(GENMASK(7, 0), dlm_addr), SMFI_M1K_DLM_BA0); +} + +static int flash_wait_status(const struct device *dev, enum m1ksts2 state) +{ + /* Waiting for M1K-READ to complete */ + if (WAIT_FOR(!IS_BIT_SET(sys_read8(SMFI_M1KSTS2), state), INT_MAX, NULL) == false) { + LOG_ERR("%s: Timeout waiting for status", __func__); + + return -ETIMEDOUT; + } + + return 0; +} + +static int m1k_flash_read(const struct device *dev, off_t offset, const void *dst_data, size_t len) +{ + int ret; + uint16_t count; + uint8_t m1kflhctrl5_cmd; + + /* It's the start address of M1K-READ */ + flash_set_m1k_read_lba(dev, offset); + + /* M1K DLM base address */ + flash_set_m1k_dlm_ba(dev, (uint32_t)dst_data); + + /* M1k-READ size (Maximum 1024 bytes) */ + count = (len - 1) & M1K_READ_BCNT_MASK; + + m1kflhctrl5_cmd = sys_read8(SMFI_M1KFLHCTRL5) & ~GENMASK(1, 0); + /* M1K-READ byte count[9:8] */ + sys_write8(m1kflhctrl5_cmd | M1K_READ_BCNT(FIELD_GET(GENMASK(9, 8), count)), + SMFI_M1KFLHCTRL5); + /* M1K-READ byte count[7:0] */ + sys_write8(FIELD_GET(GENMASK(7, 0), count), SMFI_M1KFLHCTRL4); + + m1kflhctrl5_cmd = sys_read8(SMFI_M1KFLHCTRL5) & ~GENMASK(7, 6); + /* Read data from the flash to DLM */ + sys_write8(m1kflhctrl5_cmd | M1K_READ_CMD(M1K_READ), SMFI_M1KFLHCTRL5); + + /* Write-1-Start M1K-READ */ + sys_write8(W1S_READ, SMFI_M1KFLHCTRL1); + ret = flash_wait_status(dev, M1K_READ_DUTY); + + /* Reset the M1K setting and counter to 0 */ + sys_write8(0, SMFI_M1KFLHCTRL4); + sys_write8(0, SMFI_M1KFLHCTRL5); + + return ret; +} + +static int m1k_flash_write(const struct device *dev, off_t offset, const void *src_data, size_t len) +{ + int ret; + uint16_t count; + uint8_t m1kflhctrl7_cmd; + + /* It's the start address of M1K-PROG */ + flash_set_m1k_pe_lba(dev, offset); + + /* M1K DLM base address */ + flash_set_m1k_dlm_ba(dev, (uint32_t)src_data); + + /* M1k-PROG size (Maximum 1024 bytes) */ + count = (len - 1) & M1K_PROG_BCNT_MASK; + + m1kflhctrl7_cmd = sys_read8(SMFI_M1KFLHCTRL7) & ~GENMASK(1, 0); + /* M1K-PROG byte count[9:8] */ + sys_write8(m1kflhctrl7_cmd | M1K_PROG_BCNT(FIELD_GET(GENMASK(9, 8), count)), + SMFI_M1KFLHCTRL7); + /* M1K-PROG byte count[7:0] */ + sys_write8(FIELD_GET(GENMASK(7, 0), count), SMFI_M1KFLHCTRL6); + + m1kflhctrl7_cmd = sys_read8(SMFI_M1KFLHCTRL7) & ~GENMASK(7, 6); + /* Copy byte count data from the DLM to flash */ + sys_write8(m1kflhctrl7_cmd | M1K_PE_CMD(M1K_PROG), SMFI_M1KFLHCTRL7); + + /* Write-1-Start M1K-PROG/M1K-ERASE */ + sys_write8(W1S_M1K_PE, SMFI_M1KFLHCTRL1); + ret = flash_wait_status(dev, M1K_PE_CYC); + + /* Reset counter to 0 */ + sys_write8(0, SMFI_M1KFLHCTRL6); + sys_write8(0, SMFI_M1KFLHCTRL7); + + return ret; +} + +static int m1k_flash_erase(const struct device *dev, off_t offset, size_t len) +{ + int ret; + uint8_t m1kflhctrl7_cmd; + + /* It's the lower bound address of M1K-ERASE */ + flash_set_m1k_pe_lba(dev, offset); + + /* It's the upper bound address of M1K-ERASE */ + flash_set_m1k_erase_uba(dev, offset + FLASH_ERASE_BLK_SZ); + + m1kflhctrl7_cmd = sys_read8(SMFI_M1KFLHCTRL7) & ~GENMASK(7, 6); + /* Erase the flash within an address range */ + sys_write8(m1kflhctrl7_cmd | M1K_PE_CMD(M1K_ERASE), SMFI_M1KFLHCTRL7); + + /* Write-1-Start M1K-ERASE */ + sys_write8(W1S_M1K_PE, SMFI_M1KFLHCTRL1); + ret = flash_wait_status(dev, M1K_PE_CYC); + + return ret; +} + +/* Read data from flash */ +static int flash_it51xxx_read(const struct device *dev, off_t offset, void *dst_data, size_t len) +{ + struct flash_it51xxx_dev_data *data = dev->data; + int ret; + uint8_t *dst = (uint8_t *)dst_data; + + LOG_DBG("%s: offset=%lx, data addr=%p, len=%u", __func__, offset, (uint8_t *)dst_data, len); + + if (len == 0) { + return 0; + } + + if (!is_valid_range(offset, len)) { + LOG_ERR("Out of boundaries: FLASH_SIZE=%#x, offset=%#lx, len=%u", FLASH_SIZE, + offset, len); + return -EINVAL; + } + + k_sem_take(&data->sem, K_FOREVER); + + /* For M1K_READ, setting 1 will not plus EC image location */ + sys_write8(sys_read8(SMFI_M1KFLHCTRL3) | M1KPHY, SMFI_M1KFLHCTRL3); + + while (len > 0) { + size_t read_len = MIN(len, FLASH_READ_MAX_SZ); + + ret = m1k_flash_read(dev, offset, dst, read_len); + if (ret != 0) { + LOG_ERR("%s: failed at offset=%#lx", __func__, offset); + break; + } + + offset += read_len; + dst += read_len; + len -= read_len; + } + + /* Reset the M1K setting and counter to 0 */ + sys_write8(0, SMFI_M1KFLHCTRL3); + sys_write8(0, SMFI_M1KFLHCTRL4); + sys_write8(0, SMFI_M1KFLHCTRL5); + + k_sem_give(&data->sem); + + return ret; +} + +/* Write data to the flash, page by page */ +static int flash_it51xxx_write(const struct device *dev, off_t offset, const void *src_data, + size_t len) +{ + struct flash_it51xxx_dev_data *data = dev->data; + int ret; + const uint8_t *src = (const uint8_t *)src_data; + + LOG_DBG("%s: offset=%lx, data addr=%p, len=%u", __func__, offset, (const uint8_t *)src_data, + len); + + if (len == 0) { + return 0; + } + + if (!is_valid_range(offset, len)) { + LOG_ERR("Out of boundaries: FLASH_SIZE=%#x, offset=%#lx, len=%u", FLASH_SIZE, + offset, len); + return -EINVAL; + } + + k_sem_take(&data->sem, K_FOREVER); + + while (len > 0) { + size_t write_len = MIN(len, FLASH_WRITE_MAX_SZ); + + ret = m1k_flash_write(dev, offset, src, write_len); + if (ret != 0) { + LOG_ERR("%s: failed at offset=%#lx", __func__, offset); + break; + } + + offset += write_len; + src += write_len; + len -= write_len; + } + + /* Reset counter to 0 */ + sys_write8(0, SMFI_M1KFLHCTRL6); + sys_write8(0, SMFI_M1KFLHCTRL7); + + k_sem_give(&data->sem); + + return ret; +} + +/* Erase multiple blocks */ +static int flash_it51xxx_erase(const struct device *dev, off_t offset, size_t len) +{ + struct flash_it51xxx_dev_data *data = dev->data; + int ret; + + LOG_DBG("%s: offset=%lx, len=%u", __func__, offset, len); + + if (len == 0) { + return 0; + } + + if (!is_valid_range(offset, len)) { + LOG_ERR("Out of boundaries: FLASH_SIZE=%#x, offset=%#lx, len=%u", FLASH_SIZE, + offset, len); + return -EINVAL; + } + + /* Check that the offset and length are multiples of the erase block size */ + if ((offset % FLASH_ERASE_BLK_SZ) || (len % FLASH_ERASE_BLK_SZ)) { + LOG_ERR("Erase range is not a multiple of the block size. offset=%#lx, len=%u", + offset, len); + return -EINVAL; + } + + k_sem_take(&data->sem, K_FOREVER); + + while (len > 0) { + ret = m1k_flash_erase(dev, offset, len); + if (ret != 0) { + LOG_ERR("%s: failed at offset=%#lx", __func__, offset); + break; + } + + offset += FLASH_ERASE_BLK_SZ; + len -= FLASH_ERASE_BLK_SZ; + } + + k_sem_give(&data->sem); + + return ret; +} + +static const struct flash_parameters flash_it51xxx_parameters = { + .write_block_size = FLASH_WRITE_BLK_SZ, + .erase_value = 0xff, +}; + +static const struct flash_parameters *flash_it51xxx_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_it51xxx_parameters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static const struct flash_pages_layout dev_layout = { + .pages_count = FLASH_SIZE / FLASH_ERASE_BLK_SZ, + .pages_size = FLASH_ERASE_BLK_SZ, +}; + +static void flash_it51xxx_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + *layout = &dev_layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static DEVICE_API(flash, flash_it51xxx_api) = { + .read = flash_it51xxx_read, + .write = flash_it51xxx_write, + .erase = flash_it51xxx_erase, + .get_parameters = flash_it51xxx_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_it51xxx_pages_layout, +#endif +}; + +static int flash_it51xxx_init(const struct device *dev) +{ + const struct flash_it51xxx_config *cfg = dev->config; + struct flash_it51xxx_dev_data *data = dev->data; + int ret; + uint8_t flhctrl3r_val; + + LOG_INF("%s: M1K select access flash=%d", __func__, cfg->m1k_sel_access_flash); + + flhctrl3r_val = sys_read8(SMFI_FLHCTRL3R); + if (cfg->m1k_sel_access_flash) { + /* Enable SPI flash and SPI pins are normal operation */ + sys_write8((flhctrl3r_val | SIFE) & ~FFSPITRI, SMFI_FLHCTRL3R); + + /* M1K-READ will access the SPI flash (FSPI) */ + sys_write8(M1K_READ_SEL_FSPI, SMFI_M1K_READ_LBA3); + /* M1K-PROG/M1K-ERASE will access the SPI flash (FSPI) */ + sys_write8(M1K_PE_SEL_FSPI, SMFI_M1K_PE_LBA3); + + /* Set the pin to FSPI alternate function. */ + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("%s: Failed to configure FSPI pins", dev->name); + return ret; + } + + if (cfg->m1k_sel_access_flash == EXTERNAL_FSPI_CS1) { + /* M1K-READ will access the SPI flash on FSCE1# */ + sys_write8(sys_read8(SMFI_M1K_READ_LBA3) | M1K_READ_SEL_FSCE1, + SMFI_M1K_READ_LBA3); + /* M1K-PROG/M1K-ERASE will access the SPI flash on FSCE1# */ + sys_write8(sys_read8(SMFI_M1K_PE_LBA3) | M1K_PE_SEL_FSCE1, + SMFI_M1K_PE_LBA3); + /* Enable two-flash */ + sys_write8(sys_read8(SMFI_FLHCTRL4R) | EN2FLH, SMFI_FLHCTRL4R); + } + } else { + /* Use internal flash, the SPI pins should be set to tri-state */ + sys_write8((flhctrl3r_val & ~SIFE) | FFSPITRI, SMFI_FLHCTRL3R); + } + + /* Initialize mutex for flash controller */ + k_sem_init(&data->sem, 1, 1); + + return 0; +} + +static struct flash_it51xxx_dev_data flash_it51xxx_data; + +PINCTRL_DT_INST_DEFINE(0); + +static const struct flash_it51xxx_config flash_it51xxx_cfg = { + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .m1k_sel_access_flash = DT_INST_ENUM_IDX(0, m1k_sel_access_flash), +}; + +BUILD_ASSERT(!((DT_INST_ENUM_IDX(0, m1k_sel_access_flash) >= EXTERNAL_FSPI_CS0) && + !DT_INST_NODE_HAS_PROP(0, pinctrl_0)), + "Access external-fspi-cs0/cs1, pinctrl must be configured."); + +DEVICE_DT_INST_DEFINE(0, flash_it51xxx_init, NULL, &flash_it51xxx_data, &flash_it51xxx_cfg, + PRE_KERNEL_2, CONFIG_FLASH_INIT_PRIORITY, &flash_it51xxx_api); diff --git a/dts/bindings/flash_controller/ite,it51xxx-manual-flash-1k.yaml b/dts/bindings/flash_controller/ite,it51xxx-manual-flash-1k.yaml new file mode 100644 index 0000000000000..5ab9e9226b3e4 --- /dev/null +++ b/dts/bindings/flash_controller/ite,it51xxx-manual-flash-1k.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE IT51XXX manual flash 1k(M1k) + +compatible: "ite,it51xxx-manual-flash-1k" + +include: [flash-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + description: | + Access internal flash does not need to configure pinctrl, + so require is not true. + + pinctrl-names: + description: | + As above. + + m1k-sel-access-flash: + type: string + default: "internal" + enum: + - "internal" + - "external-fspi-cs0" + - "external-fspi-cs1" + description: | + This option enables access to the internal e-Flash or + external SPI flash via FSCE# or FSCE1#. diff --git a/dts/riscv/ite/it51xxx-pinctrl-map.dtsi b/dts/riscv/ite/it51xxx-pinctrl-map.dtsi index d7f352c9950c1..f4810536dc4ef 100644 --- a/dts/riscv/ite/it51xxx-pinctrl-map.dtsi +++ b/dts/riscv/ite/it51xxx-pinctrl-map.dtsi @@ -40,6 +40,35 @@ pinmuxs = <&pinctrli 7 IT8XXX2_ALT_FUNC_1>; }; + /* FSPI alternate function */ + fspi_fsce_gpg3_default: fspi_fsce_gpg3_default { + pinmuxs = <&pinctrlg 3 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fmosi_gpg4_default: fspi_fmosi_gpg4_default { + pinmuxs = <&pinctrlg 4 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fmiso_gpg5_default: fspi_fmiso_gpg5_default { + pinmuxs = <&pinctrlg 5 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fsce1_gpg6_default: fspi_fsce1_gpg6_default { + pinmuxs = <&pinctrlg 6 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fsck_gpg7_default: fspi_fsck_gpg7_default { + pinmuxs = <&pinctrlg 7 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fdio2_gph5_default: fspi_fdio2_gph5_default { + pinmuxs = <&pinctrlh 5 IT8XXX2_ALT_FUNC_1>; + }; + + fspi_fdio3_gph6_default: fspi_fdio3_gph6_default { + pinmuxs = <&pinctrlh 6 IT8XXX2_ALT_FUNC_1>; + }; + /* I2C alternate function */ i2c0_clk_gpf2_default: i2c0_clk_gpf2_default { pinmuxs = <&pinctrlf 2 IT8XXX2_ALT_FUNC_1>; diff --git a/dts/riscv/ite/it51xxx.dtsi b/dts/riscv/ite/it51xxx.dtsi index d28319f689605..2398b758ffb3a 100644 --- a/dts/riscv/ite/it51xxx.dtsi +++ b/dts/riscv/ite/it51xxx.dtsi @@ -65,6 +65,15 @@ }; }; + manual_flash_1k: manual-flash-1k@f010a6 { + compatible = "ite,it51xxx-manual-flash-1k"; + reg = <0x00f010a6 0x5a + 0x00f01000 0xa6>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + sram0: memory@800000 { compatible = "mmio-sram"; reg = <0x800000 DT_SIZE_K(128)>; diff --git a/soc/ite/ec/it51xxx/chip_chipregs.h b/soc/ite/ec/it51xxx/chip_chipregs.h index d550ceaf7b31d..725a696e47443 100644 --- a/soc/ite/ec/it51xxx/chip_chipregs.h +++ b/soc/ite/ec/it51xxx/chip_chipregs.h @@ -75,6 +75,11 @@ struct smfi_it51xxx_regs { #define SCARH_ENABLE BIT(7) #define SCARH_ADDR_BIT19 BIT(3) +#define IT51XXX_SMFI_BASE 0xf01000 +/* 0x63: Flash Control Register 3 */ +#define IT51XXX_SMFI_FLHCTRL3R (IT51XXX_SMFI_BASE + 0x63) +#define IT51XXX_SMFI_FFSPITRI BIT(0) + /** * * (16xxh) General Purpose I/O Port (GPIO) registers diff --git a/soc/ite/ec/it51xxx/soc.c b/soc/ite/ec/it51xxx/soc.c index 79eca7e5c28be..cb1aa52bf7944 100644 --- a/soc/ite/ec/it51xxx/soc.c +++ b/soc/ite/ec/it51xxx/soc.c @@ -117,6 +117,10 @@ void soc_prep_hook(void) struct gpio_ite_ec_regs *const gpio_regs = GPIO_ITE_EC_REGS_BASE; struct gctrl_ite_ec_regs *const gctrl_regs = GCTRL_ITE_EC_REGS_BASE; + /* Set FSPI pins are tri-state */ + sys_write8(sys_read8(IT51XXX_SMFI_FLHCTRL3R) | IT51XXX_SMFI_FFSPITRI, + IT51XXX_SMFI_FLHCTRL3R); + /* Scratch SRAM0 uses the 4KB based form 0x801000h */ gctrl_regs->GCTRL_SCR0BAR = IT51XXX_SEL_SRAM0_BASE_4K;