blob: b3d297a4ed803a0af6b5b3f3da94f55a28fc82d7 [file] [log] [blame]
/*
* Copyright (c) 2025 ITE Corporation. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ite_it51xxx_manual_flash_1k
#include <soc.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/flash/it51xxx_flash_api_ex.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/logging/log.h>
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)
/* 0x3b: EC-Indirect Memory Address Register 0 */
#define SMFI_ECINDAR0 (IT51XXX_SMFI_REGS_BASE + 0x3b)
/* 0x3c: EC-Indirect Memory Address Register 1 */
#define SMFI_ECINDAR1 (IT51XXX_SMFI_REGS_BASE + 0x3c)
/* 0x3d: EC-Indirect Memory Address Register 2 */
#define SMFI_ECINDAR2 (IT51XXX_SMFI_REGS_BASE + 0x3d)
/* 0x3e: EC-Indirect Memory Address Register 3 */
#define SMFI_ECINDAR3 (IT51XXX_SMFI_REGS_BASE + 0x3e)
#define SEL_SPI 0x00
#define SEL_EFLASH 0x01
#define ECINDA31_30(n) FIELD_PREP(GENMASK(7, 6), n)
/* 0x3f: EC-Indirect Memory Data Register */
#define SMFI_ECINDDR (IT51XXX_SMFI_REGS_BASE + 0x3f)
/* 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)
/* 0x81: Flash Control Register 6 */
#define SMFI_FLHCTRL6R (IT51XXX_SMFI_REGS_BASE + 0x81)
#define FSPI28AMEN BIT(4)
/* 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)
struct flash_it51xxx_dev_data {
struct k_sem sem;
enum flash_it51xxx_ex_op flash;
};
struct flash_it51xxx_config {
const struct pinctrl_dev_config *pcfg;
enum flash_it51xxx_ex_op target_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;
}
static int m1k_flash_sel_access(const struct device *dev, enum flash_it51xxx_ex_op target_flash)
{
const struct flash_it51xxx_config *cfg = dev->config;
struct flash_it51xxx_dev_data *data = dev->data;
int ret;
uint8_t flhctrl3r_val;
LOG_DBG("%s: Runtime M1K select access flash=%d", __func__, target_flash);
/* Save the opcode to device data */
data->flash = target_flash;
/* Disable two-flash */
sys_write8(sys_read8(SMFI_FLHCTRL4R) & ~EN2FLH, SMFI_FLHCTRL4R);
flhctrl3r_val = sys_read8(SMFI_FLHCTRL3R);
if (target_flash != FLASH_IT51XXX_INTERNAL) {
/* 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 (target_flash == FLASH_IT51XXX_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);
/* M1K-READ will access the e-flash */
sys_write8(0, SMFI_M1K_READ_LBA3);
/* M1K-PROG/M1K-ERASE will access the e-flash */
sys_write8(0, SMFI_M1K_PE_LBA3);
}
return 0;
}
static void m1k_flash_address_mode(const struct device *dev, enum flash_it51xxx_ex_op addr_mode)
{
struct flash_it51xxx_dev_data *data = dev->data;
uint8_t sel_flash;
volatile uint8_t ecinddr __unused;
LOG_DBG("%s: Addressing mode=%d", __func__, addr_mode);
/* Decide whether legacy(24-bit) or external SPI flash(28-bit) addressing */
if (addr_mode == FLASH_IT51XXX_ADDR_4B) {
sys_write8(sys_read8(SMFI_FLHCTRL6R) | FSPI28AMEN, SMFI_FLHCTRL6R);
} else {
sys_write8(sys_read8(SMFI_FLHCTRL6R) & ~FSPI28AMEN, SMFI_FLHCTRL6R);
}
/* EC-Indirect memory address (SPI or e-flash)*/
sel_flash = data->flash == FLASH_IT51XXX_INTERNAL ? SEL_EFLASH : SEL_SPI;
sys_write8(ECINDA31_30(sel_flash), SMFI_ECINDAR3);
sys_write8(0, SMFI_ECINDAR2);
sys_write8(0, SMFI_ECINDAR1);
sys_write8(0, SMFI_ECINDAR0);
/* Dummy read memory data*/
ecinddr = sys_read8(SMFI_ECINDDR);
}
/* 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 */
#ifdef CONFIG_FLASH_EX_OP_ENABLED
static int flash_it51xxx_ex_op(const struct device *dev, uint16_t opcode, const uintptr_t in,
void *out)
{
struct flash_it51xxx_dev_data *data = dev->data;
int ret = 0;
LOG_DBG("%s: Extended operation code=%x", __func__, opcode);
k_sem_take(&data->sem, K_FOREVER);
switch (opcode) {
case FLASH_IT51XXX_INTERNAL:
case FLASH_IT51XXX_EXTERNAL_FSPI_CS0:
case FLASH_IT51XXX_EXTERNAL_FSPI_CS1:
ret = m1k_flash_sel_access(dev, opcode);
break;
case FLASH_IT51XXX_ADDR_3B:
case FLASH_IT51XXX_ADDR_4B:
m1k_flash_address_mode(dev, opcode);
break;
default:
return -ENOTSUP;
}
k_sem_give(&data->sem);
return ret;
}
#endif
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
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
.ex_op = flash_it51xxx_ex_op,
#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;
LOG_DBG("%s: M1K select access flash=%d", __func__, cfg->target_flash);
/* Default to access flash */
ret = m1k_flash_sel_access(dev, cfg->target_flash);
/* Default addressing mode */
m1k_flash_address_mode(dev, FLASH_IT51XXX_ADDR_3B);
/* Initialize mutex for flash controller */
k_sem_init(&data->sem, 1, 1);
return ret;
}
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),
.target_flash = DT_INST_ENUM_IDX(0, m1k_sel_access_flash),
};
BUILD_ASSERT(!((DT_INST_ENUM_IDX(0, m1k_sel_access_flash) >= FLASH_IT51XXX_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);