drivers: flash: Initial support OSPI flash driver on RA8 boards

Support OSPI flash driver on EK-RA8M1 and EK-RA8D1 with ospi_b
and S28HL512T flash.

Signed-off-by: Tri Nguyen <tri.nguyen.wj@bp.renesas.com>
Signed-off-by: Thao Luong <thao.luong.uw@renesas.com>
This commit is contained in:
Tri Nguyen 2024-08-14 16:27:06 +07:00 committed by Benjamin Cabé
commit 1005cd9fa2
9 changed files with 1247 additions and 0 deletions

View file

@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_devic
zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_NOR flash_mspi_nor.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_RENESAS_RA_OSPI_B flash_renesas_ra_ospi_b.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c)

View file

@ -191,6 +191,7 @@ source "drivers/flash/Kconfig.numaker"
source "drivers/flash/Kconfig.numaker_rmc"
source "drivers/flash/Kconfig.nxp_s32"
source "drivers/flash/Kconfig.renesas_ra"
source "drivers/flash/Kconfig.renesas_ra_ospi"
source "drivers/flash/Kconfig.rpi_pico"
source "drivers/flash/Kconfig.rts5912"
source "drivers/flash/Kconfig.rv32m1"

View file

@ -0,0 +1,18 @@
# Renesas RA Family
# Copyright (c) 2024-2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
config FLASH_RENESAS_RA_OSPI_B
bool "Renesas RA Octal-SPI driver"
default y
depends on DT_HAS_RENESAS_RA_OSPI_B_NOR_ENABLED
select FLASH_HAS_DRIVER_ENABLED
select FLASH_HAS_PAGE_LAYOUT
select FLASH_HAS_EXPLICIT_ERASE
select USE_RA_FSP_OSPI_B_NOR_FLASH
select FLASH_JESD216
select FLASH_HAS_EX_OP
select PINCTRL
help
Enable Octal-SPI Nor flash driver for RA series

View file

@ -0,0 +1,785 @@
/*
* Copyright (c) 2024-2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT renesas_ra_ospi_b_nor
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/init.h>
#include <soc.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/pinctrl.h>
#include "flash_renesas_ra_ospi_b.h"
LOG_MODULE_REGISTER(flash_renesas_ra_ospi_b, CONFIG_FLASH_LOG_LEVEL);
struct flash_renesas_ra_ospi_b_data {
ospi_b_instance_ctrl_t ospi_b_ctrl;
spi_flash_cfg_t ospi_b_cfg;
ospi_b_timing_setting_t ospi_b_timing_settings;
ospi_b_xspi_command_set_t ospi_b_high_speed_command_set;
ospi_b_extended_cfg_t ospi_b_config_extend;
ospi_b_table_t const xspi_command_set;
struct k_sem sem;
};
struct flash_renesas_ra_ospi_b_config {
size_t flash_size;
int protocol;
int data_rate;
uint32_t max_frequency;
const struct device *clock_dev;
struct clock_control_ra_subsys_cfg clock_subsys;
const struct pinctrl_dev_config *pcfg;
};
static const struct flash_parameters ospi_b_ra_param = {
.write_block_size = DT_PROP(RA_OSPI_B_NOR_NODE, write_block_size),
.erase_value = ERASE_VALUE,
};
static void acquire_device(const struct device *dev)
{
struct flash_renesas_ra_ospi_b_data *dev_data = dev->data;
k_sem_take(&dev_data->sem, K_FOREVER);
}
static void release_device(const struct device *dev)
{
struct flash_renesas_ra_ospi_b_data *dev_data = dev->data;
k_sem_give(&dev_data->sem);
}
static int flash_renesas_ra_ospi_b_wait_operation(ospi_b_instance_ctrl_t *p_ctrl, uint32_t timeout)
{
spi_flash_status_t status = {RESET_VALUE};
status.write_in_progress = true;
while (status.write_in_progress) {
/* Get device status */
R_OSPI_B_StatusGet(p_ctrl, &status);
if (timeout == RESET_VALUE) {
LOG_DBG("Time out for operation");
return -EIO;
}
k_sleep(K_USEC(50));
timeout--;
}
return 0;
}
static int flash_renesas_ra_ospi_b_write_enable(ospi_b_instance_ctrl_t *p_ctrl)
{
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
fsp_err_t err;
/* Transfer write enable command */
transfer = (SPI_FLASH_PROTOCOL_EXTENDED_SPI == p_ctrl->spi_protocol)
? direct_transfer[TRANSFER_WRITE_ENABLE_SPI]
: direct_transfer[TRANSFER_WRITE_ENABLE_OSPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (err != FSP_SUCCESS) {
return -EIO;
}
/* Read Status Register */
transfer = (SPI_FLASH_PROTOCOL_EXTENDED_SPI == p_ctrl->spi_protocol)
? direct_transfer[TRANSFER_READ_STATUS_SPI]
: direct_transfer[TRANSFER_READ_STATUS_OSPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
/* Check Write Enable bit in Status Register */
if ((err != FSP_SUCCESS) || (SPI_NOR_WREN_MASK != (transfer.data & SPI_NOR_WREN_MASK))) {
return -EIO;
}
return 0;
}
static int flash_renesas_ra_ospi_b_setup_calibrate_data(ospi_b_instance_ctrl_t *p_ctrl)
{
uint32_t autocalibration_data[] = {0xFFFF0000U, 0x000800FFU, 0x00FFF700U, 0xF700F708U};
/* Verify auto-calibration data */
if (memcmp((uint8_t *)APP_ADDRESS(SECTOR_THREE), &autocalibration_data,
sizeof(autocalibration_data)) != RESET_VALUE) {
fsp_err_t err;
/* Erase the flash sector that stores auto-calibration data */
err = R_OSPI_B_Erase(p_ctrl, (uint8_t *)APP_ADDRESS(SECTOR_THREE),
SPI_NOR_SECTOR_SIZE);
if (err != FSP_SUCCESS) {
LOG_DBG("Erase the flash sector Failed");
return -EIO;
}
/* Wait until erase operation completes */
err = flash_renesas_ra_ospi_b_wait_operation(p_ctrl, TIME_ERASE_4K);
if (err != FSP_SUCCESS) {
LOG_DBG("Wait for erase operation completes Failed");
return -EIO;
}
/* Write auto-calibration data to the flash */
err = R_OSPI_B_Write(p_ctrl, (uint8_t *)&autocalibration_data,
(uint8_t *)APP_ADDRESS(SECTOR_THREE),
sizeof(autocalibration_data));
if (err != FSP_SUCCESS) {
LOG_DBG("Write auto-calibration data Failed");
return -EIO;
}
/* Wait until write operation completes */
err = flash_renesas_ra_ospi_b_wait_operation(p_ctrl, TIME_WRITE);
if (err != FSP_SUCCESS) {
LOG_DBG("Wait for write operation completes Failed");
return -EIO;
}
}
return 0;
}
static int flash_renesas_ra_ospi_b_spi_mode_init(ospi_b_instance_ctrl_t *p_ctrl,
spi_flash_cfg_t *p_cfg)
{
/* By default, the flash device is in SPI mode, so it is necessary to open the OSPI module
* in SPI mode
*/
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
fsp_err_t err;
/* Open OSPI module */
err = R_OSPI_B_Open(p_ctrl, p_cfg);
if (err != FSP_SUCCESS) {
LOG_DBG("OSPI open Failed");
return -EIO;
}
/* DDR sampling window extend */
R_XSPI->LIOCFGCS_b[p_ctrl->channel].DDRSMPEX = 1;
/* Switch OSPI module to 1S-1S-1S mode to configure flash device */
err = R_OSPI_B_SpiProtocolSet(p_ctrl, SPI_FLASH_PROTOCOL_EXTENDED_SPI);
if (err != FSP_SUCCESS) {
LOG_DBG("Switch OSPI module to 1S-1S-1S mode Failed");
return -EIO;
}
/* Reset flash device by driving OM_RESET pin */
R_XSPI->LIOCTL_b.RSTCS0 = 0;
k_sleep(K_USEC(500));
R_XSPI->LIOCTL_b.RSTCS0 = 1;
k_sleep(K_NSEC(50));
/* Transfer write enable command */
err = flash_renesas_ra_ospi_b_write_enable(p_ctrl);
if (err != FSP_SUCCESS) {
LOG_DBG("Enable write Failed");
return -EIO;
}
/* Write to CFR2V to configure Address Byte Length and Memory Array Read Latency */
transfer = direct_transfer[TRANSFER_WRITE_CFR2V_SPI];
transfer.address_length = ADDRESS_LENGTH_THREE;
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (err != FSP_SUCCESS) {
LOG_DBG("Configure Address Byte Length and Memory Array Read Latency Failed");
return -EIO;
}
/* Transfer write enable command */
err = flash_renesas_ra_ospi_b_write_enable(p_ctrl);
if (err != FSP_SUCCESS) {
LOG_DBG("Enable write Failed");
return -EIO;
}
/* Write to CFR3V to configure Volatile Register Read Latency */
transfer = direct_transfer[TRANSFER_WRITE_CFR3V_SPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (err != FSP_SUCCESS) {
LOG_DBG("Configure Volatile Register Read Latency Failed");
return -EIO;
}
/* Read back and verify CFR2V register data */
transfer = direct_transfer[TRANSFER_READ_CFR2V_SPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (err != FSP_SUCCESS) {
LOG_DBG("Read back CFR2V register Failed");
return -EIO;
}
if (DATA_CFR2V_REGISTER != (uint8_t)transfer.data) {
LOG_DBG("Verify CFR2V register data Failed");
return -EIO;
}
/* Read back and verify CFR3V register data */
transfer = direct_transfer[TRANSFER_READ_CFR3V_SPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (err != FSP_SUCCESS) {
LOG_DBG("Read back CFR3V register Failed");
return -EIO;
}
if (DATA_CFR3V_REGISTER != (uint8_t)transfer.data) {
LOG_DBG("Verify CFR3V register data Failed");
return -EIO;
}
/* Setup calibrate data */
err = flash_renesas_ra_ospi_b_setup_calibrate_data(p_ctrl);
if (err != FSP_SUCCESS) {
LOG_DBG("Setup calibrate data Failed");
return -EIO;
}
return 0;
}
static int flash_renesas_ra_ospi_b_set_protocol_to_opi(ospi_b_instance_ctrl_t *p_ctrl,
const struct device *dev)
{
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
fsp_err_t err;
/* Transfer write enable command */
err = flash_renesas_ra_ospi_b_write_enable(p_ctrl);
if (err != FSP_SUCCESS) {
LOG_DBG("Enable write Failed");
return -EIO;
}
/* Write to CFR5V Register to Configure flash device interface mode */
transfer = direct_transfer[TRANSFER_WRITE_CFR5V_SPI];
transfer.data = DATA_SET_OSPI_CFR5V_REGISTER;
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (err != FSP_SUCCESS) {
LOG_DBG("Configure flash device interface mode Failed");
return -EIO;
}
/* Switch OSPI module mode to OPI mode */
err = R_OSPI_B_SpiProtocolSet(p_ctrl, SPI_FLASH_PROTOCOL_8D_8D_8D);
if (err != FSP_SUCCESS) {
LOG_DBG("Switch to OPI mode Failed");
return -EIO;
}
/* Read back and verify CFR5V register data */
transfer = direct_transfer[TRANSFER_READ_CFR5V_OSPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (err != FSP_SUCCESS) {
LOG_DBG("Read back CFR5V register Failed");
return -EIO;
}
if (DATA_SET_OSPI_CFR5V_REGISTER != (uint8_t)transfer.data) {
LOG_DBG("CFR5V register data is Incorrect");
return -EIO;
}
return 0;
}
static inline bool flash_renesas_ra_ospi_b_is_valid_address(const struct device *dev, off_t offset,
size_t len)
{
const struct flash_renesas_ra_ospi_b_config *config = dev->config;
return (offset >= 0 && (offset < (config->flash_size)) &&
(len <= (config->flash_size - offset)));
}
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
static int flash_renesas_ra_ospi_b_ex_op(const struct device *dev, uint16_t code,
const uintptr_t in, void *out)
{
struct flash_renesas_ra_ospi_b_data *ospi_b_data = dev->data;
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
int ret = -ENOTSUP;
ARG_UNUSED(in);
ARG_UNUSED(out);
acquire_device(dev);
if (code == FLASH_EX_OP_RESET) {
fsp_err_t err = flash_renesas_ra_ospi_b_write_enable(&ospi_b_data->ospi_b_ctrl);
if (err == FSP_SUCCESS) {
/* Enable reset */
transfer = (SPI_FLASH_PROTOCOL_EXTENDED_SPI ==
ospi_b_data->ospi_b_ctrl.spi_protocol)
? direct_transfer[TRANSFER_RESET_ENABLE_SPI]
: direct_transfer[TRANSFER_RESET_ENABLE_OSPI];
err = R_OSPI_B_DirectTransfer(&ospi_b_data->ospi_b_ctrl, &transfer,
SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
}
if (err == FSP_SUCCESS) {
/* Reset Register */
transfer = (SPI_FLASH_PROTOCOL_EXTENDED_SPI ==
ospi_b_data->ospi_b_ctrl.spi_protocol)
? direct_transfer[TRANSFER_RESET_MEM_SPI]
: direct_transfer[TRANSFER_RESET_MEM_OSPI];
err = R_OSPI_B_DirectTransfer(&ospi_b_data->ospi_b_ctrl, &transfer,
SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
}
if (err == FSP_SUCCESS) {
ret = 0;
} else {
ret = -EIO;
}
}
release_device(dev);
return ret;
}
#endif /* CONFIG_FLASH_EX_OP_ENABLED */
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
#define SET_PAGES(node_id) \
{.pages_count = DT_PROP(node_id, pages_count), .pages_size = DT_PROP(node_id, pages_size)},
static const struct flash_pages_layout ospi_b_flash_ra_layout[] = {
DT_FOREACH_CHILD(DT_NODELABEL(pages_layout), SET_PAGES)};
void flash_renesas_ra_ospi_b_page_layout(const struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
ARG_UNUSED(dev);
*layout = ospi_b_flash_ra_layout;
*layout_size = ARRAY_SIZE(ospi_b_flash_ra_layout);
}
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
#if defined(CONFIG_FLASH_JESD216_API)
static int flash_renesas_ra_ospi_b_read_device_id(ospi_b_instance_ctrl_t *p_ctrl,
uint8_t *const p_id)
{
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
fsp_err_t err;
/* Read and check flash device ID */
transfer = (SPI_FLASH_PROTOCOL_EXTENDED_SPI == p_ctrl->spi_protocol)
? direct_transfer[TRANSFER_READ_DEVICE_ID_SPI]
: direct_transfer[TRANSFER_READ_DEVICE_ID_OSPI];
err = R_OSPI_B_DirectTransfer(p_ctrl, &transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (err != FSP_SUCCESS) {
return -EIO;
}
/* Get flash device ID */
memcpy(p_id, &transfer.data, sizeof(transfer.data));
return 0;
}
static int flash_renesas_ra_ospi_b_read_jedec_id(const struct device *dev, uint8_t *id)
{
struct flash_renesas_ra_ospi_b_data *ospi_b_data = dev->data;
int ret;
if (id == NULL) {
return -EINVAL;
}
acquire_device(dev);
ret = flash_renesas_ra_ospi_b_read_device_id(&ospi_b_data->ospi_b_ctrl, id);
if (ret) {
LOG_ERR("Failed to read jedec id");
} else {
LOG_INF("Manuf ID = %02x Memory Type = %02x Memory Density = %02x ID Length "
"= %02x\n",
id[0], id[1], id[2], id[3]);
}
release_device(dev);
return ret;
}
static int flash_renesas_ra_ospi_b_sfdp_read(const struct device *dev, off_t offset, void *data,
size_t len)
{
struct flash_renesas_ra_ospi_b_data *ospi_b_data = dev->data;
spi_flash_direct_transfer_t transfer = {RESET_VALUE};
size_t size;
fsp_err_t err;
if (len == 0) {
return 0;
}
if (data == NULL) {
LOG_ERR("The data buffer is NULL");
return -EINVAL;
}
acquire_device(dev);
if (ospi_b_data->ospi_b_ctrl.spi_protocol == SPI_FLASH_PROTOCOL_EXTENDED_SPI) {
transfer = direct_transfer[TRANSFER_READ_SFDP_ID_SPI];
} else {
transfer = direct_transfer[TRANSFER_READ_SFDP_ID_OSPI];
}
while (len > 0) {
size = len > transfer.data_length ? transfer.data_length : len;
transfer.address = offset;
transfer.data_length = size;
err = R_OSPI_B_DirectTransfer(&ospi_b_data->ospi_b_ctrl, &transfer,
SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (err != FSP_SUCCESS) {
LOG_ERR("Failed to read SFDP id");
release_device(dev);
return -EIO;
}
memcpy(data, &transfer.data, size);
len -= size;
offset += size;
data += size;
}
release_device(dev);
return 0;
}
#endif /* CONFIG_FLASH_JESD216_API */
static int flash_renesas_ra_ospi_b_erase(const struct device *dev, off_t offset, size_t len)
{
struct flash_renesas_ra_ospi_b_data *ospi_b_data = dev->data;
const struct flash_renesas_ra_ospi_b_config *config = dev->config;
uint32_t erase_size, erase_timeout;
fsp_err_t err;
struct flash_pages_info page_info_start, page_info_end;
int ret;
if (!len) {
return 0;
} else if (len % SPI_NOR_SECTOR_SIZE != 0) {
LOG_ERR("Wrong sector size 0x%x", len);
return -EINVAL;
}
if (!flash_renesas_ra_ospi_b_is_valid_address(dev, offset, len)) {
LOG_ERR("Address or size exceeds expected values: "
"Address 0x%lx, size %u",
(long)offset, len);
return -EINVAL;
}
/* check offset and len that valid in sector layout */
ret = flash_get_page_info_by_offs(dev, offset, &page_info_start);
if ((ret != 0) || (offset != page_info_start.start_offset)) {
LOG_ERR("The offset 0x%lx is not aligned with the starting sector", (long)offset);
return -EINVAL;
}
ret = flash_get_page_info_by_offs(dev, (offset + len), &page_info_end);
if ((ret != 0) || ((offset + len) != page_info_end.start_offset)) {
LOG_ERR("The size %u is not aligned with the ending sector", len);
return -EINVAL;
}
acquire_device(dev);
while (len > 0) {
if (offset == 0 && len == config->flash_size) {
/* Chip erase */
LOG_INF("Chip Erase");
erase_size = SPI_FLASH_ERASE_SIZE_CHIP_ERASE;
erase_timeout = UINT32_MAX;
} else if ((offset) <= (off_t)(ospi_b_flash_ra_layout[0].pages_size *
(ospi_b_flash_ra_layout[0].pages_count))) {
erase_size = SPI_NOR_SECTOR_SIZE;
erase_timeout = TIME_ERASE_4K;
} else {
erase_size = SECTOR_SIZE_256K;
erase_timeout = TIME_ERASE_256K;
}
err = R_OSPI_B_Erase(
&ospi_b_data->ospi_b_ctrl,
(uint8_t *)(BSP_FEATURE_OSPI_B_DEVICE_1_START_ADDRESS + offset),
erase_size);
if (err != FSP_SUCCESS) {
LOG_ERR("Erase at address 0x%lx, size %zu Failed", offset, erase_size);
ret = -EIO;
break;
}
err = flash_renesas_ra_ospi_b_wait_operation(&ospi_b_data->ospi_b_ctrl,
erase_timeout);
if (err != FSP_SUCCESS) {
LOG_ERR("Wait for erase to finish timeout");
ret = -EIO;
break;
}
offset += erase_size;
len -= len < erase_size ? len : erase_size;
}
release_device(dev);
return ret;
}
static int flash_renesas_ra_ospi_b_read(const struct device *dev, off_t offset, void *data,
size_t len)
{
if (!len) {
return 0;
}
if (!flash_renesas_ra_ospi_b_is_valid_address(dev, offset, len)) {
LOG_ERR("Address or size exceeds expected values: "
"Address 0x%lx, size %zu",
(long)offset, len);
return -EINVAL;
}
memcpy(data, (uint8_t *)(BSP_FEATURE_OSPI_B_DEVICE_1_START_ADDRESS) + offset, len);
return 0;
}
static int flash_renesas_ra_ospi_b_write(const struct device *dev, off_t offset, const void *data,
size_t len)
{
struct flash_renesas_ra_ospi_b_data *ospi_b_data = dev->data;
fsp_err_t err;
int ret = 0;
size_t size;
const uint8_t *p_src;
if (!len) {
return 0;
}
if (data != NULL) {
p_src = data;
} else {
LOG_ERR("The data buffer is NULL");
return -EINVAL;
}
if (!flash_renesas_ra_ospi_b_is_valid_address(dev, offset, len)) {
LOG_ERR("Address or size exceeds expected values: "
"Address 0x%lx, size %zu",
(long)offset, len);
return -EINVAL;
}
acquire_device(dev);
while (len > 0) {
size = len > ospi_b_data->ospi_b_cfg.page_size_bytes
? ospi_b_data->ospi_b_cfg.page_size_bytes
: len;
err = R_OSPI_B_Write(
&ospi_b_data->ospi_b_ctrl, p_src,
(uint8_t *)(BSP_FEATURE_OSPI_B_DEVICE_1_START_ADDRESS + offset), size);
if (err != FSP_SUCCESS) {
LOG_ERR("Write at address 0x%lx, size %zu", offset, size);
ret = -EIO;
break;
}
err = flash_renesas_ra_ospi_b_wait_operation(&ospi_b_data->ospi_b_ctrl, TIME_WRITE);
if (err != FSP_SUCCESS) {
LOG_ERR("Wait for write to finish timeout");
ret = -EIO;
break;
}
len -= size;
offset += size;
p_src = p_src + size;
}
release_device(dev);
return ret;
}
static const struct flash_parameters *
flash_renesas_ra_ospi_b_get_parameters(const struct device *dev)
{
ARG_UNUSED(dev);
return &ospi_b_ra_param;
}
static int flash_renesas_ra_ospi_b_get_size(const struct device *dev, uint64_t *size)
{
const struct flash_renesas_ra_ospi_b_config *config = dev->config;
*size = (uint64_t)config->flash_size;
return 0;
}
static DEVICE_API(flash, flash_renesas_ra_ospi_b_api) = {
.erase = flash_renesas_ra_ospi_b_erase,
.write = flash_renesas_ra_ospi_b_write,
.read = flash_renesas_ra_ospi_b_read,
.get_parameters = flash_renesas_ra_ospi_b_get_parameters,
.get_size = flash_renesas_ra_ospi_b_get_size,
#ifdef CONFIG_FLASH_PAGE_LAYOUT
.page_layout = flash_renesas_ra_ospi_b_page_layout,
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
#if defined(CONFIG_FLASH_JESD216_API)
.sfdp_read = flash_renesas_ra_ospi_b_sfdp_read,
.read_jedec_id = flash_renesas_ra_ospi_b_read_jedec_id,
#endif /* CONFIG_FLASH_JESD216_API */
#if defined(CONFIG_FLASH_EX_OP_ENABLED)
.ex_op = flash_renesas_ra_ospi_b_ex_op,
#endif /* CONFIG_FLASH_EX_OP_ENABLED */
};
static int flash_renesas_ra_ospi_b_init(const struct device *dev)
{
const struct flash_renesas_ra_ospi_b_config *config = dev->config;
struct flash_renesas_ra_ospi_b_data *data = dev->data;
uint32_t clock_freq;
int ret;
/* protocol/data_rate of XSPI checking */
if (config->protocol == XSPI_DUAL_MODE || config->protocol == XSPI_QUAD_MODE) {
LOG_ERR("XSPI mode DUAL|QUAD currently not support");
return -ENOTSUP;
} else if (((config->protocol != XSPI_OCTO_MODE) &&
(config->data_rate == XSPI_DTR_TRANSFER)) ||
((config->protocol == XSPI_OCTO_MODE) &&
(config->data_rate == XSPI_STR_TRANSFER))) {
LOG_ERR("XSPI mode SPI/DTR or OPI/STR is not valid");
return -ENOTSUP;
}
if (!device_is_ready(config->clock_dev)) {
LOG_ERR("Clock control device not ready");
return -ENODEV;
}
ret = clock_control_on(config->clock_dev, (clock_control_subsys_t)&config->clock_subsys);
if (ret < 0) {
LOG_ERR("Could not initialize clock (%d)", ret);
return ret;
}
ret = clock_control_get_rate(config->clock_dev,
(clock_control_subsys_t)&config->clock_subsys, &clock_freq);
if (ret) {
LOG_ERR("Failed to get clock frequency (%d)", ret);
return ret;
}
if ((config->protocol == XSPI_SPI_MODE && (config->max_frequency / 2) < clock_freq) ||
(config->protocol == XSPI_OCTO_MODE && (config->max_frequency) < clock_freq)) {
LOG_ERR("Invalid clock frequency (%u)", clock_freq);
return -EINVAL;
}
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret) {
LOG_ERR("Failed to configure pins (%d)", ret);
return ret;
}
k_sem_init(&data->sem, 1, 1);
ret = flash_renesas_ra_ospi_b_spi_mode_init(&data->ospi_b_ctrl, &data->ospi_b_cfg);
if (ret) {
LOG_ERR("Init SPI mode failed");
return ret;
}
if (config->protocol == XSPI_OCTO_MODE) {
ret = flash_renesas_ra_ospi_b_set_protocol_to_opi(&data->ospi_b_ctrl, dev);
if (ret) {
LOG_ERR("Init OPI mode failed");
return ret;
}
}
LOG_INF("Mode: %d Freq: %u", config->protocol, clock_freq);
return ret;
}
PINCTRL_DT_DEFINE(DT_INST_PARENT(0));
static const struct flash_renesas_ra_ospi_b_config ospi_b_config = {
.flash_size = DT_REG_SIZE(RA_OSPI_B_NOR_NODE),
.protocol = DT_PROP(RA_OSPI_B_NOR_NODE, protocol_mode),
.data_rate = DT_PROP(RA_OSPI_B_NOR_NODE, data_rate),
.max_frequency = DT_PROP(RA_OSPI_B_NOR_NODE, ospi_max_frequency),
.clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(0))),
.clock_subsys = {.mstp = (uint32_t)DT_CLOCKS_CELL(DT_INST_PARENT(0), mstp),
.stop_bit = (uint32_t)DT_CLOCKS_CELL(DT_INST_PARENT(0), stop_bit)},
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(0))};
static struct flash_renesas_ra_ospi_b_data ospi_b_data = {
.ospi_b_timing_settings = {.command_to_command_interval = OSPI_B_COMMAND_INTERVAL_CLOCKS_2,
.cs_pullup_lag = OSPI_B_COMMAND_CS_PULLUP_CLOCKS_NO_EXTENSION,
.cs_pulldown_lead =
OSPI_B_COMMAND_CS_PULLDOWN_CLOCKS_NO_EXTENSION},
.ospi_b_high_speed_command_set = {.protocol = SPI_FLASH_PROTOCOL_8D_8D_8D,
.command_bytes = OSPI_B_COMMAND_BYTES_2,
.read_command = S28HX512T_SPI_NOR_OCMD_READ,
.page_program_command = S28HX512T_SPI_NOR_OCMD_PP_4B,
.write_enable_command = S28HX512T_SPI_NOR_OCMD_WEN,
.status_command = S28HX512T_SPI_NOR_OCMD_RSR,
.read_dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_MEM_OCTAL,
.program_dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL,
.status_dummy_cycles =
S28HX512T_SPI_NOR_DUMMY_RD_REG_OCTAL,
.p_erase_commands = &high_speed_erase_commands},
.xspi_command_set = {.p_table = &ospi_b_data.ospi_b_high_speed_command_set, .length = 1U},
.ospi_b_config_extend = {.channel = OSPI_B_DEVICE_NUMBER_1,
.data_latch_delay_clocks = 0,
.p_timing_settings = &ospi_b_data.ospi_b_timing_settings,
.p_xspi_command_set = &ospi_b_data.xspi_command_set,
.p_autocalibration_preamble_pattern_addr =
APP_ADDRESS(SECTOR_THREE),
.read_dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_MEM,
.program_dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR,
.status_dummy_cycles = 0},
.ospi_b_cfg = {.spi_protocol = SPI_FLASH_PROTOCOL_1S_1S_1S,
.read_mode = SPI_FLASH_READ_MODE_STANDARD,
.address_bytes = SPI_FLASH_ADDRESS_BYTES_4,
.dummy_clocks = SPI_FLASH_DUMMY_CLOCKS_DEFAULT,
.page_program_address_lines = (spi_flash_data_lines_t)0U,
.page_size_bytes = PAGE_SIZE_BYTE,
.write_status_bit = WRITE_STATUS_BIT,
.write_enable_bit = WRITE_ENABLE_BIT,
.page_program_command = SPI_NOR_CMD_PP_4B,
.write_enable_command = SPI_NOR_CMD_WREN,
.status_command = SPI_NOR_CMD_RDSR,
.read_command = SPI_NOR_CMD_READ_FAST,
.xip_enter_command = 0U,
.xip_exit_command = 0U,
.erase_command_list_length = ERASE_COMMAND_LENGTH(erase_command_list),
.p_erase_command_list = &erase_command_list[0],
.p_extend = &ospi_b_data.ospi_b_config_extend}};
DEVICE_DT_INST_DEFINE(0, flash_renesas_ra_ospi_b_init, NULL, &ospi_b_data, &ospi_b_config,
POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &flash_renesas_ra_ospi_b_api);

View file

@ -0,0 +1,297 @@
/*
* Copyright (c) 2024 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_FLASH_RENESAS_RA_OSPI_B_H_
#define ZEPHYR_DRIVERS_FLASH_RENESAS_RA_OSPI_B_H_
#include <zephyr/drivers/flash.h>
#include <zephyr/dt-bindings/flash_controller/xspi.h>
#include <zephyr/drivers/clock_control/renesas_ra_cgc.h>
#include <r_spi_flash_api.h>
#include <r_ospi_b.h>
#include "spi_nor_s28hx512t.h"
#include "spi_nor.h"
/* Device node */
#define RA_OSPI_B_NOR_NODE DT_INST(0, renesas_ra_ospi_b_nor)
/* Flash erase value */
#define ERASE_VALUE (0xff)
/* Page size */
#define PAGE_SIZE_BYTE 64
/* Flash device sector size */
#define SECTOR_SIZE_128K (0x20000)
#define SECTOR_SIZE_256K (0x40000)
/* Flash device timing */
#define TIME_ERASE_256K (16000)
#define TIME_ERASE_4K (1000U)
#define TIME_WRITE (1000U)
/* Bit status */
#define WRITE_STATUS_BIT (0)
#define WRITE_ENABLE_BIT (1)
/* Calibration sector */
#define SECTOR_THREE (2U)
/* Command length */
#define COMMAND_LENGTH_SPI (1U)
#define COMMAND_LENGTH_OSPI (2U)
/* Transfer address length */
#define ADDRESS_DUMMY (0U)
#define ADDRESS_LENGTH_ZERO (0U)
#define ADDRESS_LENGTH_THREE (3U)
#define ADDRESS_LENGTH_FOUR (4U)
/* Transfer data length */
#define DATA_DUMMY (0U)
#define DATA_LENGTH_ZERO (0U)
#define DATA_LENGTH_ONE (1U)
#define DATA_LENGTH_TWO (2U)
#define DATA_LENGTH_FOUR (4U)
#define DATA_LENGTH_EIGHT (8U)
/* Configure flash device */
#define DATA_CFR2V_REGISTER (0x83)
#define DATA_CFR3V_REGISTER (0x40)
#define DATA_SET_SPI_CFR5V_REGISTER (0x40)
#define DATA_SET_OSPI_CFR5V_REGISTER (0x43)
/* Flash device address space mapping */
#define APP_ADDRESS(sector_no) \
((uint8_t *)(BSP_FEATURE_OSPI_B_DEVICE_1_START_ADDRESS + \
((sector_no) * SPI_NOR_SECTOR_SIZE)))
/* Erase command */
static spi_flash_erase_command_t erase_command_list[] = {
{.command = SPI_NOR_CMD_SE_4B, .size = SPI_NOR_SECTOR_SIZE},
{.command = S28HX512T_SPI_NOR_CMD_SE_256KB, .size = SECTOR_SIZE_256K},
{.command = S28HX512T_SPI_NOR_CMD_ERCHP, .size = SPI_FLASH_ERASE_SIZE_CHIP_ERASE}};
static spi_flash_erase_command_t high_speed_erase_command_list[] = {
{.command = S28HX512T_SPI_NOR_OCMD_SE_4KB, .size = SPI_NOR_SECTOR_SIZE},
{.command = S28HX512T_SPI_NOR_OCMD_SE_256KB, .size = SECTOR_SIZE_256K},
{.command = S28HX512T_SPI_NOR_OCMD_ERCHP, .size = SPI_FLASH_ERASE_SIZE_CHIP_ERASE}};
/* Erase command length */
#define ERASE_COMMAND_LENGTH(arr) (sizeof(arr) / sizeof((arr)[0]))
static ospi_b_table_t const high_speed_erase_commands = {
.p_table = &high_speed_erase_command_list,
.length = ERASE_COMMAND_LENGTH(high_speed_erase_command_list),
};
/* Reset value */
#define RESET_VALUE (0x00)
/* Transfer table */
typedef enum e_transfer {
TRANSFER_WRITE_ENABLE_SPI = 0,
TRANSFER_WRITE_CFR2V_SPI,
TRANSFER_WRITE_CFR3V_SPI,
TRANSFER_WRITE_CFR5V_SPI,
TRANSFER_READ_STATUS_SPI,
TRANSFER_READ_CFR2V_SPI,
TRANSFER_READ_CFR3V_SPI,
TRANSFER_READ_CFR5V_SPI,
TRANSFER_READ_DEVICE_ID_SPI,
TRANSFER_READ_SFDP_ID_SPI,
TRANSFER_RESET_ENABLE_SPI,
TRANSFER_RESET_MEM_SPI,
TRANSFER_WRITE_ENABLE_OSPI,
TRANSFER_WRITE_CFR2V_OSPI,
TRANSFER_WRITE_CFR3V_OSPI,
TRANSFER_WRITE_CFR5V_OSPI,
TRANSFER_READ_STATUS_OSPI,
TRANSFER_READ_CFR2V_OSPI,
TRANSFER_READ_CFR3V_OSPI,
TRANSFER_READ_CFR5V_OSPI,
TRANSFER_READ_DEVICE_ID_OSPI,
TRANSFER_READ_SFDP_ID_OSPI,
TRANSFER_RESET_ENABLE_OSPI,
TRANSFER_RESET_MEM_OSPI,
TRANSFER_MAX
} transfer_t;
spi_flash_direct_transfer_t direct_transfer[TRANSFER_MAX] = {
/* Transfer structure for SPI mode */
[TRANSFER_WRITE_ENABLE_SPI] = {.command = SPI_NOR_CMD_WREN,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
[TRANSFER_WRITE_CFR2V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_WR_WRARG,
.address = S28HX512T_SPI_NOR_CFR2V_ADDR,
.data = DATA_CFR2V_REGISTER,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
[TRANSFER_WRITE_CFR3V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_WR_WRARG,
.address = S28HX512T_SPI_NOR_CFR3V_ADDR,
.data = DATA_CFR3V_REGISTER,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
[TRANSFER_WRITE_CFR5V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_WR_WRARG,
.address = S28HX512T_SPI_NOR_CFR5V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
[TRANSFER_READ_STATUS_SPI] = {.command = SPI_NOR_CMD_RDSR,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_STATUS},
[TRANSFER_READ_CFR2V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_RREG,
.address = S28HX512T_SPI_NOR_CFR2V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG},
[TRANSFER_READ_CFR3V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_RREG,
.address = S28HX512T_SPI_NOR_CFR3V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG},
[TRANSFER_READ_CFR5V_SPI] = {.command = S28HX512T_SPI_NOR_CMD_RREG,
.address = S28HX512T_SPI_NOR_CFR5V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_ONE,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG},
[TRANSFER_READ_DEVICE_ID_SPI] = {.command = SPI_NOR_CMD_RDID,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_FOUR,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_STATUS},
[TRANSFER_READ_SFDP_ID_SPI] = {.command = S28HX512T_SPI_NOR_CMD_RSFDPID,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_THREE,
.data_length = DATA_LENGTH_EIGHT,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_SFDP},
[TRANSFER_RESET_ENABLE_SPI] = {.command = SPI_NOR_CMD_RESET_EN,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
[TRANSFER_RESET_MEM_SPI] = {.command = SPI_NOR_CMD_RESET_MEM,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_SPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR},
/* Transfer structure for OPI mode */
[TRANSFER_WRITE_ENABLE_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_WEN,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
[TRANSFER_WRITE_CFR2V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_WR_REG2,
.address = S28HX512T_SPI_NOR_CFR2V_ADDR,
.data = DATA_CFR2V_REGISTER,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
[TRANSFER_WRITE_CFR3V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_WR_REG2,
.address = S28HX512T_SPI_NOR_CFR3V_ADDR,
.data = DATA_CFR3V_REGISTER,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
[TRANSFER_WRITE_CFR5V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_WR_REG2,
.address = S28HX512T_SPI_NOR_CFR5V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
[TRANSFER_READ_STATUS_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RSR,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_STATUS_OCTAL},
[TRANSFER_READ_CFR2V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RSR,
.address = S28HX512T_SPI_NOR_CFR2V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG_OCTAL},
[TRANSFER_READ_CFR3V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RSR,
.address = S28HX512T_SPI_NOR_CFR3V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG_OCTAL},
[TRANSFER_READ_CFR5V_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RREG,
.address = S28HX512T_SPI_NOR_CFR5V_ADDR,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_TWO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_REG_OCTAL},
[TRANSFER_READ_DEVICE_ID_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RDID,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_FOUR,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_STATUS_OCTAL},
[TRANSFER_READ_SFDP_ID_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RSFDPID,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_FOUR,
.data_length = DATA_LENGTH_EIGHT,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_RD_SFDP_OCTAL},
[TRANSFER_RESET_ENABLE_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RST_EN,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
[TRANSFER_RESET_MEM_OSPI] = {.command = S28HX512T_SPI_NOR_OCMD_RST_MEM,
.address = ADDRESS_DUMMY,
.data = DATA_DUMMY,
.command_length = COMMAND_LENGTH_OSPI,
.address_length = ADDRESS_LENGTH_ZERO,
.data_length = DATA_LENGTH_ZERO,
.dummy_cycles = S28HX512T_SPI_NOR_DUMMY_WR_OCTAL},
};
#endif /* ZEPHYR_DRIVERS_FLASH_RENESAS_RA_OSPI_B_H_ */

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024-2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SPI_NOR_S28HX512T_H__
#define __SPI_NOR_S28HX512T_H__
#define S28HX512T_SPI_NOR_CMD_WR_WRARG 0x71 /* Write Any Register */
#define S28HX512T_SPI_NOR_CMD_RSFDPID 0x5A /* Read SFDP ID */
#define S28HX512T_SPI_NOR_CMD_RREG 0x65 /* Read Any Register */
#define S28HX512T_SPI_NOR_CMD_SE_256KB 0xDC /* Sector Erase 256KB */
#define S28HX512T_SPI_NOR_CMD_ERCHP 0x60 /* Erase Chip */
#define S28HX512T_SPI_NOR_OCMD_WEN 0x0606 /* Octal Write enable */
#define S28HX512T_SPI_NOR_OCMD_RSR 0x0505 /* Octal Read status register */
#define S28HX512T_SPI_NOR_OCMD_WR_REG2 0x7171 /* Octal Write config register 2 */
#define S28HX512T_SPI_NOR_OCMD_RDID 0x9F9F /* Octal Read JEDEC ID */
#define S28HX512T_SPI_NOR_OCMD_RSFDPID 0x5A5A /* Octal Read SFDP ID */
#define S28HX512T_SPI_NOR_OCMD_RREG 0x6565 /* Octal Read Any Register */
#define S28HX512T_SPI_NOR_OCMD_PP_4B 0x1212 /* Octal Page Program 4 Byte Address */
#define S28HX512T_SPI_NOR_OCMD_READ 0xEEEE /* Octal Read data */
#define S28HX512T_SPI_NOR_OCMD_RST_EN 0x6666 /* Octal Reset Enable */
#define S28HX512T_SPI_NOR_OCMD_RST_MEM 0x9999 /* Reset Memory */
#define S28HX512T_SPI_NOR_OCMD_SE_4KB 0x2121 /* Octal Sector Erase 4Kb address */
#define S28HX512T_SPI_NOR_OCMD_SE_256KB 0xDCDC /* Octal Sector Erase 256Kb address */
#define S28HX512T_SPI_NOR_OCMD_ERCHP 0x6060 /* Octal Erase Chip */
#define S28HX512T_SPI_NOR_DUMMY_WR 0U
#define S28HX512T_SPI_NOR_DUMMY_WR_OCTAL 0U
#define S28HX512T_SPI_NOR_DUMMY_RD_STATUS 0U
#define S28HX512T_SPI_NOR_DUMMY_RD_STATUS_OCTAL 4U
#define S28HX512T_SPI_NOR_DUMMY_RD_REG 1U
#define S28HX512T_SPI_NOR_DUMMY_RD_REG_OCTAL 4U
#define S28HX512T_SPI_NOR_DUMMY_RD_MEM 3U
#define S28HX512T_SPI_NOR_DUMMY_RD_MEM_OCTAL 10U
#define S28HX512T_SPI_NOR_DUMMY_RD_SFDP 8U
#define S28HX512T_SPI_NOR_DUMMY_RD_SFDP_OCTAL 8U
#define S28HX512T_SPI_NOR_CFR1V_ADDR 0x00800002
#define S28HX512T_SPI_NOR_CFR2V_ADDR 0x00800003
#define S28HX512T_SPI_NOR_CFR3V_ADDR 0x00800004
#define S28HX512T_SPI_NOR_CFR4V_ADDR 0x00800005
#define S28HX512T_SPI_NOR_CFR5V_ADDR 0x00800006
#endif /*__SPI_NOR_S28HX512T_H__*/

View file

@ -0,0 +1,70 @@
# Copyright (c) 2024 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
description: Renesas RA OSPI FLASH
compatible: "renesas,ra-ospi-b-nor"
include: [base.yaml]
on-bus: ospi
properties:
reg:
required: true
description: Flash Memory base address and size in bytes
size:
type: int
required: true
description: Flash Memory size
protocol-mode:
type: int
required: true
description: |
The width and rate of XSPI bus to which flash memory is connected.
Possible values are :
- XSPI_SPI_MODE <1> = SPI mode on 1 data line
- XSPI_DUAL_MODE <2> = Dual mode on 2 data lines
- XSPI_QUAD_MODE <4> = Quad mode on 4 data lines
- XSPI_OCTO_MODE <8> = Octo mode on 8 data lines
enum:
- 1
- 2
- 4
- 8
data-rate:
type: int
required: true
description: |
The SPI data Rate is STR or DTR
Possible values are :
- XSPI_STR_TRANSFER <1> = Single Rate Transfer
- XSPI_DTR_TRANSFER <2> = Dual Rate Transfer (only with XSPI_OCTO_MODE)
ospi-max-frequency:
type: int
required: true
description: Max frequency input on OSPI
write-block-size:
type: int
description: Address alignment required by flash write operations
child-binding:
description: OSPI Flash page layout description
child-binding:
description: Individual flash page layout entry
properties:
pages-count:
description: Number of consecutive pages with size pages-size bytes
type: int
required: true
pages-size:
type: int
required: true

View file

@ -0,0 +1,23 @@
# Copyright (c) 2024 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0
description: Renesas RA OSPI
compatible: "renesas,ra-ospi-b"
include: [base.yaml, pinctrl-device.yaml]
bus: ospi
properties:
reg:
required: true
pinctrl-0:
required: true
pinctrl-names:
required: true
clocks:
required: true

View file

@ -181,6 +181,11 @@ config USE_RA_FSP_LPM
help
Enable RA FSP LPM driver
config USE_RA_FSP_OSPI_B_NOR_FLASH
bool
help
Enable RA FSP Octal-SPI driver
endif # HAS_RENESAS_RA_FSP
if HAS_RENESAS_RZ_FSP