Commit 57044228 authored by Lionel Debieve's avatar Lionel Debieve
Browse files

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: default avatarLionel Debieve <lionel.debieve@st.com>
parent 0581a887
...@@ -19,9 +19,11 @@ ...@@ -19,9 +19,11 @@
#include <drivers/mmc.h> #include <drivers/mmc.h>
#include <drivers/partition/partition.h> #include <drivers/partition/partition.h>
#include <drivers/raw_nand.h> #include <drivers/raw_nand.h>
#include <drivers/spi_nand.h>
#include <drivers/st/io_mmc.h> #include <drivers/st/io_mmc.h>
#include <drivers/st/io_stm32image.h> #include <drivers/st/io_stm32image.h>
#include <drivers/st/stm32_fmc2_nand.h> #include <drivers/st/stm32_fmc2_nand.h>
#include <drivers/st/stm32_qspi.h>
#include <drivers/st/stm32_sdmmc2.h> #include <drivers/st/stm32_sdmmc2.h>
#include <lib/mmio.h> #include <lib/mmio.h>
#include <lib/utils.h> #include <lib/utils.h>
...@@ -70,6 +72,17 @@ static io_mtd_dev_spec_t nand_dev_spec = { ...@@ -70,6 +72,17 @@ static io_mtd_dev_spec_t nand_dev_spec = {
static const io_dev_connector_t *nand_dev_con; static const io_dev_connector_t *nand_dev_con;
#endif #endif
#if STM32MP_SPI_NAND
static io_mtd_dev_spec_t spi_nand_dev_spec = {
.ops = {
.init = spi_nand_init,
.read = nand_read,
},
};
static const io_dev_connector_t *spi_dev_con;
#endif
#ifdef AARCH32_SP_OPTEE #ifdef AARCH32_SP_OPTEE
static const struct stm32image_part_info optee_header_partition_spec = { static const struct stm32image_part_info optee_header_partition_spec = {
.name = OPTEE_HEADER_IMAGE_NAME, .name = OPTEE_HEADER_IMAGE_NAME,
...@@ -226,6 +239,9 @@ static void print_boot_device(boot_api_context_t *boot_context) ...@@ -226,6 +239,9 @@ static void print_boot_device(boot_api_context_t *boot_context)
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
INFO("Using FMC NAND\n"); INFO("Using FMC NAND\n");
break; break;
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
INFO("Using SPI NAND\n");
break;
default: default:
ERROR("Boot interface not found\n"); ERROR("Boot interface not found\n");
panic(); panic();
...@@ -382,6 +398,60 @@ static void boot_fmc2_nand(boot_api_context_t *boot_context) ...@@ -382,6 +398,60 @@ static void boot_fmc2_nand(boot_api_context_t *boot_context)
} }
#endif /* STM32MP_RAW_NAND */ #endif /* STM32MP_RAW_NAND */
#if STM32MP_SPI_NAND
static void boot_spi_nand(boot_api_context_t *boot_context)
{
int io_result __unused;
uint8_t idx;
struct stm32image_part_info *part;
io_result = stm32_qspi_init();
assert(io_result == 0);
io_result = register_io_dev_mtd(&spi_dev_con);
assert(io_result == 0);
/* Open connections to device */
io_result = io_dev_open(spi_dev_con,
(uintptr_t)&spi_nand_dev_spec,
&storage_dev_handle);
assert(io_result == 0);
stm32image_dev_info_spec.device_size =
spi_nand_dev_spec.device_size;
idx = IMG_IDX_BL33;
part = &stm32image_dev_info_spec.part_info[idx];
part->part_offset = STM32MP_NAND_BL33_OFFSET;
part->bkp_offset = spi_nand_dev_spec.erase_size;
#ifdef AARCH32_SP_OPTEE
idx = IMG_IDX_OPTEE_HEADER;
part = &stm32image_dev_info_spec.part_info[idx];
part->part_offset = STM32MP_NAND_TEEH_OFFSET;
part->bkp_offset = spi_nand_dev_spec.erase_size;
idx = IMG_IDX_OPTEE_PAGED;
part = &stm32image_dev_info_spec.part_info[idx];
part->part_offset = STM32MP_NAND_TEED_OFFSET;
part->bkp_offset = spi_nand_dev_spec.erase_size;
idx = IMG_IDX_OPTEE_PAGER;
part = &stm32image_dev_info_spec.part_info[idx];
part->part_offset = STM32MP_NAND_TEEX_OFFSET;
part->bkp_offset = spi_nand_dev_spec.erase_size;
#endif
io_result = register_io_dev_stm32image(&stm32image_dev_con);
assert(io_result == 0);
io_result = io_dev_open(stm32image_dev_con,
(uintptr_t)&stm32image_dev_info_spec,
&image_dev_handle);
assert(io_result == 0);
}
#endif /* STM32MP_SPI_NAND */
void stm32mp_io_setup(void) void stm32mp_io_setup(void)
{ {
int io_result __unused; int io_result __unused;
...@@ -422,6 +492,12 @@ void stm32mp_io_setup(void) ...@@ -422,6 +492,12 @@ void stm32mp_io_setup(void)
boot_fmc2_nand(boot_context); boot_fmc2_nand(boot_context);
break; break;
#endif #endif
#if STM32MP_SPI_NAND
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
dmbsy();
boot_spi_nand(boot_context);
break;
#endif
default: default:
ERROR("Boot interface %d not supported\n", ERROR("Boot interface %d not supported\n",
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
/* Boot occurred on FMC */ /* Boot occurred on FMC */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U #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' * @brief Possible value of boot context field 'EmmcXferStatus'
*/ */
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
#define STM32MP1_BOOT_DEVICE_H #define STM32MP1_BOOT_DEVICE_H
#include <drivers/raw_nand.h> #include <drivers/raw_nand.h>
#include <drivers/spi_nand.h>
int plat_get_raw_nand_data(struct rawnand_device *device); 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 */ #endif /* STM32MP1_BOOT_DEVICE_H */
...@@ -28,17 +28,21 @@ $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) ...@@ -28,17 +28,21 @@ $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
STM32MP_EMMC ?= 0 STM32MP_EMMC ?= 0
STM32MP_SDMMC ?= 0 STM32MP_SDMMC ?= 0
STM32MP_RAW_NAND ?= 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") $(error "No boot device driver is enabled")
endif endif
$(eval $(call assert_boolean,STM32MP_EMMC)) $(eval $(call assert_boolean,STM32MP_EMMC))
$(eval $(call assert_boolean,STM32MP_SDMMC)) $(eval $(call assert_boolean,STM32MP_SDMMC))
$(eval $(call assert_boolean,STM32MP_RAW_NAND)) $(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_EMMC))
$(eval $(call add_define,STM32MP_SDMMC)) $(eval $(call add_define,STM32MP_SDMMC))
$(eval $(call add_define,STM32MP_RAW_NAND)) $(eval $(call add_define,STM32MP_RAW_NAND))
$(eval $(call add_define,STM32MP_SPI_NAND))
PLAT_INCLUDES := -Iplat/st/common/include/ PLAT_INCLUDES := -Iplat/st/common/include/
PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
...@@ -108,7 +112,16 @@ BL2_SOURCES += drivers/mtd/nand/raw_nand.c \ ...@@ -108,7 +112,16 @@ BL2_SOURCES += drivers/mtd/nand/raw_nand.c \
drivers/st/fmc/stm32_fmc2_nand.c drivers/st/fmc/stm32_fmc2_nand.c
endif 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 \ BL2_SOURCES += drivers/mtd/nand/core.c \
plat/st/stm32mp1/stm32mp1_boot_device.c plat/st/stm32mp1/stm32mp1_boot_device.c
endif endif
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#define SZ_512 0x200U #define SZ_512 0x200U
#if STM32MP_RAW_NAND #if STM32MP_RAW_NAND || STM32MP_SPI_NAND
static int get_data_from_otp(struct nand_device *nand_dev) static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
{ {
int result; int result;
uint32_t nand_param; uint32_t nand_param;
...@@ -81,28 +81,37 @@ static int get_data_from_otp(struct nand_device *nand_dev) ...@@ -81,28 +81,37 @@ static int get_data_from_otp(struct nand_device *nand_dev)
NAND_BLOCK_NB_UNIT * nand_dev->block_size; NAND_BLOCK_NB_UNIT * nand_dev->block_size;
ecc: ecc:
switch ((nand_param & NAND_ECC_BIT_NB_MASK) >> if (is_slc) {
NAND_ECC_BIT_NB_SHIFT) { switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
case NAND_ECC_BIT_NB_1_BITS: NAND_ECC_BIT_NB_SHIFT) {
nand_dev->ecc.max_bit_corr = 1U; case NAND_ECC_BIT_NB_1_BITS:
break; nand_dev->ecc.max_bit_corr = 1U;
break;
case NAND_ECC_BIT_NB_4_BITS:
nand_dev->ecc.max_bit_corr = 4U; case NAND_ECC_BIT_NB_4_BITS:
break; nand_dev->ecc.max_bit_corr = 4U;
break;
case NAND_ECC_BIT_NB_8_BITS:
nand_dev->ecc.max_bit_corr = 8U; case NAND_ECC_BIT_NB_8_BITS:
break; nand_dev->ecc.max_bit_corr = 8U;
break;
case NAND_ECC_ON_DIE:
nand_dev->ecc.mode = NAND_ECC_ONDIE; case NAND_ECC_ON_DIE:
break; nand_dev->ecc.mode = NAND_ECC_ONDIE;
break;
default:
if (nand_dev->ecc.max_bit_corr == 0U) { default:
ERROR("No valid eccbit number\n"); if (nand_dev->ecc.max_bit_corr == 0U) {
return -EINVAL; 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 @@ ecc: ...@@ -111,7 +120,7 @@ ecc:
return 0; return 0;
} }
#endif #endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */
#if STM32MP_RAW_NAND #if STM32MP_RAW_NAND
int plat_get_raw_nand_data(struct rawnand_device *device) int plat_get_raw_nand_data(struct rawnand_device *device)
...@@ -119,7 +128,24 @@ int plat_get_raw_nand_data(struct rawnand_device *device) ...@@ -119,7 +128,24 @@ int plat_get_raw_nand_data(struct rawnand_device *device)
device->nand_dev->ecc.mode = NAND_ECC_HW; device->nand_dev->ecc.mode = NAND_ECC_HW;
device->nand_dev->ecc.size = SZ_512; device->nand_dev->ecc.size = SZ_512;
return get_data_from_otp(device->nand_dev); 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, false);
} }
#endif #endif
...@@ -340,6 +340,9 @@ enum ddr_type { ...@@ -340,6 +340,9 @@ enum ddr_type {
#define NAND_ECC_BIT_NB_8_BITS U(3) #define NAND_ECC_BIT_NB_8_BITS U(3)
#define NAND_ECC_ON_DIE U(4) #define NAND_ECC_ON_DIE U(4)
/* NAND number of planes */
#define NAND_PLANE_BIT_NB_MASK BIT(14)
/******************************************************************************* /*******************************************************************************
* STM32MP1 TAMP * STM32MP1 TAMP
******************************************************************************/ ******************************************************************************/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment