diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 5ec28d3fd4816..20e6feb957ab9 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -97,7 +97,7 @@ config FLASH_STM32_OPTION_BYTES config USE_MICROCHIP_QSPI_FLASH_WITH_STM32 bool "Include patch for Microchip qspi flash when running with stm32" - depends on DT_HAS_ST_STM32_QSPI_NOR_ENABLED + depends on FLASH_STM32_QSPI || FLASH_STM32_OSPI || FLASH_STM32_XSPI help Set to use Microchip QSPI flash memories which use the PP_1_1_4 opcode (32H) for the PP_1_4_4 operation (usually 38H). diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index ddcdc1390388a..d95f3a18d723e 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -707,6 +707,32 @@ static int stm32_ospi_write_enable(struct flash_stm32_ospi_data *dev_data, return stm32_ospi_wait_auto_polling(dev_data, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE); } +static int ospi_write_unprotect(const struct device *dev) +{ + struct flash_stm32_ospi_data *dev_data = dev->data; + int ret = 0; + + /* This is a SPI/STR command to issue to the external Flash device */ + OSPI_RegularCmdTypeDef cmd_unprotect = ospi_prepare_cmd(OSPI_SPI_MODE, OSPI_STR_TRANSFER); + + cmd_unprotect.Instruction = SPI_NOR_CMD_ULBPR; + cmd_unprotect.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; + cmd_unprotect.AddressMode = HAL_OSPI_ADDRESS_NONE; + cmd_unprotect.DataMode = HAL_OSPI_DATA_NONE; + + if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { + ret = stm32_ospi_write_enable(dev_data, OSPI_SPI_MODE, OSPI_STR_TRANSFER); + + if (ret != 0) { + return ret; + } + + ret = ospi_send_cmd(dev, &cmd_unprotect); + } + + return ret; +} + /* Write Flash configuration register 2 with new dummy cycles */ static int stm32_ospi_write_cfg2reg_dummy(OSPI_HandleTypeDef *hospi, uint8_t nor_mode, uint8_t nor_rate) @@ -1487,6 +1513,10 @@ static int flash_stm32_ospi_write(const struct device *dev, off_t addr, case SPI_NOR_CMD_PP_1_4_4_4B: __fallthrough; case SPI_NOR_CMD_PP_1_4_4: +#if defined(CONFIG_USE_MICROCHIP_QSPI_FLASH_WITH_STM32) + /* Microchip QSPI flash uses PP_1_1_4 opcode for the PP_1_4_4 operation */ + cmd_pp.Instruction = SPI_NOR_CMD_PP_1_1_4; +#endif /* CONFIG_USE_MICROCHIP_QSPI_FLASH_WITH_STM32 */ cmd_pp.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; cmd_pp.AddressMode = HAL_OSPI_ADDRESS_4_LINES; cmd_pp.DataMode = HAL_OSPI_DATA_4_LINES; @@ -2569,6 +2599,13 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + ret = ospi_write_unprotect(dev); + if (ret != 0) { + LOG_ERR("write unprotect failed: %d", ret); + return -ENODEV; + } + LOG_DBG("Write Un-protected"); + #ifdef CONFIG_STM32_MEMMAP /* Now configure the octo Flash in MemoryMapped (access by address) */ ret = stm32_ospi_set_memorymap(dev); diff --git a/drivers/flash/flash_stm32_xspi.c b/drivers/flash/flash_stm32_xspi.c index 0f6fbf193e28f..a7a2d56d90f57 100644 --- a/drivers/flash/flash_stm32_xspi.c +++ b/drivers/flash/flash_stm32_xspi.c @@ -567,6 +567,31 @@ static int stm32_xspi_write_enable(const struct device *dev, return stm32_xspi_wait_auto_polling(dev, &s_config, HAL_XSPI_TIMEOUT_DEFAULT_VALUE); } +static int xspi_write_unprotect(const struct device *dev) +{ + int ret = 0; + + /* This is a SPI/STR command to issue to the external Flash device */ + XSPI_RegularCmdTypeDef cmd_unprotect = xspi_prepare_cmd(XSPI_SPI_MODE, XSPI_STR_TRANSFER); + + cmd_unprotect.Instruction = SPI_NOR_CMD_ULBPR; + cmd_unprotect.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; + cmd_unprotect.AddressMode = HAL_XSPI_ADDRESS_NONE; + cmd_unprotect.DataMode = HAL_XSPI_DATA_NONE; + + if (IS_ENABLED(DT_INST_PROP(0, requires_ulbpr))) { + ret = stm32_xspi_write_enable(dev, XSPI_SPI_MODE, XSPI_STR_TRANSFER); + + if (ret != 0) { + return ret; + } + + ret = xspi_send_cmd(dev, &cmd_unprotect); + } + + return ret; +} + /* Write Flash configuration register 2 with new dummy cycles */ static int stm32_xspi_write_cfg2reg_dummy(const struct device *dev, uint8_t nor_mode, uint8_t nor_rate) @@ -1355,6 +1380,10 @@ static int flash_stm32_xspi_write(const struct device *dev, off_t addr, case SPI_NOR_CMD_PP_1_4_4_4B: __fallthrough; case SPI_NOR_CMD_PP_1_4_4: { +#if defined(CONFIG_USE_MICROCHIP_QSPI_FLASH_WITH_STM32) + /* Microchip QSPI flash uses PP_1_1_4 opcode for the PP_1_4_4 operation */ + cmd_pp.Instruction = SPI_NOR_CMD_PP_1_1_4; +#endif /* CONFIG_USE_MICROCHIP_QSPI_FLASH_WITH_STM32 */ cmd_pp.InstructionMode = HAL_XSPI_INSTRUCTION_1_LINE; cmd_pp.AddressMode = HAL_XSPI_ADDRESS_4_LINES; cmd_pp.DataMode = HAL_XSPI_DATA_4_LINES; @@ -2372,6 +2401,13 @@ static int flash_stm32_xspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + ret = xspi_write_unprotect(dev); + if (ret != 0) { + LOG_ERR("write unprotect failed: %d", ret); + return -ENODEV; + } + LOG_DBG("Write Un-protected"); + #ifdef CONFIG_STM32_MEMMAP ret = stm32_xspi_set_memorymap(dev); if (ret != 0) { diff --git a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml index fd841fd00bdc5..30f7da29cebe8 100644 --- a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml @@ -109,3 +109,12 @@ properties: * 2READ 1-2-2 (0xBB) -> 2READ 1-2-2 4B (0xBC) * QREAD 1-1-4 (0x6B) -> QREAD 1-1-4 4B (0x6C) * 4READ 1-4-4 (0xEB) -> 4READ 1-4-4 4B (0xEC) + requires-ulbpr: + type: boolean + description: | + Indicates the device requires the ULBPR (0x98) command. + + Some flash chips such as the Microchip SST26VF series have a block + protection register that initializes to write-protected. Use this + property to indicate that the BPR must be unlocked before write + operations can proceed.