From 7593a14a0af2b7984977f3c8d8365cbbc7e9528a Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 1 Jun 2023 15:39:02 +0200 Subject: [PATCH] drivers: flash: stm32 ospi drivers with Memorymapped mode Enable the MemoryMapped Mode for the stm32 octoFlash driver Configure the Flash in MemoryMapped to use in XiP mode. With this mode the erase and write are not supported. Address and size are given by the DTS register property. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_ospi.c | 186 ++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 4 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index e2a22fba6cf..5a9f73fe7bf 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -978,11 +978,135 @@ 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) + : SPI_NOR_OCMD_RD) + : 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); +} +#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) @@ -1012,6 +1136,13 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, return -ENOTSUP; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + LOG_DBG("MemoryMap : cannot erase"); + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd_erase = { .OperationType = HAL_OSPI_OPTYPE_COMMON_CFG, .FlashId = HAL_OSPI_FLASH_ID_1, @@ -1026,9 +1157,9 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, 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) @@ -1137,6 +1268,7 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, } +end_erase: ospi_unlock_thread(dev); return ret; @@ -1161,6 +1293,17 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + 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); + + return 0; + } +#endif /* CONFIG_STM32_MEMMAP */ + OSPI_RegularCmdTypeDef cmd = ospi_prepare_cmd(dev_cfg->data_mode, dev_cfg->data_rate); if (dev_cfg->data_mode != OSPI_OPI_MODE) { @@ -1229,7 +1372,10 @@ static int flash_stm32_ospi_read(const struct device *dev, off_t addr, 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) { @@ -1249,6 +1395,16 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, return 0; } +#ifdef CONFIG_STM32_MEMMAP + if (stm32_ospi_is_memorymap(dev)) { + LOG_DBG("MemoryMapped Write offset: 0x%lx, len: %zu", + (long)(STM32_OSPI_BASE_ADDRESS + addr), + size); + memcpy((uint8_t *)STM32_OSPI_BASE_ADDRESS + addr, data, size); + + return 0; + } +#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); @@ -1913,6 +2069,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 @@ -2292,9 +2458,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; }