stm32mp1: Add support for SPI-NAND boot device
STM32MP1 platform is able to boot from SPI-NAND devices.
These modifications add this support using the new
SPI-NAND framework.
Change-Id: I0d5448bdc4bde153c1209e8043846c0f935ae5ba
Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index ba5d22f..1f05d0b 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -36,6 +36,9 @@
/* Boot occurred on FMC */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U
+/* Boot occurred on QSPI NAND */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U
+
/**
* @brief Possible value of boot context field 'EmmcXferStatus'
*/
diff --git a/plat/st/stm32mp1/include/stm32mp1_boot_device.h b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
index ae6b02b..db80f93 100644
--- a/plat/st/stm32mp1/include/stm32mp1_boot_device.h
+++ b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
@@ -8,7 +8,9 @@
#define STM32MP1_BOOT_DEVICE_H
#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
int plat_get_raw_nand_data(struct rawnand_device *device);
+int plat_get_spi_nand_data(struct spinand_device *device);
#endif /* STM32MP1_BOOT_DEVICE_H */
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 71b3916..d25f3b3 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -28,17 +28,21 @@
STM32MP_EMMC ?= 0
STM32MP_SDMMC ?= 0
STM32MP_RAW_NAND ?= 0
+STM32MP_SPI_NAND ?= 0
-ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_NAND}),)
+ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_NAND} \
+ ${STM32MP_SPI_NAND}),)
$(error "No boot device driver is enabled")
endif
$(eval $(call assert_boolean,STM32MP_EMMC))
$(eval $(call assert_boolean,STM32MP_SDMMC))
$(eval $(call assert_boolean,STM32MP_RAW_NAND))
+$(eval $(call assert_boolean,STM32MP_SPI_NAND))
$(eval $(call add_define,STM32MP_EMMC))
$(eval $(call add_define,STM32MP_SDMMC))
$(eval $(call add_define,STM32MP_RAW_NAND))
+$(eval $(call add_define,STM32MP_SPI_NAND))
PLAT_INCLUDES := -Iplat/st/common/include/
PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
@@ -108,7 +112,16 @@
drivers/st/fmc/stm32_fmc2_nand.c
endif
-ifneq ($(filter 1,${STM32MP_RAW_NAND}),)
+ifeq (${STM32MP_SPI_NAND},1)
+BL2_SOURCES += drivers/mtd/nand/spi_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NAND},1)
+BL2_SOURCES += drivers/mtd/spi-mem/spi_mem.c \
+ drivers/st/spi/stm32_qspi.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND}),)
BL2_SOURCES += drivers/mtd/nand/core.c \
plat/st/stm32mp1/stm32mp1_boot_device.c
endif
diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c
index 8b1f07f..fa352f3 100644
--- a/plat/st/stm32mp1/stm32mp1_boot_device.c
+++ b/plat/st/stm32mp1/stm32mp1_boot_device.c
@@ -12,8 +12,8 @@
#define SZ_512 0x200U
-#if STM32MP_RAW_NAND
-static int get_data_from_otp(struct nand_device *nand_dev)
+#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
+static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
{
int result;
uint32_t nand_param;
@@ -81,28 +81,37 @@
NAND_BLOCK_NB_UNIT * nand_dev->block_size;
ecc:
- switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
- NAND_ECC_BIT_NB_SHIFT) {
- case NAND_ECC_BIT_NB_1_BITS:
- nand_dev->ecc.max_bit_corr = 1U;
- break;
+ if (is_slc) {
+ switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
+ NAND_ECC_BIT_NB_SHIFT) {
+ case NAND_ECC_BIT_NB_1_BITS:
+ nand_dev->ecc.max_bit_corr = 1U;
+ break;
- case NAND_ECC_BIT_NB_4_BITS:
- nand_dev->ecc.max_bit_corr = 4U;
- break;
+ case NAND_ECC_BIT_NB_4_BITS:
+ nand_dev->ecc.max_bit_corr = 4U;
+ break;
- case NAND_ECC_BIT_NB_8_BITS:
- nand_dev->ecc.max_bit_corr = 8U;
- break;
+ case NAND_ECC_BIT_NB_8_BITS:
+ nand_dev->ecc.max_bit_corr = 8U;
+ break;
- case NAND_ECC_ON_DIE:
- nand_dev->ecc.mode = NAND_ECC_ONDIE;
- break;
+ case NAND_ECC_ON_DIE:
+ nand_dev->ecc.mode = NAND_ECC_ONDIE;
+ break;
- default:
- if (nand_dev->ecc.max_bit_corr == 0U) {
- ERROR("No valid eccbit number\n");
- return -EINVAL;
+ default:
+ if (nand_dev->ecc.max_bit_corr == 0U) {
+ ERROR("No valid eccbit number\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* Selected multiple plane NAND */
+ if ((nand_param & NAND_PLANE_BIT_NB_MASK) != 0U) {
+ nand_dev->nb_planes = 2U;
+ } else {
+ nand_dev->nb_planes = 1U;
}
}
@@ -111,7 +120,7 @@
return 0;
}
-#endif
+#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */
#if STM32MP_RAW_NAND
int plat_get_raw_nand_data(struct rawnand_device *device)
@@ -119,7 +128,24 @@
device->nand_dev->ecc.mode = NAND_ECC_HW;
device->nand_dev->ecc.size = SZ_512;
+ return get_data_from_otp(device->nand_dev, true);
+}
+#endif
+
+#if STM32MP_SPI_NAND
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ zeromem(&device->spi_read_cache_op, sizeof(struct spi_mem_op));
+ device->spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE_4X;
+ device->spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.addr.nbytes = 2U;
+ device->spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.dummy.nbytes = 1U;
+ device->spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->spi_read_cache_op.data.dir = SPI_MEM_DATA_IN;
+
- return get_data_from_otp(device->nand_dev);
+ return get_data_from_otp(device->nand_dev, false);
}
#endif
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index 7ac9b5f..a427dcf 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -340,6 +340,9 @@
#define NAND_ECC_BIT_NB_8_BITS U(3)
#define NAND_ECC_ON_DIE U(4)
+/* NAND number of planes */
+#define NAND_PLANE_BIT_NB_MASK BIT(14)
+
/*******************************************************************************
* STM32MP1 TAMP
******************************************************************************/