From c2933175c9b523b4ca39c006d4dcf72415669bdd Mon Sep 17 00:00:00 2001 From: crasbe Date: Wed, 17 Apr 2024 16:26:45 +0200 Subject: [PATCH] drivers/mtd_spi_nor: removed Kconfig & added MX/ISSI security features --- drivers/Kconfig | 1 - drivers/include/mtd_spi_nor.h | 69 ++++-- drivers/mtd_spi_nor/Kconfig | 22 -- .../mtd_spi_nor/include/mtd_spi_nor_defines.h | 232 ++++++++++++++++++ drivers/mtd_spi_nor/mtd_spi_nor.c | 40 ++- drivers/mtd_spi_nor/mtd_spi_nor_configs.c | 70 +++++- 6 files changed, 378 insertions(+), 56 deletions(-) delete mode 100644 drivers/mtd_spi_nor/Kconfig create mode 100644 drivers/mtd_spi_nor/include/mtd_spi_nor_defines.h diff --git a/drivers/Kconfig b/drivers/Kconfig index facbb5d74db52..a2f3ee7867684 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -56,7 +56,6 @@ endmenu # Sensor Device Drivers menu "Storage Device Drivers" rsource "mtd_sdcard/Kconfig" -rsource "mtd_spi_nor/Kconfig" endmenu # Storage Device Drivers endmenu # Drivers diff --git a/drivers/include/mtd_spi_nor.h b/drivers/include/mtd_spi_nor.h index 0624a6ac1052d..d8ceb2b08bac2 100644 --- a/drivers/include/mtd_spi_nor.h +++ b/drivers/include/mtd_spi_nor.h @@ -36,24 +36,6 @@ extern "C" { #endif -#define STATUS_WIP 0x01u -#define STATUS_WEL 0x02u -#define STATUS_BP0 0x04u -#define STATUS_BP1 0x08u -#define STATUS_BP2 0x10u -#define STATUS_BP3 0x20u -#define STATUS_QE 0x40u -#define STATUS_SRWD 0x80u - -#define SECURITY_SOTP 0x01u -#define SECURITY_LDSO 0x02u -#define SECURITY_PSB 0x04u -#define SECURITY_ESB 0x08u -#define SECURITY_XXXXX 0x10u -#define SECURITY_PFAIL 0x20u -#define SECURITY_EFAIL 0x40u -#define SECURITY_WPSEL 0x80u - /** * @brief SPI NOR flash opcode table */ @@ -71,7 +53,7 @@ typedef struct { uint8_t chip_erase; /**< Chip erase */ uint8_t sleep; /**< Deep power down */ uint8_t wake; /**< Release from deep power down */ - uint8_t rdscur; /**< Read security register */ + uint8_t security; /**< Read security register */ } mtd_spi_nor_opcode_t; /** @@ -114,6 +96,17 @@ typedef struct __attribute__((packed)) { */ #define SPI_NOR_F_SECT_64K (4) +/** + * @brief Flag to set when the device supports the Macronix security register (rdscur opcode) + */ +#define SPI_NOR_F_MX_SECUR (256) + +/** + * @brief Flag to set when the device supports the ISSI security/extended read register + * (rderp opcode) + */ +#define SPI_NOR_F_ISSI_SECUR (512) + /** * @brief Compile-time parameters for a serial flash device */ @@ -188,7 +181,8 @@ extern const mtd_desc_t mtd_spi_nor_driver; * The numbers were taken from Micron M25P16, but the same opcodes can * be found in Macronix MX25L25735E, and multiple other data sheets for * different devices, as well as in the Linux kernel, so they seem quite - * sensible for default values. */ + * sensible for default values. + */ extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default; /** @@ -198,6 +192,41 @@ extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default; */ extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default_4bytes; +/** + * @brief Macronix-specific opcodes including security features + * + * Some Macronix NOR Flashs have a dedicated security register which has flags to indicate + * if the last program/erase operation was successful or not. The RDSCUR opcode is + * used ot access this register, which requires a vendor specific opcode set. + * To utilize this feature, the SPI_NOR_F_MX_SECUR flag has to be set as well. + */ +extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_macronix; + +/** + * @brief Macronix-specific 4-byte opcodes including security features + * + * Commands for 4-byte address chips (above 128Mb) + */ +extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_macronix_4bytes; + +/** + * @brief ISSI-specific opcodes including security features + * + * Some ISSI NOR Flashs have a dedicated Extended Read Parameter register which has flags + * to indicate if the last program/erase operation was successful or not. + * The RDERP opcode is used to access this register, which requires a vendor specific + * opcode set. + * To utilize this feature, the SPI_NOR_F_MX_SECUR flag has to be set as well. + */ +extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_issi; + +/** + * @brief ISSI-specific 4-byte opcodes including security features + * + * Commands for 4-byte address chips (above 128Mb) + */ +extern const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_issi_4bytes; + #ifdef __cplusplus } #endif diff --git a/drivers/mtd_spi_nor/Kconfig b/drivers/mtd_spi_nor/Kconfig deleted file mode 100644 index 02fc754077ee2..0000000000000 --- a/drivers/mtd_spi_nor/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2020 Continental -# -# This file is subject to the terms and conditions of the GNU Lesser -# General Public License v2.1. See the file LICENSE in the top level -# directory for more details. -# -menuconfig KCONFIG_USEMODULE_MTD_SPI_NOR - bool "Configure MTD_SPI_NOR driver" - depends on USEMODULE_MTD_SPI_NOR - help - Configure the MODULE_MTD_SPI_NOR driver using Kconfig. - -if KCONFIG_USEMODULE_MTD_SPI_NOR - -config MTD_SPI_NOR_RDSCUR - bool "Enable rdscur command usage" - help - Enable this if your SPI flash supports RDSCUR (Read Security register) - command (Macronix flashes do). In that case a rdscur command is issued - after a program or an erase command to check if it succeed. - -endif # KCONFIG_USEMODULE_MTD_SPI_NOR diff --git a/drivers/mtd_spi_nor/include/mtd_spi_nor_defines.h b/drivers/mtd_spi_nor/include/mtd_spi_nor_defines.h new file mode 100644 index 0000000000000..60157dff1a367 --- /dev/null +++ b/drivers/mtd_spi_nor/include/mtd_spi_nor_defines.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2024 Technische Universität Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_mtd_spi_nor + * @{ + * + * @file + * @brief Definitions for the MTD SPI NOR Flash driver + * + * More detailed information about the file and the functionality implemented. + * + * @author Christopher Büchse + * + */ + +#ifndef MTD_SPI_NOR_DEFINES_H +#define MTD_SPI_NOR_DEFINES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Common Status Bits from the Status Register of SPI NOR Flashs + * @{ + */ +/** + * @brief Write In Progress Flag (R) + * + * 0 - Device is ready + * 1 - Write cycle in progress and device is busy + */ +#define SPI_NOR_STATUS_WIP 0x01u + +/** + * @brief Write Enable Latch Flag (R/W) + * + * 0 - Device is not write enabled + * 1 - Device is write enabled + */ +#define SPI_NOR_STATUS_WEL 0x02u + +/** + * @brief Block Protection Bit 0 Flag (R/W) + * + * 0 - Specific blocks are not write-protected + * 1 - Specific blocks are write-protected + */ +#define SPI_NOR_STATUS_BP0 0x04u + +/** + * @brief Block Protection Bit 1 Flag (R/W) + * + * 0 - Specific blocks are not write-protected + * 1 - Specific blocks are write-protected + */ +#define SPI_NOR_STATUS_BP1 0x08u + +/** + * @brief Block Protection Bit 2 Flag (R/W) + * + * 0 - Specific blocks are not write-protected + * 1 - Specific blocks are write-protected + */ +#define SPI_NOR_STATUS_BP2 0x10u + +/** + * @brief Block Protection Bit 3 Flag (R/W) + * + * 0 - Specific blocks are not write-protected + * 1 - Specific blocks are write-protected + */ +#define SPI_NOR_STATUS_BP3 0x20u + +/** + * @brief Quad Enable Flag (R/W) + * + * 0 - Quad output function disabled + * 1 - Quad output function enabled + */ +#define SPI_NOR_STATUS_QE 0x40u + +/** + * @brief Status Register Write Disable Flag (R/W) + * + * 0 - Status Register is not write protected + * 1 - Status Register is write protected + */ +#define SPI_NOR_STATUS_SRWD 0x80u + +/** @} */ + +/** + * @name Macronix Style Security Register Bits + * @note These flags were taken from the MX25L51245G datasheet, but probably apply + * to other devices from Macronix as well. + * @{ + */ +/** + * @brief Secured OTP Flag + * + * 0 - OTP area not factory locked + * 1 - OTP area factory locked + */ +#define MX_SECURITY_SOTP 0x01u + +/** + * @brief Lock-down Secured OTP Flag + * + * 0 - OTP area not (user) locked + * 1 - OTP area locked (can not be programmed/erased) + */ +#define MX_SECURITY_LDSO 0x02u + +/** + * @brief Program Suspend Flag + * + * 0 - Program is not suspended + * 1 - Program suspended + */ +#define MX_SECURITY_PSB 0x04u + +/** + * @brief Erase Suspend Flag + * + * 0 - Erase is not suspended + * 1 - Erase is suspended + */ +#define MX_SECURITY_ESB 0x08u + +/** + * @brief Reserved + */ +#define MX_SECURITY_XXXXX 0x10u + +/** + * @brief Program Fail Flag + * + * 0 - Program Operation succeeded + * 1 - Program Operation failed or region is protected + */ +#define MX_SECURITY_PFAIL 0x20u + +/** + * @brief Erase Fail Flag + * + * 0 - Erase Operation succeeded + * 1 - Erase Operation failed or region is protected + */ +#define MX_SECURITY_EFAIL 0x40u + +/** + * @brief Write Protection Selection Flag + * + * 0 - Normal Write Protect mode + * 1 - Advanced Sector Protection mode + */ +#define MX_SECURITY_WPSEL 0x80u +/** @} */ + +/** + * @name ISSI Style Security Register Bits from Extended Read Register (ERP) + * @note These flags were taken from the IS25LE01G datasheet, but probably + * apply to other devices from ISSI as well. + * @{ + */ + +/** + * @brief Reserved + */ +#define IS_SECURITY_XXXXX 0x01u + +/** + * @brief Protection Error Flag (R) + * + * 0 - No protection error + * 1 - Protection Error occurred in program or erase + */ +#define IS_SECURITY_PROT_E 0x02u + +/** + * @brief Program Error Flag (R) + * + * 0 - Program Operation succeeded + * 1 - Program Operation failed or region is protected + */ +#define IS_SECURITY_P_ERR 0x04u + +/** + * @brief Erase Error Flag (R) + * + * 0 - Erase Operation succeeded + * 1 - Erase Operation failed or region is protected + */ +#define IS_SECURITY_E_ERR 0x08u + +/** + * @brief Data Learning Pattern Flag (R/W) + * + * 0 - DLP is disabled + * 1 - DLP is enabled + */ +#define IS_SECURITY_DLPEN 0x10u + +/** + * @brief Output Driver Strength Bit 0 (R/W) + */ +#define IS_SECURITY_ODS0 0x20u + +/** + * @brief Output Driver Strength Bit 1 (R/W) + */ +#define IS_SECURITY_ODS1 0x40u + +/** + * @brief Output Driver Strength Bit 2 (R/W) + */ +#define IS_SECURITY_ODS2 0x80u +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* MTD_SPI_NOR_DEFINES_H */ +/** @} */ diff --git a/drivers/mtd_spi_nor/mtd_spi_nor.c b/drivers/mtd_spi_nor/mtd_spi_nor.c index 832b5a05fa909..928f6e6e1d2eb 100644 --- a/drivers/mtd_spi_nor/mtd_spi_nor.c +++ b/drivers/mtd_spi_nor/mtd_spi_nor.c @@ -35,6 +35,8 @@ #include "time_units.h" #include "thread.h" +#include "include/mtd_spi_nor_defines.h" + #if IS_USED(MODULE_ZTIMER) #include "ztimer.h" #elif IS_USED(MODULE_XTIMER) @@ -361,7 +363,7 @@ static inline void wait_for_write_enable_cleared(const mtd_spi_nor_t *dev) mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status)); TRACE("mtd_spi_nor: wait device status = 0x%02x, waiting !WEL\n", (unsigned int)status); - if ((status & STATUS_WEL) == 0) { + if ((status & SPI_NOR_STATUS_WEL) == 0) { break; } thread_yield(); @@ -375,7 +377,7 @@ static inline void wait_for_write_enable_set(const mtd_spi_nor_t *dev) mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status)); TRACE("mtd_spi_nor: wait device status = 0x%02x, waiting WEL\n", (unsigned int)status); - if (status & STATUS_WEL) { + if (status & SPI_NOR_STATUS_WEL) { break; } thread_yield(); @@ -399,7 +401,7 @@ static inline void wait_for_write_complete(const mtd_spi_nor_t *dev, uint32_t us mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status)); TRACE("mtd_spi_nor: wait device status = 0x%02x, waiting !WIP\n", (unsigned int)status); - if ((status & STATUS_WIP) == 0) { + if ((status & SPI_NOR_STATUS_WIP) == 0) { break; } i++; @@ -666,11 +668,19 @@ static int mtd_spi_nor_write_page(mtd_dev_t *mtd, const void *src, uint32_t page /* Wait for WEL to be cleared */ wait_for_write_enable_cleared(dev); - if (IS_ACTIVE(CONFIG_MTD_SPI_NOR_RDSCUR)) { + if (dev->params->flag & SPI_NOR_F_MX_SECUR) { /* Read security register */ - uint8_t rdscur; - mtd_spi_cmd_read(dev, dev->params->opcode->rdscur, &rdscur, sizeof(rdscur)); - if (rdscur & SECURITY_PFAIL) { + uint8_t security; + mtd_spi_cmd_read(dev, dev->params->opcode->security, &security, sizeof(security)); + if (security & MX_SECURITY_PFAIL) { + DEBUG("mtd_spi_nor_write: ERR: page program failed!\n"); + ret = -EIO; + } + } else if (dev->params->flag & SPI_NOR_F_ISSI_SECUR) { + /* Read extended read register for security flags */ + uint8_t security; + mtd_spi_cmd_read(dev, dev->params->opcode->security, &security, sizeof(security)); + if (security & IS_SECURITY_P_ERR) { DEBUG("mtd_spi_nor_write: ERR: page program failed!\n"); ret = -EIO; } @@ -759,11 +769,19 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) /* Wait for WEL to be cleared */ wait_for_write_enable_cleared(dev); - if (IS_ACTIVE(CONFIG_MTD_SPI_NOR_RDSCUR)) { + if (dev->params->flag & SPI_NOR_F_MX_SECUR) { /* Read security register */ - uint8_t rdscur; - mtd_spi_cmd_read(dev, dev->params->opcode->rdscur, &rdscur, sizeof(rdscur)); - if (rdscur & SECURITY_EFAIL) { + uint8_t security; + mtd_spi_cmd_read(dev, dev->params->opcode->security, &security, sizeof(security)); + if (security & MX_SECURITY_EFAIL) { + DEBUG("mtd_spi_nor_erase: ERR: erase failed!\n"); + ret = -EIO; + } + } else if (dev->params->flag & SPI_NOR_F_ISSI_SECUR) { + /* Read extended read register for security flags */ + uint8_t security; + mtd_spi_cmd_read(dev, dev->params->opcode->security, &security, sizeof(security)); + if (security & IS_SECURITY_E_ERR) { DEBUG("mtd_spi_nor_erase: ERR: erase failed!\n"); ret = -EIO; } diff --git a/drivers/mtd_spi_nor/mtd_spi_nor_configs.c b/drivers/mtd_spi_nor/mtd_spi_nor_configs.c index 60e5b13e619be..15b717cf517c9 100644 --- a/drivers/mtd_spi_nor/mtd_spi_nor_configs.c +++ b/drivers/mtd_spi_nor/mtd_spi_nor_configs.c @@ -40,7 +40,6 @@ const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default = { .chip_erase = 0xc7, .sleep = 0xb9, .wake = 0xab, - .rdscur = 0x2b, }; const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default_4bytes = { @@ -57,7 +56,74 @@ const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default_4bytes = { .chip_erase = 0xc7, .sleep = 0xb9, .wake = 0xab, - .rdscur = 0x2b, +}; + +const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_macronix = { + .rdid = 0x9f, + .wren = 0x06, + .rdsr = 0x05, + .wrsr = 0x01, + .read = 0x03, + .read_fast = 0x0b, + .page_program = 0x02, + .sector_erase = 0x20, + .block_erase_32k = 0x52, + .block_erase_64k = 0xd8, + .chip_erase = 0xc7, + .sleep = 0xb9, + .wake = 0xab, + .security = 0x2b, +}; + +const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_macronix_4bytes = { + .rdid = 0x9f, + .wren = 0x06, + .rdsr = 0x05, + .wrsr = 0x01, + .read = 0x13, + .read_fast = 0x0c, + .page_program = 0x12, + .sector_erase = 0x21, + .block_erase_32k = 0x5c, + .block_erase_64k = 0xdc, + .chip_erase = 0xc7, + .sleep = 0xb9, + .wake = 0xab, + .security = 0x2b, +}; + +const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_issi = { + .rdid = 0x9f, + .wren = 0x06, + .rdsr = 0x05, + .wrsr = 0x01, + .read = 0x03, + .read_fast = 0x0b, + .page_program = 0x02, + .sector_erase = 0x20, + .block_erase_32k = 0x52, + .block_erase_64k = 0xd8, + .chip_erase = 0xc7, + .sleep = 0xb9, + .wake = 0xab, + .security = 0x81, +}; + +const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_issi_4bytes = { + .rdid = 0x9f, + .wren = 0x06, + .rdsr = 0x05, + .wrsr = 0x01, + .read = 0x13, + .read_fast = 0x0c, + .page_program = 0x12, + .sector_erase = 0x21, + .block_erase_32k = 0x5c, + .block_erase_64k = 0xdc, + .chip_erase = 0xc7, + .sleep = 0xb9, + .wake = 0xab, + .security = 0x81, }; /** @} */