From 12e21dfde236407b8253fcde6937f11ca44cb8b0 Mon Sep 17 00:00:00 2001 From: Lionel Debieve Date: Mon, 4 Nov 2019 12:28:15 +0100 Subject: [PATCH] stm32mp1: Add support for raw NAND boot device STM32MP1 platform is able to boot from raw NAND devices. These modifications add this support using the new raw NAND framework. Change-Id: I9e9c2b03930f98a5ac23f2b6b41945bef43e5043 Signed-off-by: Lionel Debieve --- plat/st/common/bl2_io_storage.c | 76 +++++++++++ plat/st/stm32mp1/include/boot_api.h | 3 + plat/st/stm32mp1/include/platform_def.h | 1 + .../stm32mp1/include/stm32mp1_boot_device.h | 14 ++ plat/st/stm32mp1/platform.mk | 17 ++- plat/st/stm32mp1/stm32mp1_boot_device.c | 125 ++++++++++++++++++ plat/st/stm32mp1/stm32mp1_def.h | 59 ++++++++- 7 files changed, 290 insertions(+), 5 deletions(-) create mode 100644 plat/st/stm32mp1/include/stm32mp1_boot_device.h create mode 100644 plat/st/stm32mp1/stm32mp1_boot_device.c diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c index d7f53ceec..e2629fa5d 100644 --- a/plat/st/common/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -14,11 +14,14 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include @@ -56,6 +59,17 @@ static const io_block_dev_spec_t mmc_block_dev_spec = { static const io_dev_connector_t *mmc_dev_con; #endif /* STM32MP_SDMMC || STM32MP_EMMC */ +#if STM32MP_RAW_NAND +static io_mtd_dev_spec_t nand_dev_spec = { + .ops = { + .init = nand_raw_init, + .read = nand_read, + }, +}; + +static const io_dev_connector_t *nand_dev_con; +#endif + #ifdef AARCH32_SP_OPTEE static const struct stm32image_part_info optee_header_partition_spec = { .name = OPTEE_HEADER_IMAGE_NAME, @@ -209,6 +223,9 @@ static void print_boot_device(boot_api_context_t *boot_context) case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: INFO("Using EMMC\n"); break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + INFO("Using FMC NAND\n"); + break; default: ERROR("Boot interface not found\n"); panic(); @@ -312,6 +329,59 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type, } #endif /* STM32MP_SDMMC || STM32MP_EMMC */ +#if STM32MP_RAW_NAND +static void boot_fmc2_nand(boot_api_context_t *boot_context) +{ + int io_result __unused; + uint8_t idx; + struct stm32image_part_info *part; + + io_result = stm32_fmc2_init(); + assert(io_result == 0); + + /* Register the IO device on this platform */ + io_result = register_io_dev_mtd(&nand_dev_con); + assert(io_result == 0); + + /* Open connections to device */ + io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec, + &storage_dev_handle); + assert(io_result == 0); + + stm32image_dev_info_spec.device_size = 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 = 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 = 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 = 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 = 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_RAW_NAND */ + void stm32mp_io_setup(void) { int io_result __unused; @@ -346,6 +416,12 @@ void stm32mp_io_setup(void) boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance); break; #endif +#if STM32MP_RAW_NAND + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: + dmbsy(); + boot_fmc2_nand(boot_context); + break; +#endif default: ERROR("Boot interface %d not supported\n", diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h index c80aef6dd..ba5d22fa2 100644 --- a/plat/st/stm32mp1/include/boot_api.h +++ b/plat/st/stm32mp1/include/boot_api.h @@ -33,6 +33,9 @@ /* Boot occurred on EMMC */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U +/* Boot occurred on FMC */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U + /** * @brief Possible value of boot context field 'EmmcXferStatus' */ diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h index 263e6d6e1..450a9d404 100644 --- a/plat/st/stm32mp1/include/platform_def.h +++ b/plat/st/stm32mp1/include/platform_def.h @@ -51,6 +51,7 @@ #define MAX_IO_DEVICES U(4) #define MAX_IO_HANDLES U(4) #define MAX_IO_BLOCK_DEVICES U(1) +#define MAX_IO_MTD_DEVICES U(1) /******************************************************************************* * BL2 specific defines. diff --git a/plat/st/stm32mp1/include/stm32mp1_boot_device.h b/plat/st/stm32mp1/include/stm32mp1_boot_device.h new file mode 100644 index 000000000..ae6b02beb --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_boot_device.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_BOOT_DEVICE_H +#define STM32MP1_BOOT_DEVICE_H + +#include + +int plat_get_raw_nand_data(struct rawnand_device *device); + +#endif /* STM32MP1_BOOT_DEVICE_H */ diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index a14a9abbb..71b39168d 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -27,15 +27,18 @@ $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) # Boot devices STM32MP_EMMC ?= 0 STM32MP_SDMMC ?= 0 +STM32MP_RAW_NAND ?= 0 -ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),) +ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_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 add_define,STM32MP_EMMC)) $(eval $(call add_define,STM32MP_SDMMC)) +$(eval $(call add_define,STM32MP_RAW_NAND)) PLAT_INCLUDES := -Iplat/st/common/include/ PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ @@ -83,6 +86,7 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \ BL2_SOURCES += drivers/io/io_block.c \ drivers/io/io_dummy.c \ + drivers/io/io_mtd.c \ drivers/io/io_storage.c \ drivers/st/crypto/stm32_hash.c \ drivers/st/io/io_stm32image.c \ @@ -98,6 +102,17 @@ BL2_SOURCES += drivers/mmc/mmc.c \ drivers/st/mmc/stm32_sdmmc2.c endif +ifeq (${STM32MP_RAW_NAND},1) +$(eval $(call add_define_val,NAND_ONFI_DETECT,1)) +BL2_SOURCES += drivers/mtd/nand/raw_nand.c \ + drivers/st/fmc/stm32_fmc2_nand.c +endif + +ifneq ($(filter 1,${STM32MP_RAW_NAND}),) +BL2_SOURCES += drivers/mtd/nand/core.c \ + plat/st/stm32mp1/stm32mp1_boot_device.c +endif + BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \ drivers/st/ddr/stm32mp1_ram.c diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c new file mode 100644 index 000000000..8b1f07f6d --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_boot_device.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +#define SZ_512 0x200U + +#if STM32MP_RAW_NAND +static int get_data_from_otp(struct nand_device *nand_dev) +{ + int result; + uint32_t nand_param; + + /* Check if NAND parameters are stored in OTP */ + result = bsec_shadow_read_otp(&nand_param, NAND_OTP); + if (result != BSEC_OK) { + ERROR("BSEC: NAND_OTP Error %i\n", result); + return -EACCES; + } + + if (nand_param == 0U) { + return 0; + } + + if ((nand_param & NAND_PARAM_STORED_IN_OTP) == 0U) { + goto ecc; + } + + /* NAND parameter shall be read from OTP */ + if ((nand_param & NAND_WIDTH_MASK) != 0U) { + nand_dev->buswidth = NAND_BUS_WIDTH_16; + } else { + nand_dev->buswidth = NAND_BUS_WIDTH_8; + } + + switch ((nand_param & NAND_PAGE_SIZE_MASK) >> NAND_PAGE_SIZE_SHIFT) { + case NAND_PAGE_SIZE_2K: + nand_dev->page_size = 0x800U; + break; + + case NAND_PAGE_SIZE_4K: + nand_dev->page_size = 0x1000U; + break; + + case NAND_PAGE_SIZE_8K: + nand_dev->page_size = 0x2000U; + break; + + default: + ERROR("Cannot read NAND page size\n"); + return -EINVAL; + } + + switch ((nand_param & NAND_BLOCK_SIZE_MASK) >> NAND_BLOCK_SIZE_SHIFT) { + case NAND_BLOCK_SIZE_64_PAGES: + nand_dev->block_size = 64U * nand_dev->page_size; + break; + + case NAND_BLOCK_SIZE_128_PAGES: + nand_dev->block_size = 128U * nand_dev->page_size; + break; + + case NAND_BLOCK_SIZE_256_PAGES: + nand_dev->block_size = 256U * nand_dev->page_size; + break; + + default: + ERROR("Cannot read NAND block size\n"); + return -EINVAL; + } + + nand_dev->size = ((nand_param & NAND_BLOCK_NB_MASK) >> + NAND_BLOCK_NB_SHIFT) * + 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; + + 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_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; + } + } + + VERBOSE("OTP: Block %i Page %i Size %lli\n", nand_dev->block_size, + nand_dev->page_size, nand_dev->size); + + return 0; +} +#endif + +#if STM32MP_RAW_NAND +int plat_get_raw_nand_data(struct rawnand_device *device) +{ + device->nand_dev->ecc.mode = NAND_ECC_HW; + device->nand_dev->ecc.size = SZ_512; + + return get_data_from_otp(device->nand_dev); +} +#endif + diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index 5ec730f4b..7ac9b5fe4 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #endif @@ -107,15 +108,15 @@ enum ddr_type { #ifdef AARCH32_SP_OPTEE #if STACK_PROTECTOR_ENABLED -#define STM32MP_BL2_SIZE U(0x00019000) /* 100 KB for BL2 */ +#define STM32MP_BL2_SIZE U(0x0001A000) /* 100 KB for BL2 */ #else -#define STM32MP_BL2_SIZE U(0x00017000) /* 92 KB for BL2 */ +#define STM32MP_BL2_SIZE U(0x00018000) /* 92 KB for BL2 */ #endif #else #if STACK_PROTECTOR_ENABLED -#define STM32MP_BL2_SIZE U(0x00018000) /* 96 KB for BL2 */ +#define STM32MP_BL2_SIZE U(0x00019000) /* 96 KB for BL2 */ #else -#define STM32MP_BL2_SIZE U(0x00016000) /* 88 KB for BL2 */ +#define STM32MP_BL2_SIZE U(0x00017000) /* 88 KB for BL2 */ #endif #endif @@ -144,6 +145,19 @@ enum ddr_type { #define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000)) +/* Define maximum page size for NAND devices */ +#define PLATFORM_MTD_MAX_PAGE_SIZE U(0x1000) + +/******************************************************************************* + * STM32MP1 RAW partition offset for MTD devices + ******************************************************************************/ +#define STM32MP_NAND_BL33_OFFSET U(0x00200000) +#ifdef AARCH32_SP_OPTEE +#define STM32MP_NAND_TEEH_OFFSET U(0x00600000) +#define STM32MP_NAND_TEED_OFFSET U(0x00680000) +#define STM32MP_NAND_TEEX_OFFSET U(0x00700000) +#endif + /******************************************************************************* * STM32MP1 device/io map related constants (used for MMU) ******************************************************************************/ @@ -266,6 +280,7 @@ enum ddr_type { /* OTP offsets */ #define DATA0_OTP U(0) #define PART_NUMBER_OTP U(1) +#define NAND_OTP U(9) #define PACKAGE_OTP U(16) #define HW2_OTP U(18) @@ -289,6 +304,42 @@ enum ddr_type { /* HW2 OTP */ #define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13) +/* NAND OTP */ +/* NAND parameter storage flag */ +#define NAND_PARAM_STORED_IN_OTP BIT(31) + +/* NAND page size in bytes */ +#define NAND_PAGE_SIZE_MASK GENMASK_32(30, 29) +#define NAND_PAGE_SIZE_SHIFT 29 +#define NAND_PAGE_SIZE_2K U(0) +#define NAND_PAGE_SIZE_4K U(1) +#define NAND_PAGE_SIZE_8K U(2) + +/* NAND block size in pages */ +#define NAND_BLOCK_SIZE_MASK GENMASK_32(28, 27) +#define NAND_BLOCK_SIZE_SHIFT 27 +#define NAND_BLOCK_SIZE_64_PAGES U(0) +#define NAND_BLOCK_SIZE_128_PAGES U(1) +#define NAND_BLOCK_SIZE_256_PAGES U(2) + +/* NAND number of block (in unit of 256 blocs) */ +#define NAND_BLOCK_NB_MASK GENMASK_32(26, 19) +#define NAND_BLOCK_NB_SHIFT 19 +#define NAND_BLOCK_NB_UNIT U(256) + +/* NAND bus width in bits */ +#define NAND_WIDTH_MASK BIT(18) +#define NAND_WIDTH_SHIFT 18 + +/* NAND number of ECC bits per 512 bytes */ +#define NAND_ECC_BIT_NB_MASK GENMASK_32(17, 15) +#define NAND_ECC_BIT_NB_SHIFT 15 +#define NAND_ECC_BIT_NB_UNSET U(0) +#define NAND_ECC_BIT_NB_1_BITS U(1) +#define NAND_ECC_BIT_NB_4_BITS U(2) +#define NAND_ECC_BIT_NB_8_BITS U(3) +#define NAND_ECC_ON_DIE U(4) + /******************************************************************************* * STM32MP1 TAMP ******************************************************************************/