Skip to content

stm32 OSPI flash driver enables XiP on external NOR flash #68597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions boards/st/b_u585i_iot02a/b_u585i_iot02a.dts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

/dts-v1/;
#include "b_u585i_iot02a-common.dtsi"
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>

/ {
model = "STMicroelectronics B-U585I-IOT02A discovery kit";
Expand All @@ -25,6 +27,14 @@
led1 = &red_led_1;
sw0 = &user_button;
};

octo_nor: memory@70000000 {
compatible = "zephyr,memory-region";
reg = <0x70000000 DT_SIZE_M(64)>;
zephyr,memory-region = "EXTMEM";
/* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

&flash0 {
Expand Down
7 changes: 6 additions & 1 deletion boards/st/b_u585i_iot02a/board.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ if(CONFIG_BUILD_WITH_TFM)
endif()
endif()

board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw")
if(CONFIG_STM32_MEMMAP)
board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw")
board_runner_args(stm32cubeprogrammer "--hex-file=${ZEPHYR_BASE}/build/zephyr/zephyr.hex")
board_runner_args(stm32cubeprogrammer "--extload=MX25LM51245G_STM32U585I-IOT02A.stldr")
else()
board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw")
endif()

board_runner_args(openocd "--tcl-port=6666")
board_runner_args(openocd --cmd-pre-init "gdb_report_data_abort enable")
Expand Down
9 changes: 9 additions & 0 deletions boards/st/stm32h7b3i_dk/board.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,14 @@
board_runner_args(jlink "--device=STM32H7B3LI" "--speed=4000")
board_runner_args(openocd --target-handle=_CHIPNAME.cpu0)

if(CONFIG_STM32_MEMMAP)
board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw")
board_runner_args(stm32cubeprogrammer "--hex-file=${ZEPHYR_BASE}/build/zephyr/zephyr.hex")
board_runner_args(stm32cubeprogrammer "--extload=MX25LM51245G_STM32H7B3I-DISCO.stldr")
else()
board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw" )
endif()

include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake)
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
8 changes: 8 additions & 0 deletions boards/st/stm32h7b3i_dk/stm32h7b3i_dk.dts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};

octo_nor: memory@90000000 {
compatible = "zephyr,memory-region";
reg = <0x90000000 DT_SIZE_M(64)>;
zephyr,memory-region = "EXTMEM";
/* The ATTR_MPU_EXTMEM attribut causing a MPU FAULT */
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};

transceiver0: can-phy0 {
compatible = "microchip,mcp2562fd", "can-transceiver-gpio";
standby-gpios = <&gpioh 8 GPIO_ACTIVE_HIGH>;
Expand Down
230 changes: 219 additions & 11 deletions drivers/flash/flash_stm32_ospi.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,11 +978,149 @@ static int stm32_ospi_mem_reset(const struct device *dev)
return 0;
}

#ifdef CONFIG_STM32_MEMMAP
/* Function to configure the octoflash in MemoryMapped mode */
static int stm32_ospi_set_memorymap(const struct device *dev)
{
HAL_StatusTypeDef ret;
const struct flash_stm32_ospi_config *dev_cfg = dev->config;
struct flash_stm32_ospi_data *dev_data = dev->data;
OSPI_RegularCmdTypeDef s_command;
OSPI_MemoryMappedTypeDef s_MemMappedCfg;

/* Configure octoflash in MemoryMapped mode */
if ((dev_cfg->data_mode == OSPI_SPI_MODE) &&
(stm32_ospi_hal_address_size(dev) == HAL_OSPI_ADDRESS_24_BITS)) {
/* OPI mode and 3-bytes address size not supported by memory */
LOG_ERR("OSPI_SPI_MODE in 3Bytes addressing is not supported");
return -EIO;
}

/* Initialize the read command */
s_command.OperationType = HAL_OSPI_OPTYPE_READ_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? HAL_OSPI_INSTRUCTION_1_LINE
: HAL_OSPI_INSTRUCTION_8_LINES)
: HAL_OSPI_INSTRUCTION_8_LINES;
s_command.InstructionDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? HAL_OSPI_INSTRUCTION_DTR_DISABLE
: HAL_OSPI_INSTRUCTION_DTR_ENABLE;
s_command.InstructionSize = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? HAL_OSPI_INSTRUCTION_8_BITS
: HAL_OSPI_INSTRUCTION_16_BITS)
: HAL_OSPI_INSTRUCTION_16_BITS;
s_command.Instruction = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? ((stm32_ospi_hal_address_size(dev) ==
HAL_OSPI_ADDRESS_24_BITS)
? SPI_NOR_CMD_READ_FAST
: SPI_NOR_CMD_READ_FAST_4B)
: dev_data->read_opcode)
: SPI_NOR_OCMD_DTR_RD;
s_command.AddressMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? HAL_OSPI_ADDRESS_1_LINE
: HAL_OSPI_ADDRESS_8_LINES)
: HAL_OSPI_ADDRESS_8_LINES;
s_command.AddressDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? HAL_OSPI_ADDRESS_DTR_DISABLE
: HAL_OSPI_ADDRESS_DTR_ENABLE;
s_command.AddressSize = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? stm32_ospi_hal_address_size(dev)
: HAL_OSPI_ADDRESS_32_BITS;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? HAL_OSPI_DATA_1_LINE
: HAL_OSPI_DATA_8_LINES)
: HAL_OSPI_DATA_8_LINES;
s_command.DataDtrMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? HAL_OSPI_DATA_DTR_DISABLE
: HAL_OSPI_DATA_DTR_ENABLE;
s_command.DummyCycles = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? ((dev_cfg->data_mode == OSPI_SPI_MODE)
? SPI_NOR_DUMMY_RD
: SPI_NOR_DUMMY_RD_OCTAL)
: SPI_NOR_DUMMY_RD_OCTAL_DTR;
s_command.DQSMode = (dev_cfg->data_rate == OSPI_STR_TRANSFER)
? HAL_OSPI_DQS_DISABLE
: HAL_OSPI_DQS_ENABLE;

s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;

ret = HAL_OSPI_Command(&dev_data->hospi, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (ret != HAL_OK) {
LOG_ERR("%d: Failed to set memory map", ret);
return -EIO;
}

/* Initialize the program command */
s_command.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
if (dev_cfg->data_rate == OSPI_STR_TRANSFER) {
s_command.Instruction = (dev_cfg->data_mode == OSPI_SPI_MODE)
? ((stm32_ospi_hal_address_size(dev) ==
HAL_OSPI_ADDRESS_24_BITS)
? SPI_NOR_CMD_PP
: SPI_NOR_CMD_PP_4B)
: SPI_NOR_OCMD_PAGE_PRG;
} else {
s_command.Instruction = SPI_NOR_OCMD_PAGE_PRG;
}
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;

ret = HAL_OSPI_Command(&dev_data->hospi, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (ret != HAL_OK) {
LOG_ERR("%d: Failed to set memory mapped", ret);
return -EIO;
}

/* Enable the memory-mapping */
s_MemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;

ret = HAL_OSPI_MemoryMapped(&dev_data->hospi, &s_MemMappedCfg);
if (ret != HAL_OK) {
LOG_ERR("%d: Failed to set memory mapped", ret);
return -EIO;
}

LOG_INF("MemoryMap mode enabled");
return 0;
}

/* Function to return true if the octoflash is in MemoryMapped else false */
static bool stm32_ospi_is_memorymap(const struct device *dev)
{
struct flash_stm32_ospi_data *dev_data = dev->data;

return ((READ_BIT(dev_data->hospi.Instance->CR,
OCTOSPI_CR_FMODE) == OCTOSPI_CR_FMODE) ?
true : false);
}

static int stm32_ospi_abort(const struct device *dev)
{
struct flash_stm32_ospi_data *dev_data = dev->data;
HAL_StatusTypeDef hal_ret;

hal_ret = HAL_OSPI_Abort(&dev_data->hospi);
if (hal_ret != HAL_OK) {
LOG_ERR("%d: OSPI abort failed", hal_ret);
return -EIO;
}

return 0;
}
#endif /* CONFIG_STM32_MEMMAP */

/*
* Function to erase the flash : chip or sector with possible OSPI/SPI and STR/DTR
* to erase the complete chip (using dedicated command) :
* set size >= flash size
* set addr = 0
* NOTE: cannot erase in MemoryMapped mode
*/
static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
size_t size)
Expand Down Expand Up @@ -1012,6 +1150,20 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
return -ENOTSUP;
}

ospi_lock_thread(dev);

#ifdef CONFIG_STM32_MEMMAP
if (stm32_ospi_is_memorymap(dev)) {
/* Abort ongoing transfer to force CS high/BUSY deasserted */
ret = stm32_ospi_abort(dev);
if (ret != 0) {
LOG_ERR("Failed to abort memory-mapped access before erase");
goto end_erase;
}
}
/* Continue with Indirect Mode */
#endif /* CONFIG_STM32_MEMMAP */

OSPI_RegularCmdTypeDef cmd_erase = {
.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG,
.FlashId = HAL_OSPI_FLASH_ID_1,
Expand All @@ -1022,13 +1174,11 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD,
};

ospi_lock_thread(dev);

if (stm32_ospi_mem_ready(dev_data,
dev_cfg->data_mode, dev_cfg->data_rate) != 0) {
ospi_unlock_thread(dev);
LOG_ERR("Erase failed : flash busy");
return -EBUSY;
ret = -EBUSY;
goto end_erase;
}

cmd_erase.InstructionMode = (dev_cfg->data_mode == OSPI_OPI_MODE)
Expand Down Expand Up @@ -1134,9 +1284,10 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
ret = stm32_ospi_mem_ready(dev_data, dev_cfg->data_mode,
dev_cfg->data_rate);
}

}
goto end_erase;

end_erase:
ospi_unlock_thread(dev);

return ret;
Expand All @@ -1146,9 +1297,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr,
static int flash_stm32_ospi_read(const struct device *dev, off_t addr,
void *data, size_t size)
{
const struct flash_stm32_ospi_config *dev_cfg = dev->config;
struct flash_stm32_ospi_data *dev_data = dev->data;
int ret;
int ret = 0;

if (!ospi_address_is_valid(dev, addr, size)) {
LOG_ERR("Error: address or size exceeds expected values: "
Expand All @@ -1161,6 +1310,25 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr,
return 0;
}

#ifdef CONFIG_STM32_MEMMAP
/* If not MemMapped then configure it */
if (!stm32_ospi_is_memorymap(dev)) {
if (stm32_ospi_set_memorymap(dev) != 0) {
LOG_ERR("READ failed: cannot enable MemoryMap");
return -EIO;
}
}
/* Now in MemMapped mode : read with memcopy */
LOG_DBG("MemoryMapped Read offset: 0x%lx, len: %zu",
(long)(STM32_OSPI_BASE_ADDRESS + addr),
size);
memcpy(data, (uint8_t *)STM32_OSPI_BASE_ADDRESS + addr, size);

#else /* CONFIG_STM32_MEMMAP */
const struct flash_stm32_ospi_config *dev_cfg = dev->config;
struct flash_stm32_ospi_data *dev_data = dev->data;


OSPI_RegularCmdTypeDef cmd = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate);

if (dev_cfg->data_mode != OSPI_OPI_MODE) {
Expand Down Expand Up @@ -1226,10 +1394,14 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr,

ospi_unlock_thread(dev);

#endif /* CONFIG_STM32_MEMMAP */
return ret;
}

/* Function to write the flash (page program) : with possible OSPI/SPI and STR/DTR */
/*
* Function to write the flash (page program) : with possible OSPI/SPI and STR/DTR
* NOTE: writing in MemoryMapped mode is not guaranted
*/
static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
const void *data, size_t size)
{
Expand All @@ -1249,6 +1421,19 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
return 0;
}

ospi_lock_thread(dev);

#ifdef CONFIG_STM32_MEMMAP
if (stm32_ospi_is_memorymap(dev)) {
/* Abort ongoing transfer to force CS high/BUSY deasserted */
ret = stm32_ospi_abort(dev);
if (ret != 0) {
LOG_ERR("Failed to abort memory-mapped access before write");
goto end_write;
}
}
/* Continue with Indirect Mode */
#endif /* CONFIG_STM32_MEMMAP */
/* page program for STR or DTR mode */
OSPI_RegularCmdTypeDef cmd_pp = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate);

Expand Down Expand Up @@ -1292,7 +1477,6 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
cmd_pp.DummyCycles = 0U;

LOG_DBG("OSPI: write %zu data", size);
ospi_lock_thread(dev);

ret = stm32_ospi_mem_ready(dev_data,
dev_cfg->data_mode, dev_cfg->data_rate);
Expand Down Expand Up @@ -1341,7 +1525,9 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr,
break;
}
}
goto end_write;

end_write:
ospi_unlock_thread(dev);

return ret;
Expand Down Expand Up @@ -1913,6 +2099,16 @@ static int flash_stm32_ospi_init(const struct device *dev)
return -ENODEV;
}

#ifdef CONFIG_STM32_MEMMAP
/* If MemoryMapped then configure skip init */
if (stm32_ospi_is_memorymap(dev)) {
LOG_DBG("NOR init'd in MemMapped mode\n");
/* Force HAL instance in correct state */
dev_data->hospi.State = HAL_OSPI_STATE_BUSY_MEM_MAPPED;
return 0;
}
#endif /* CONFIG_STM32_MEMMAP */

#if STM32_OSPI_USE_DMA
/*
* DMA configuration
Expand Down Expand Up @@ -2292,9 +2488,21 @@ static int flash_stm32_ospi_init(const struct device *dev)
}
#endif /* CONFIG_FLASH_PAGE_LAYOUT */

LOG_INF("NOR octo-flash at 0x%lx (0x%x bytes)",
#ifdef CONFIG_STM32_MEMMAP
/* Now configure the octo Flash in MemoryMapped (access by address) */
ret = stm32_ospi_set_memorymap(dev);
if (ret != 0) {
LOG_ERR("Error (%d): setting NOR in MemoryMapped mode", ret);
return -EINVAL;
}
LOG_DBG("NOR octo-flash in MemoryMapped mode at 0x%lx (0x%x bytes)",
(long)(STM32_OSPI_BASE_ADDRESS),
dev_cfg->flash_size);
#else
LOG_DBG("NOR octo-flash at 0x%lx (0x%x bytes)",
(long)(STM32_OSPI_BASE_ADDRESS),
dev_cfg->flash_size);
#endif /* CONFIG_STM32_MEMMAP */

return 0;
}
Expand Down
Loading
Loading