diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 39d57ebc188..bf6fa61c434 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -11,6 +11,12 @@ config FLASH_HAS_DRIVER_ENABLED help This option is enabled when any flash driver is enabled. +config FLASH_HAS_EX_OP + bool + help + This option is selected by drivers that support flash extended + operations. + config FLASH_HAS_PAGE_LAYOUT bool help @@ -78,6 +84,14 @@ config FLASH_PAGE_LAYOUT help Enables API for retrieving the layout of flash memory pages. +config FLASH_EX_OP_ENABLED + bool "API for extended flash operations" + depends on FLASH_HAS_EX_OP + default n + help + Enables flash extended operations API. It can be used to perform + non-standard operations e.g. manipulating flash protection. + config FLASH_INIT_PRIORITY int "Flash init priority" default KERNEL_INIT_PRIORITY_DEVICE diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c index 6ffb6c7fe42..b83a739a5d4 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -98,3 +98,22 @@ static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, #include #endif /* CONFIG_FLASH_JESD216_API */ + +#ifdef CONFIG_FLASH_EX_OP_ENABLED + +static inline int z_vrfy_flash_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out) +{ + Z_OOPS(Z_SYSCALL_DRIVER_FLASH(dev, ex_op)); + + /* + * If the code is a vendor code, then ex_op function have to perform + * verification. Zephyr codes should be verified here, but currently + * there are no Zephyr extended codes yet. + */ + + return z_impl_flash_ex_op(dev, code, in, out); +} +#include + +#endif /* CONFIG_FLASH_EX_OP_ENABLED */ diff --git a/include/zephyr/drivers/flash.h b/include/zephyr/drivers/flash.h index d1d56bdd456..df2402c1a86 100644 --- a/include/zephyr/drivers/flash.h +++ b/include/zephyr/drivers/flash.h @@ -125,6 +125,8 @@ typedef void (*flash_api_pages_layout)(const struct device *dev, typedef int (*flash_api_sfdp_read)(const struct device *dev, off_t offset, void *data, size_t len); typedef int (*flash_api_read_jedec_id)(const struct device *dev, uint8_t *id); +typedef int (*flash_api_ex_op)(const struct device *dev, uint16_t code, + const uintptr_t in, void *out); __subsystem struct flash_driver_api { flash_api_read read; @@ -138,6 +140,9 @@ __subsystem struct flash_driver_api { flash_api_sfdp_read sfdp_read; flash_api_read_jedec_id read_jedec_id; #endif /* CONFIG_FLASH_JESD216_API */ +#if defined(CONFIG_FLASH_EX_OP_ENABLED) + flash_api_ex_op ex_op; +#endif /* CONFIG_FLASH_EX_OP_ENABLED */ }; /** @@ -422,6 +427,67 @@ static inline const struct flash_parameters *z_impl_flash_get_parameters(const s return api->get_parameters(dev); } +/** + * @brief Execute flash extended operation on given device + * + * Besides of standard flash operations like write or erase, flash controllers + * also support additional features like write protection or readout + * protection. These features are not available in every flash controller, + * what's more controllers can implement it in a different way. + * + * It doesn't make sense to add a separate flash API function for every flash + * controller feature, because it could be unique (supported on small number of + * flash controllers) or the API won't be able to represent the same feature on + * every flash controller. + * + * @param dev Flash device + * @param code Operation which will be executed on the device. + * @param in Pointer to input data used by operation. If operation doesn't + * need any input data it could be NULL. + * @param out Pointer to operation output data. If operation doesn't produce + * any output it could be NULL. + * + * @retval 0 on success. + * @retval -ENOTSUP if given device doesn't support extended operation. + * @retval -ENOSYS if support for extended operations is not enabled in Kconfig + * @retval negative value on extended operation errors. + */ +__syscall int flash_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out); + +/* + * Extended operation interface provides flexible way for supporting flash + * controller features. Code space is divided equally into Zephyr codes + * (MSb == 0) and vendor codes (MSb == 1). This way we can easily add extended + * operations to the drivers without cluttering the API or problems with API + * incompatibility. Extended operation can be promoted from vendor codes to + * Zephyr codes if the feature is available in most flash controllers and + * can be represented in the same way. + * + * It's not forbidden to have operation in Zephyr codes and vendor codes for + * the same functionality. In this case, vendor operation could provide more + * specific access when abstraction in Zephyr counterpart is insufficient. + */ +#define FLASH_EX_OP_VENDOR_BASE 0x8000 +#define FLASH_EX_OP_IS_VENDOR(c) ((c) & FLASH_EX_OP_VENDOR_BASE) + +static inline int z_impl_flash_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out) +{ +#if defined(CONFIG_FLASH_EX_OP_ENABLED) + const struct flash_driver_api *api = + (const struct flash_driver_api *)dev->api; + + if (api->ex_op == NULL) { + return -ENOTSUP; + } + + return api->ex_op(dev, code, in, out); +#else + return -ENOSYS; +#endif /* CONFIG_FLASH_EX_OP_ENABLED */ +} + #ifdef __cplusplus } #endif