diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 8bc0c734ef1..a152e9ffeab 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NATIVE_POSIX flash_native_posix.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) zephyr_sources(flash_stm32.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 21c3219fd99..a3f59b34a2a 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -69,4 +69,6 @@ source "drivers/flash/Kconfig.w25qxxdv" source "drivers/flash/Kconfig.simulator" +source "drivers/flash/Kconfig.rv32m1" + endif # FLASH diff --git a/drivers/flash/Kconfig.rv32m1 b/drivers/flash/Kconfig.rv32m1 new file mode 100644 index 00000000000..3fa4b1c2ad5 --- /dev/null +++ b/drivers/flash/Kconfig.rv32m1 @@ -0,0 +1,17 @@ +# +# Copyright (c) 2019 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_FLASH_RV32M1 + bool "RV32M1 flash shim driver" + depends on HAS_RV32M1_FTFX + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + help + Enables the RV32M1 flash shim driver. + WARNING: This driver will disable the system interrupts for + the duration of the flash erase/write operations. This will + have an impact on the overall system performance - whether + this is acceptable or not will depend on the use case. diff --git a/drivers/flash/soc_flash_rv32m1.c b/drivers/flash/soc_flash_rv32m1.c new file mode 100644 index 00000000000..b91fc7f84ab --- /dev/null +++ b/drivers/flash/soc_flash_rv32m1.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2016 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "flash_priv.h" + +#include "fsl_common.h" +#include "fsl_flash.h" + +#define CONFIG_FLASH_SIZE DT_FLASH_SIZE + +struct flash_priv { + flash_config_t config; + /* + * HACK: flash write protection is managed in software. + */ + struct k_sem write_lock; + u32_t pflash_block_base; +}; + +/* + * Interrupt vectors could be executed from flash hence the need for locking. + * The underlying MCUX driver takes care of copying the functions to SRAM. + * + * For more information, see the application note below on Read-While-Write + * http://cache.freescale.com/files/32bit/doc/app_note/AN4695.pdf + * + */ + +static int flash_mcux_erase(struct device *dev, off_t offset, size_t len) +{ + struct flash_priv *priv = dev->driver_data; + u32_t addr; + status_t rc; + unsigned int key; + + if (k_sem_take(&priv->write_lock, K_NO_WAIT)) { + return -EACCES; + } + + addr = offset + priv->pflash_block_base; + + key = irq_lock(); + rc = FLASH_Erase(&priv->config, addr, len, kFLASH_ApiEraseKey); + irq_unlock(key); + + k_sem_give(&priv->write_lock); + + return (rc == kStatus_Success) ? 0 : -EINVAL; +} + +static int flash_mcux_read(struct device *dev, off_t offset, + void *data, size_t len) +{ + struct flash_priv *priv = dev->driver_data; + u32_t addr; + + /* + * The MCUX supports different flash chips whose valid ranges are + * hidden below the API: until the API export these ranges, we can not + * do any generic validation + */ + addr = offset + priv->pflash_block_base; + + memcpy(data, (void *) addr, len); + + return 0; +} + +static int flash_mcux_write(struct device *dev, off_t offset, + const void *data, size_t len) +{ + struct flash_priv *priv = dev->driver_data; + u32_t addr; + status_t rc; + unsigned int key; + + if (k_sem_take(&priv->write_lock, K_NO_WAIT)) { + return -EACCES; + } + + addr = offset + priv->pflash_block_base; + + key = irq_lock(); + rc = FLASH_Program(&priv->config, addr, (uint32_t *) data, len); + irq_unlock(key); + + k_sem_give(&priv->write_lock); + + return (rc == kStatus_Success) ? 0 : -EINVAL; +} + +static int flash_mcux_write_protection(struct device *dev, bool enable) +{ + struct flash_priv *priv = dev->driver_data; + int rc = 0; + + if (enable) { + rc = k_sem_take(&priv->write_lock, K_FOREVER); + } else { + k_sem_give(&priv->write_lock); + } + + return rc; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static const struct flash_pages_layout dev_layout = { + .pages_count = KB(CONFIG_FLASH_SIZE) / + DT_SOC_NV_FLASH_0_ERASE_BLOCK_SIZE, + .pages_size = DT_SOC_NV_FLASH_0_ERASE_BLOCK_SIZE, +}; + +static void flash_mcux_pages_layout( + struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + *layout = &dev_layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static struct flash_priv flash_data; + +static const struct flash_driver_api flash_mcux_api = { + .write_protection = flash_mcux_write_protection, + .erase = flash_mcux_erase, + .write = flash_mcux_write, + .read = flash_mcux_read, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_mcux_pages_layout, +#endif + .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE, +}; + +static int flash_mcux_init(struct device *dev) +{ + struct flash_priv *priv = dev->driver_data; + u32_t pflash_block_base; + status_t rc; + + CLOCK_EnableClock(kCLOCK_Mscm); + + k_sem_init(&priv->write_lock, 0, 1); + + rc = FLASH_Init(&priv->config); + + FLASH_GetProperty(&priv->config, kFLASH_PropertyPflashBlockBaseAddr, + (uint32_t *)&pflash_block_base); + priv->pflash_block_base = (u32_t) pflash_block_base; + + return (rc == kStatus_Success) ? 0 : -EIO; +} + +DEVICE_AND_API_INIT(flash_mcux, DT_FLASH_DEV_NAME, + flash_mcux_init, &flash_data, NULL, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &flash_mcux_api); + diff --git a/ext/hal/openisa/vega_sdk_riscv/Kconfig b/ext/hal/openisa/vega_sdk_riscv/Kconfig index 02519b11eb2..6ef88c32e7a 100644 --- a/ext/hal/openisa/vega_sdk_riscv/Kconfig +++ b/ext/hal/openisa/vega_sdk_riscv/Kconfig @@ -15,3 +15,10 @@ config HAS_RV32M1_LPI2C bool help Set if the low power i2c (LPI2C) module is present in the SoC. + +config HAS_RV32M1_FTFX + bool + help + Set if the flash memory (FTFA, FTFE, or FTFL) module is present in + the SoC. + diff --git a/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt b/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt index a50be0c20af..b62e097788e 100644 --- a/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt +++ b/ext/hal/openisa/vega_sdk_riscv/devices/RV32M1/drivers/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_include_directories(.) zephyr_sources(fsl_clock.c) zephyr_sources_ifdef(CONFIG_UART_RV32M1_LPUART fsl_lpuart.c) zephyr_sources_ifdef(CONFIG_I2C_RV32M1_LPI2C fsl_lpi2c.c) +zephyr_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 fsl_flash.c) diff --git a/soc/riscv32/openisa_rv32m1/Kconfig.defconfig b/soc/riscv32/openisa_rv32m1/Kconfig.defconfig index 758e99813f5..3614102bb79 100644 --- a/soc/riscv32/openisa_rv32m1/Kconfig.defconfig +++ b/soc/riscv32/openisa_rv32m1/Kconfig.defconfig @@ -173,4 +173,14 @@ config I2C_RV32M1_LPI2C endif # I2C +if FLASH + +config SOC_FLASH_RV32M1 + default y + +config FLASH_BASE_ADDRESS + default $(dt_hex_val,DT_FLASH_BASE_ADDRESS) + +endif # FLASH + endif # SOC_OPENISA_RV32M1_RISCV32 diff --git a/soc/riscv32/openisa_rv32m1/Kconfig.soc b/soc/riscv32/openisa_rv32m1/Kconfig.soc index 4805f167f24..77f28c14672 100644 --- a/soc/riscv32/openisa_rv32m1/Kconfig.soc +++ b/soc/riscv32/openisa_rv32m1/Kconfig.soc @@ -14,6 +14,8 @@ config SOC_OPENISA_RV32M1_RISCV32 select VEGA_SDK_HAL select RISCV_SOC_INTERRUPT_INIT select CLOCK_CONTROL + select HAS_RV32M1_FTFX + select HAS_FLASH_LOAD_OFFSET help Enable support for OpenISA RV32M1 RISC-V processors. Choose this option to target the RI5CY or ZERO-RISCY core. This diff --git a/soc/riscv32/openisa_rv32m1/dts_fixup.h b/soc/riscv32/openisa_rv32m1/dts_fixup.h new file mode 100644 index 00000000000..decc3ac1ee3 --- /dev/null +++ b/soc/riscv32/openisa_rv32m1/dts_fixup.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2019 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* SoC level DTS fixup file */ + +#if defined(CONFIG_SOC_OPENISA_RV32M1_RISCV32) + +#define DT_FLASH_DEV_BASE_ADDRESS DT_OPENISA_RV32M1_FTFE_40023000_BASE_ADDRESS +#define DT_FLASH_DEV_NAME DT_OPENISA_RV32M1_FTFE_40023000_LABEL + +#endif /* CONFIG_SOC_OPENISA_RV32M1_RISCV32 */ + +/* End of SoC Level DTS fixup file */