Unverified Commit d87d524e authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #1466 from Yann-lms/stm32mp1

Add STMicroelectronics STM32MP1 platform support
parents e16d459d efb3728d
Showing with 2460 additions and 0 deletions
+2460 -0
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <boot_api.h>
#include <console.h>
#include <debug.h>
#include <delay_timer.h>
#include <desc_image_load.h>
#include <generic_delay_timer.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <stm32mp1_clk.h>
#include <stm32mp1_dt.h>
#include <stm32mp1_pmic.h>
#include <stm32mp1_private.h>
#include <stm32mp1_context.h>
#include <stm32mp1_pwr.h>
#include <stm32mp1_ram.h>
#include <stm32mp1_rcc.h>
#include <stm32mp1_reset.h>
#include <string.h>
#include <xlat_tables_v2.h>
void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
stm32mp1_save_boot_ctx_address(arg0);
}
void bl2_platform_setup(void)
{
int ret;
if (dt_check_pmic()) {
initialize_pmic();
}
ret = stm32mp1_ddr_probe();
if (ret < 0) {
ERROR("Invalid DDR init: error %d\n", ret);
panic();
}
INFO("BL2 runs SP_MIN setup\n");
}
void bl2_el3_plat_arch_setup(void)
{
int32_t result;
struct dt_node_info dt_dev_info;
const char *board_model;
boot_api_context_t *boot_context =
(boot_api_context_t *)stm32mp1_get_boot_ctx_address();
uint32_t clk_rate;
/*
* Disable the backup domain write protection.
* The protection is enable at each reset by hardware
* and must be disabled by software.
*/
mmio_setbits_32(PWR_BASE + PWR_CR1, PWR_CR1_DBP);
while ((mmio_read_32(PWR_BASE + PWR_CR1) & PWR_CR1_DBP) == 0U) {
;
}
/* Reset backup domain on cold boot cases */
if ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) {
mmio_setbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST);
while ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_VSWRST) ==
0U) {
;
}
mmio_clrbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST);
}
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
BL_CODE_END - BL_CODE_BASE,
MT_CODE | MT_SECURE);
/* Prevent corruption of preloaded BL32 */
mmap_add_region(BL32_BASE, BL32_BASE,
BL32_LIMIT - BL32_BASE,
MT_MEMORY | MT_RO | MT_SECURE);
/* Prevent corruption of preloaded Device Tree */
mmap_add_region(DTB_BASE, DTB_BASE,
DTB_LIMIT - DTB_BASE,
MT_MEMORY | MT_RO | MT_SECURE);
configure_mmu();
generic_delay_timer_init();
if (dt_open_and_check() < 0) {
panic();
}
if (stm32mp1_clk_probe() < 0) {
panic();
}
if (stm32mp1_clk_init() < 0) {
panic();
}
result = dt_get_stdout_uart_info(&dt_dev_info);
if ((result <= 0) ||
(dt_dev_info.status == 0U) ||
(dt_dev_info.clock < 0) ||
(dt_dev_info.reset < 0)) {
goto skip_console_init;
}
if (dt_set_stdout_pinctrl() != 0) {
goto skip_console_init;
}
if (stm32mp1_clk_enable((unsigned long)dt_dev_info.clock) != 0) {
goto skip_console_init;
}
stm32mp1_reset_assert((uint32_t)dt_dev_info.reset);
udelay(2);
stm32mp1_reset_deassert((uint32_t)dt_dev_info.reset);
mdelay(1);
clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_dev_info.clock);
if (console_init(dt_dev_info.base, clk_rate,
STM32MP1_UART_BAUDRATE) == 0) {
panic();
}
board_model = dt_get_board_model();
if (board_model != NULL) {
NOTICE("%s\n", board_model);
}
skip_console_init:
if (stm32_save_boot_interface(boot_context->boot_interface_selected,
boot_context->boot_interface_instance) !=
0) {
ERROR("Cannot save boot interface\n");
}
stm32mp1_arch_security_setup();
stm32mp1_io_setup();
}
/*
* Copyright (c) 2017, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __BOOT_API_H
#define __BOOT_API_H
#include <stdint.h>
/*
* Possible value of boot context field 'boot_interface_sel'
*/
/* Value of field 'boot_interface_sel' when no boot occurred */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_NO 0x0U
/* Boot occurred on SD */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD 0x1U
/* Boot occurred on EMMC */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U
/**
* @brief Possible value of boot context field 'EmmcXferStatus'
*/
/*
* Possible value of boot context field 'emmc_xfer_status'
*/
#define BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED 0x0U
#define BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED 0x1U
#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED 0x2U
#define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT 0x3U
/*
* Possible value of boot context field 'emmc_error_status'
*/
#define BOOT_API_CTX_EMMC_ERROR_STATUS_NONE 0x0U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT 0x1U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT 0x2U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL 0x3U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX 0x4U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND 0x5U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO 0x6U
#define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE 0x7U
/* Image Header related definitions */
/* Definition of header version */
#define BOOT_API_HEADER_VERSION 0x00010000U
/*
* Magic number used to detect header in memory
* Its value must be 'S' 'T' 'M' 0x32, i.e 0x324D5453 as field
* 'bootapi_image_header_t.magic'
* This identifies the start of a boot image.
*/
#define BOOT_API_IMAGE_HEADER_MAGIC_NB 0x324D5453U
/* Definitions related to Authentication used in image header structure */
#define BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES 64
#define BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES 64
#define BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES 32
/* Possible values of the field 'boot_api_image_header_t.ecc_algo_type' */
#define BOOT_API_ECDSA_ALGO_TYPE_P256NIST 1
#define BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256 2
/*
* Cores secure magic numbers
* Constant to be stored in bakcup register
* BOOT_API_MAGIC_NUMBER_TAMP_BCK_REG_IDX
*/
#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0U
#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1U
/*
* TAMP_BCK4R register index
* This register is used to write a Magic Number in order to restart
* Cortex A7 Core 1 and make it execute @ branch address from TAMP_BCK5R
*/
#define BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX 4U
/*
* TAMP_BCK5R register index
* This register is used to contain the branch address of
* Cortex A7 Core 1 when restarted by a TAMP_BCK4R magic number writing
*/
#define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX 5U
/*
* Possible value of boot context field 'hse_clock_value_in_hz'
*/
#define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED 0U
#define BOOT_API_CTX_HSE_CLOCK_VALUE_24_MHZ 24000000U
#define BOOT_API_CTX_HSE_CLOCK_VALUE_25_MHZ 25000000U
#define BOOT_API_CTX_HSE_CLOCK_VALUE_26_MHZ 26000000U
/*
* Possible value of boot context field 'boot_partition_used_toboot'
*/
#define BOOT_API_CTX_BOOT_PARTITION_UNDEFINED 0U
/* Used FSBL1 to boot */
#define BOOT_API_CTX_BOOT_PARTITION_FSBL1 1U
/* Used FSBL2 to boot */
#define BOOT_API_CTX_BOOT_PARTITION_FSBL2 2U
/* OTP_CFG0 */
#define BOOT_API_OTP_MODE_WORD_NB 0
/* Closed = OTP_CFG0[6] */
#define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6
/*
* Boot Context related definitions
*/
/*
* Boot core boot configuration structure
* Specifies all items of the cold boot configuration
* Memory and peripheral part.
*/
typedef struct {
/*
* Boot interface used to boot : take values from defines
* BOOT_API_CTX_BOOT_INTERFACE_SEL_XXX above
*/
uint16_t boot_interface_selected;
uint16_t boot_interface_instance;
uint32_t reserved1[13];
uint32_t otp_afmux_values[3];
uint32_t reserved[9];
/*
* Information specific to an SD boot
* Updated each time an SD boot is at least attempted,
* even if not successful
* Note : This is useful to understand why an SD boot failed
* in particular
*/
uint32_t sd_err_internal_timeout_cnt;
uint32_t sd_err_dcrc_fail_cnt;
uint32_t sd_err_dtimeout_cnt;
uint32_t sd_err_ctimeout_cnt;
uint32_t sd_err_ccrc_fail_cnt;
uint32_t sd_overall_retry_cnt;
/*
* Information specific to an eMMC boot
* Updated each time an eMMC boot is at least attempted,
* even if not successful
* Note : This is useful to understand why an eMMC boot failed
* in particular
*/
uint32_t emmc_xfer_status;
uint32_t emmc_error_status;
uint32_t emmc_nbbytes_rxcopied_tosysram_download_area;
uint32_t hse_clock_value_in_hz;
/*
* Boot partition :
* ie FSBL partition on which the boot was successful
*/
uint32_t boot_partition_used_toboot;
} __packed boot_api_context_t;
/*
* Image Header related definitions
*/
/*
* Structure used to define the common Header format used for FSBL, xloader,
* ... and in particular used by bootROM for FSBL header readout.
* FSBL header size is 256 Bytes = 0x100
*/
typedef struct {
/* BOOT_API_IMAGE_HEADER_MAGIC_NB */
uint32_t magic;
uint8_t image_signature[BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES];
/*
* Checksum of payload
* 32-bit sum all all payload bytes considered as 8 bit unigned numbers,
* discarding any overflow bits.
* Use to check UART/USB downloaded image integrity when signature
* is not used (i.e bit 0 : 'No_sig_check' = 1 in option flags)
*/
uint32_t payload_checksum;
/* Image header version : should have value BOOT_API_HEADER_VERSION */
uint32_t header_version;
/* Image length in bytes */
uint32_t image_length;
/*
* Image Entry point address : should be in the SYSRAM area
* and at least within the download area range
*/
uint32_t image_entry_point;
/* Reserved */
uint32_t reserved1;
/*
* Image load address : not used by bootROM but to be consistent
* with header format for other packages (xloader, ...)
*/
uint32_t load_address;
/* Reserved */
uint32_t reserved2;
/* Image version to be compared by bootROM with monotonic
* counter value in OTP_CFG4 prior executing the downloaded image
*/
uint32_t image_version;
/*
* Option flags:
* Bit 0 : No signature check request : 'No_sig_check'
* value 1 : for No signature check request
* value 0 : No request to bypass the signature check
* Note : No signature check is never allowed on a Secured chip
*/
uint32_t option_flags;
/*
* Type of ECC algorithm to use :
* value 1 : for P-256 NIST algorithm
* value 2 : for Brainpool 256 algorithm
* See definitions 'BOOT_API_ECDSA_ALGO_TYPE_XXX' above.
*/
uint32_t ecc_algo_type;
/*
* OEM ECC Public Key (aka Root pubk) provided in header on 512 bits.
* The SHA-256 hash of the OEM ECC pubk must match the one stored
* in OTP cells.
*/
uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES];
/* Pad up to 256 byte total size */
uint8_t pad[84];
} __packed boot_api_image_header_t;
#endif /* __BOOT_API_H */
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
#include <arch.h>
#include <common_def.h>
#include <gic_common.h>
#include <utils_def.h>
#include "../stm32mp1_def.h"
/*******************************************************************************
* Generic platform constants
******************************************************************************/
/* Size of cacheable stacks */
#if defined(IMAGE_BL32)
#define PLATFORM_STACK_SIZE 0x600
#else
#define PLATFORM_STACK_SIZE 0xC00
#endif
/* SSBL = second stage boot loader */
#define BL33_IMAGE_NAME "ssbl"
#define STM32MP1_PRIMARY_CPU U(0x0)
#define PLATFORM_CACHE_LINE_SIZE 64
#define PLATFORM_CLUSTER_COUNT ULL(1)
#define PLATFORM_CLUSTER0_CORE_COUNT U(2)
#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \
PLATFORM_CLUSTER0_CORE_COUNT)
#define PLATFORM_MAX_CPUS_PER_CLUSTER 2
#define MAX_IO_DEVICES 4
#define MAX_IO_HANDLES 4
/*******************************************************************************
* BL2 specific defines.
******************************************************************************/
/*
* Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
* size plus a little space for growth.
*/
#define BL2_BASE STM32MP1_BL2_BASE
#define BL2_LIMIT (STM32MP1_BL2_BASE + \
STM32MP1_BL2_SIZE)
/*******************************************************************************
* BL32 specific defines.
******************************************************************************/
#define BL32_BASE STM32MP1_BL32_BASE
#define BL32_LIMIT (STM32MP1_BL32_BASE + \
STM32MP1_BL32_SIZE)
/*******************************************************************************
* BL33 specific defines.
******************************************************************************/
#define BL33_BASE STM32MP1_BL33_BASE
/*
* Load address of BL33 for this platform port
*/
#define PLAT_STM32MP1_NS_IMAGE_OFFSET BL33_BASE
/*******************************************************************************
* DTB specific defines.
******************************************************************************/
#define DTB_BASE STM32MP1_DTB_BASE
#define DTB_LIMIT (STM32MP1_DTB_BASE + \
STM32MP1_DTB_SIZE)
/*******************************************************************************
* Platform specific page table and MMU setup constants
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
/*******************************************************************************
* Declarations and constants to access the mailboxes safely. Each mailbox is
* aligned on the biggest cache line size in the platform. This is known only
* to the platform as it might have a combination of integrated and external
* caches. Such alignment ensures that two maiboxes do not sit on the same cache
* line at any cache level. They could belong to different cpus/clusters &
* get written while being protected by different locks causing corruption of
* a valid mailbox address.
******************************************************************************/
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT)
/*
* Secure Interrupt: based on the standard ARM mapping
*/
#define ARM_IRQ_SEC_PHY_TIMER U(29)
#define ARM_IRQ_SEC_SGI_0 U(8)
#define ARM_IRQ_SEC_SGI_1 U(9)
#define ARM_IRQ_SEC_SGI_2 U(10)
#define ARM_IRQ_SEC_SGI_3 U(11)
#define ARM_IRQ_SEC_SGI_4 U(12)
#define ARM_IRQ_SEC_SGI_5 U(13)
#define ARM_IRQ_SEC_SGI_6 U(14)
#define ARM_IRQ_SEC_SGI_7 U(15)
#define STM32MP1_IRQ_TZC400 U(36)
#define STM32MP1_IRQ_TAMPSERRS U(229)
#define STM32MP1_IRQ_AXIERRIRQ U(244)
/*
* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
* terminology. On a GICv2 system or mode, the lists will be merged and treated
* as Group 0 interrupts.
*/
#define PLATFORM_G1S_PROPS(grp) \
INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(STM32MP1_IRQ_TAMPSERRS, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(STM32MP1_IRQ_TZC400, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE)
#define PLATFORM_G0_PROPS(grp) \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, \
GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE)
/*
* Power
*/
#define PLAT_MAX_PWR_LVL U(1)
/* Local power state for power domains in Run state. */
#define ARM_LOCAL_STATE_RUN U(0)
/* Local power state for retention. Valid only for CPU power domains */
#define ARM_LOCAL_STATE_RET U(1)
/* Local power state for power-down. Valid for CPU and cluster power domains */
#define ARM_LOCAL_STATE_OFF U(2)
/*
* This macro defines the deepest retention state possible.
* A higher state id will represent an invalid or a power down state.
*/
#define PLAT_MAX_RET_STATE ARM_LOCAL_STATE_RET
/*
* This macro defines the deepest power down states possible. Any state ID
* higher than this is invalid.
*/
#define PLAT_MAX_OFF_STATE ARM_LOCAL_STATE_OFF
/*******************************************************************************
* Size of the per-cpu data in bytes that should be reserved in the generic
* per-cpu data structure for the FVP port.
******************************************************************************/
#define PLAT_PCPU_DATA_SIZE 2
#endif /* PLATFORM_DEF_H */
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __STM32MP1_CONTEXT_H__
#define __STM32MP1_CONTEXT_H__
#include <stdint.h>
int stm32_save_boot_interface(uint32_t interface, uint32_t instance);
#endif /* __STM32MP1_CONTEXT_H__ */
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __STM32MP1_DT_H__
#define __STM32MP1_DT_H__
#include <stdbool.h>
struct dt_node_info {
uint32_t base;
int32_t clock;
int32_t reset;
bool status;
bool sec_status;
};
/*******************************************************************************
* Function and variable prototypes
******************************************************************************/
int dt_open_and_check(void);
int fdt_get_address(void **fdt_addr);
bool fdt_check_node(int node);
bool fdt_check_status(int node);
bool fdt_check_secure_status(int node);
uint32_t fdt_read_uint32_default(int node, const char *prop_name,
uint32_t dflt_value);
int fdt_read_uint32_array(int node, const char *prop_name,
uint32_t *array, uint32_t count);
int dt_set_pinctrl_config(int node);
int dt_set_stdout_pinctrl(void);
void dt_fill_device_info(struct dt_node_info *info, int node);
int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
int dt_get_stdout_uart_info(struct dt_node_info *info);
int dt_get_stdout_node_offset(void);
uint32_t dt_get_ddr_size(void);
const char *dt_get_board_model(void);
#endif /* __STM32MP1_DT_H__ */
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __STM32MP1_PRIVATE_H__
#define __STM32MP1_PRIVATE_H__
void stm32mp1_io_setup(void);
void configure_mmu(void);
void stm32mp1_arch_security_setup(void);
void stm32mp1_security_setup(void);
void stm32mp1_save_boot_ctx_address(uintptr_t address);
uintptr_t stm32mp1_get_boot_ctx_address(void);
void stm32mp1_gic_pcpu_init(void);
void stm32mp1_gic_init(void);
#endif /* __STM32MP1_PRIVATE_H__ */
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl_common.h>
#include <desc_image_load.h>
#include <platform.h>
#include <platform_def.h>
/*******************************************************************************
* Following descriptor provides BL image/ep information that gets used
* by BL2 to load the images and also subset of this information is
* passed to next BL image. The image loading sequence is managed by
* populating the images in required loading order. The image execution
* sequence is managed by populating the `next_handoff_image_id` with
* the next executable image id.
******************************************************************************/
static bl_mem_params_node_t bl2_mem_params_descs[] = {
/* Fill BL32 related information */
{
.image_id = BL32_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
SECURE | EXECUTABLE | EP_FIRST_EXE),
.ep_info.pc = BL32_BASE,
.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
SPSR_E_LITTLE,
DISABLE_ALL_EXCEPTIONS),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t,
IMAGE_ATTRIB_PLAT_SETUP),
.image_info.image_base = BL32_BASE,
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
.next_handoff_image_id = BL33_IMAGE_ID,
},
/* Fill BL33 related information */
{
.image_id = BL33_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_2, entry_point_info_t,
NON_SECURE | EXECUTABLE),
.ep_info.pc = PLAT_STM32MP1_NS_IMAGE_OFFSET,
.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
SPSR_E_LITTLE,
DISABLE_ALL_EXCEPTIONS),
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_2, image_info_t, 0),
.image_info.image_base = PLAT_STM32MP1_NS_IMAGE_OFFSET,
.image_info.image_max_size = STM32MP1_DDR_MAX_SIZE -
(PLAT_STM32MP1_NS_IMAGE_OFFSET - STM32MP1_DDR_BASE),
.next_handoff_image_id = INVALID_IMAGE_ID,
}
};
REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <desc_image_load.h>
/*******************************************************************************
* This function flushes the data structures so that they are visible
* in memory for the next BL image.
******************************************************************************/
void plat_flush_next_bl_params(void)
{
flush_bl_params_desc();
}
/*******************************************************************************
* This function returns the list of loadable images.
******************************************************************************/
bl_load_info_t *plat_get_bl_image_load_info(void)
{
return get_bl_load_info_from_mem_params_desc();
}
/*******************************************************************************
* This function returns the list of executable images.
******************************************************************************/
bl_params_t *plat_get_next_bl_params(void)
{
return get_next_bl_params_from_mem_params_desc();
}
#
# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
ARM_CORTEX_A7 := yes
ARM_WITH_NEON := yes
LOAD_IMAGE_V2 := 1
BL2_AT_EL3 := 1
ENABLE_PLAT_COMPAT := 0
USE_COHERENT_MEM := 0
STM32_TF_VERSION ?= 0
# Not needed for Cortex-A7
WORKAROUND_CVE_2017_5715:= 0
PLAT_INCLUDES := -Iplat/st/stm32mp1/include/
PLAT_INCLUDES += -Iinclude/common/tbbr
PLAT_INCLUDES += -Iinclude/drivers/st
# Device tree
STM32_DTB_FILE_NAME ?= stm32mp157c-ev1.dtb
FDT_SOURCES := $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32_DTB_FILE_NAME)))
DTC_FLAGS += -Wno-unit_address_vs_reg
include lib/libfdt/libfdt.mk
PLAT_BL_COMMON_SOURCES := plat/st/stm32mp1/stm32mp1_common.c
PLAT_BL_COMMON_SOURCES += drivers/console/aarch32/console.S \
drivers/st/uart/aarch32/stm32_console.S
ifneq (${ENABLE_STACK_PROTECTOR},0)
PLAT_BL_COMMON_SOURCES += plat/st/stm32mp1/stm32mp1_stack_protector.c
endif
include lib/xlat_tables_v2/xlat_tables.mk
PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
PLAT_BL_COMMON_SOURCES += lib/cpus/aarch32/cortex_a7.S
PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \
drivers/arm/tzc/tzc400.c \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
drivers/st/clk/stm32mp1_clk.c \
drivers/st/clk/stm32mp1_clkfunc.c \
drivers/st/ddr/stm32mp1_ddr_helpers.c \
drivers/st/gpio/stm32_gpio.c \
drivers/st/pmic/stm32_i2c.c \
drivers/st/pmic/stm32mp1_pmic.c \
drivers/st/pmic/stpmu1.c \
drivers/st/reset/stm32mp1_reset.c \
plat/st/stm32mp1/stm32mp1_context.c \
plat/st/stm32mp1/stm32mp1_dt.c \
plat/st/stm32mp1/stm32mp1_helper.S \
plat/st/stm32mp1/stm32mp1_security.c
BL2_SOURCES += drivers/io/io_dummy.c \
drivers/io/io_storage.c \
plat/st/stm32mp1/bl2_io_storage.c \
plat/st/stm32mp1/bl2_plat_setup.c
BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \
drivers/st/ddr/stm32mp1_ram.c
BL2_SOURCES += common/desc_image_load.c \
plat/st/stm32mp1/plat_bl2_mem_params_desc.c \
plat/st/stm32mp1/plat_image_load.c
# For memory footprint optimization, build with thumb and interwork support
ASFLAGS += -mthumb -mthumb-interwork
TF_CFLAGS += -mthumb -mthumb-interwork
# Macros and rules to build TF binary
STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed
STM32_DT_BASENAME := $(STM32_DTB_FILE_NAME:.dtb=)
STM32_TF_STM32 := ${BUILD_PLAT}/tf-a-${STM32_DT_BASENAME}.stm32
STM32_TF_BINARY := $(STM32_TF_STM32:.stm32=.bin)
STM32_TF_MAPFILE := $(STM32_TF_STM32:.stm32=.map)
STM32_TF_LINKERFILE := $(STM32_TF_STM32:.stm32=.ld)
STM32_TF_ELF := $(STM32_TF_STM32:.stm32=.elf)
STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${STM32_DTB_FILE_NAME}
STM32_TF_OBJS := ${BUILD_PLAT}/stm32mp1.o
# Variables for use with stm32image
STM32IMAGEPATH ?= tools/stm32image
STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT}
.PHONY: ${STM32_TF_STM32}
.SUFFIXES:
all: check_dtc_version ${STM32_TF_STM32} stm32image
ifeq ($(AARCH32_SP),sp_min)
# BL32 is built only if using SP_MIN
BL32_DEP := bl32
BL32_PATH := -DBL32_BIN_PATH=\"${BUILD_PLAT}/bl32.bin\"
endif
distclean realclean clean: clean_stm32image
stm32image:
${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH}
clean_stm32image:
${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean
check_dtc_version:
$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}'))
$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g")))
@if [ ${DTC_VERSION} -lt 10404 ]; then \
echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \
false; \
fi
${STM32_TF_OBJS}: plat/st/stm32mp1/stm32mp1.S bl2 ${BL32_DEP} ${STM32_TF_DTBFILE}
@echo " AS $<"
${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \
${BL32_PATH} \
-DBL2_BIN_PATH=\"${BUILD_PLAT}/bl2.bin\" \
-DDTB_BIN_PATH=\"${STM32_TF_DTBFILE}\" \
-c plat/st/stm32mp1/stm32mp1.S -o $@
${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S
@echo " LDS $<"
${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} -P -E $< -o $@
${STM32_TF_ELF}: ${STM32_TF_OBJS} ${STM32_TF_LINKERFILE}
@echo " LDS $<"
${Q}${LD} -o $@ ${STM32_TF_ELF_LDFLAGS} -Map=${STM32_TF_MAPFILE} --script ${STM32_TF_LINKERFILE} ${STM32_TF_OBJS}
${STM32_TF_BINARY}: ${STM32_TF_ELF}
${Q}${OC} -O binary ${STM32_TF_ELF} $@
@echo
@echo "Built $@ successfully"
@echo
${STM32_TF_STM32}: stm32image ${STM32_TF_BINARY}
@echo
@echo "Generated $@"
$(eval LOADADDR = $(shell cat ${STM32_TF_MAPFILE} | grep RAM | awk '{print $$2}'))
$(eval ENTRY = $(shell cat ${STM32_TF_MAPFILE} | grep "__BL2_IMAGE_START" | awk '{print $$1}'))
${STM32IMAGE} -s ${STM32_TF_BINARY} -d $@ -l $(LOADADDR) -e ${ENTRY} -v ${STM32_TF_VERSION}
@echo
#
# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
SP_MIN_WITH_SECURE_FIQ := 1
BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \
plat/st/stm32mp1/sp_min/sp_min_setup.c \
plat/st/stm32mp1/stm32mp1_pm.c \
plat/st/stm32mp1/stm32mp1_topology.c
# Generic GIC v2
BL32_SOURCES += drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_helpers.c \
drivers/arm/gic/v2/gicv2_main.c \
plat/common/plat_gicv2.c \
plat/st/stm32mp1/stm32mp1_gic.c
# Generic PSCI
BL32_SOURCES += plat/common/plat_psci_common.c
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <arm_gic.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <context.h>
#include <context_mgmt.h>
#include <debug.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <generic_delay_timer.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <platform_sp_min.h>
#include <stm32mp1_clk.h>
#include <stm32mp1_dt.h>
#include <stm32mp1_private.h>
#include <string.h>
#include <tzc400.h>
#include <xlat_tables_v2.h>
/******************************************************************************
* Placeholder variables for copying the arguments that have been passed to
* BL32 from BL2.
******************************************************************************/
static entry_point_info_t bl33_image_ep_info;
/*******************************************************************************
* Interrupt handler for FIQ (secure IRQ)
******************************************************************************/
void sp_min_plat_fiq_handler(uint32_t id)
{
switch (id) {
case STM32MP1_IRQ_TZC400:
ERROR("STM32MP1_IRQ_TZC400 generated\n");
panic();
break;
case STM32MP1_IRQ_AXIERRIRQ:
ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n");
panic();
break;
default:
ERROR("SECURE IT handler not define for it : %i", id);
break;
}
}
/*******************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image for
* the security state specified. BL33 corresponds to the non-secure image type
* while BL32 corresponds to the secure image type. A NULL pointer is returned
* if the image does not exist.
******************************************************************************/
entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
{
entry_point_info_t *next_image_info;
next_image_info = &bl33_image_ep_info;
if (next_image_info->pc == 0U) {
return NULL;
}
return next_image_info;
}
/*******************************************************************************
* Perform any BL32 specific platform actions.
******************************************************************************/
void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
struct dt_node_info dt_dev_info;
int result;
bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
/* Imprecise aborts can be masked in NonSecure */
write_scr(read_scr() | SCR_AW_BIT);
assert(params_from_bl2 != NULL);
assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
assert(params_from_bl2->h.version >= VERSION_2);
bl_params_node_t *bl_params = params_from_bl2->head;
/*
* Copy BL33 entry point information.
* They are stored in Secure RAM, in BL2's address space.
*/
while (bl_params != NULL) {
if (bl_params->image_id == BL33_IMAGE_ID) {
bl33_image_ep_info = *bl_params->ep_info;
break;
}
bl_params = bl_params->next_params_info;
}
if (dt_open_and_check() < 0) {
panic();
}
if (stm32mp1_clk_probe() < 0) {
panic();
}
result = dt_get_stdout_uart_info(&dt_dev_info);
if ((result > 0) && dt_dev_info.status) {
if (console_init(dt_dev_info.base, 0, STM32MP1_UART_BAUDRATE)
== 0) {
panic();
}
}
}
/*******************************************************************************
* Initialize the MMU, security and the GIC.
******************************************************************************/
void sp_min_platform_setup(void)
{
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
BL_CODE_END - BL_CODE_BASE,
MT_CODE | MT_SECURE);
configure_mmu();
/* Initialize tzc400 after DDR initialization */
stm32mp1_security_setup();
generic_delay_timer_init();
stm32mp1_gic_init();
}
void sp_min_plat_arch_setup(void)
{
}
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifdef BL32_BIN_PATH
.section .bl32_image
.incbin BL32_BIN_PATH
#endif
.section .bl2_image
.incbin BL2_BIN_PATH
.section .dtb_image
.incbin DTB_BIN_PATH
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __STM32MP1_LD_S__
#define __STM32MP1_LD_S__
#include <platform_def.h>
#include <xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(__BL2_IMAGE_START__)
MEMORY {
HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000
RAM (rwx) : ORIGIN = STM32MP1_BINARY_BASE, LENGTH = STM32MP1_BINARY_SIZE
}
SECTIONS
{
/*
* TF mapping must conform to ROM code specification.
*/
.header : {
__HEADER_START__ = .;
KEEP(*(.header))
. = ALIGN(4);
__HEADER_END__ = .;
} >HEADER
. = STM32MP1_BINARY_BASE;
.data . : {
. = ALIGN(PAGE_SIZE);
__DATA_START__ = .;
*(.data*)
/*
* dtb.
* The strongest and only alignment contraint is MMU 4K page.
* Indeed as images below will be removed, 4K pages will be re-used.
*/
. = ( STM32MP1_DTB_BASE - STM32MP1_BINARY_BASE );
__DTB_IMAGE_START__ = .;
*(.dtb_image*)
__DTB_IMAGE_END__ = .;
/*
* bl2.
* The strongest and only alignment contraint is MMU 4K page.
* Indeed as images below will be removed, 4K pages will be re-used.
*/
. = ( STM32MP1_BL2_BASE - STM32MP1_BINARY_BASE );
__BL2_IMAGE_START__ = .;
*(.bl2_image*)
__BL2_IMAGE_END__ = .;
/*
* bl32 will be settled by bl2.
* The strongest and only alignment constraint is 8 words to simplify
* memraise8 assembly code.
*/
. = ( STM32MP1_BL32_BASE - STM32MP1_BINARY_BASE );
__BL32_IMAGE_START__ = .;
*(.bl32_image*)
__BL32_IMAGE_END__ = .;
__DATA_END__ = .;
} >RAM
__TF_END__ = .;
}
#endif /*__STM32MP1_LD_S__*/
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <debug.h>
#include <gicv2.h>
#include <mmio.h>
#include <platform_def.h>
#include <platform.h>
#include <stm32mp1_private.h>
#include <xlat_tables_v2.h>
#define MAP_SRAM MAP_REGION_FLAT(STM32MP1_SRAM_BASE, \
STM32MP1_SRAM_SIZE, \
MT_MEMORY | \
MT_RW | \
MT_SECURE | \
MT_EXECUTE_NEVER)
#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \
STM32MP1_DEVICE1_SIZE, \
MT_DEVICE | \
MT_RW | \
MT_SECURE | \
MT_EXECUTE_NEVER)
#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \
STM32MP1_DEVICE2_SIZE, \
MT_DEVICE | \
MT_RW | \
MT_SECURE | \
MT_EXECUTE_NEVER)
#define MAP_DDR MAP_REGION_FLAT(STM32MP1_DDR_BASE, \
STM32MP1_DDR_MAX_SIZE, \
MT_MEMORY | \
MT_RW | \
MT_SECURE | \
MT_EXECUTE_NEVER)
#define MAP_DDR_NS MAP_REGION_FLAT(STM32MP1_DDR_BASE, \
STM32MP1_DDR_MAX_SIZE, \
MT_MEMORY | \
MT_RW | \
MT_NS | \
MT_EXECUTE_NEVER)
#if defined(IMAGE_BL2)
static const mmap_region_t stm32mp1_mmap[] = {
MAP_SRAM,
MAP_DEVICE1,
MAP_DEVICE2,
MAP_DDR,
{0}
};
#endif
#if defined(IMAGE_BL32)
static const mmap_region_t stm32mp1_mmap[] = {
MAP_SRAM,
MAP_DEVICE1,
MAP_DEVICE2,
MAP_DDR_NS,
{0}
};
#endif
void configure_mmu(void)
{
mmap_add(stm32mp1_mmap);
init_xlat_tables();
enable_mmu_secure(0);
}
uintptr_t plat_get_ns_image_entrypoint(void)
{
return BL33_BASE;
}
unsigned int plat_get_syscnt_freq2(void)
{
return read_cntfrq_el0();
}
/* Functions to save and get boot context address given by ROM code */
static uintptr_t boot_ctx_address;
void stm32mp1_save_boot_ctx_address(uintptr_t address)
{
boot_ctx_address = address;
}
uintptr_t stm32mp1_get_boot_ctx_address(void)
{
return boot_ctx_address;
}
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <errno.h>
#include <mmio.h>
#include <platform_def.h>
#include <stm32mp1_clk.h>
#include <stm32mp1_context.h>
#define TAMP_BOOT_ITF_BACKUP_REG_ID U(20)
#define TAMP_BOOT_ITF_MASK U(0x0000FF00)
#define TAMP_BOOT_ITF_SHIFT 8
int stm32_save_boot_interface(uint32_t interface, uint32_t instance)
{
uint32_t tamp_clk_off = 0;
uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID);
if (!stm32mp1_clk_is_enabled(RTCAPB)) {
tamp_clk_off = 1;
if (stm32mp1_clk_enable(RTCAPB) != 0) {
return -EINVAL;
}
}
mmio_clrsetbits_32(bkpr_itf_idx,
TAMP_BOOT_ITF_MASK,
((interface << 4) | (instance & 0xFU)) <<
TAMP_BOOT_ITF_SHIFT);
if (tamp_clk_off != 0U) {
if (stm32mp1_clk_disable(RTCAPB) != 0) {
return -EINVAL;
}
}
return 0;
}
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef STM32MP1_DEF_H
#define STM32MP1_DEF_H
#include <tbbr_img_def.h>
#include <utils_def.h>
#include <xlat_tables_defs.h>
/*******************************************************************************
* STM32MP1 memory map related constants
******************************************************************************/
#define STM32MP1_SRAM_BASE U(0x2FFC0000)
#define STM32MP1_SRAM_SIZE U(0x00040000)
/* DDR configuration */
#define STM32MP1_DDR_BASE U(0xC0000000)
#define STM32MP1_DDR_SIZE_DFLT U(0x20000000) /* 512 MB */
#define STM32MP1_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */
#define STM32MP1_DDR_SPEED_DFLT 528
/* DDR power initializations */
#ifndef __ASSEMBLY__
enum ddr_type {
STM32MP_DDR3,
STM32MP_LPDDR2,
};
#endif
/* Section used inside TF binaries */
#define STM32MP1_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */
/* 256 Octets reserved for header */
#define STM32MP1_HEADER_SIZE U(0x00000100)
#define STM32MP1_BINARY_BASE (STM32MP1_SRAM_BASE + \
STM32MP1_PARAM_LOAD_SIZE + \
STM32MP1_HEADER_SIZE)
#define STM32MP1_BINARY_SIZE (STM32MP1_SRAM_SIZE - \
(STM32MP1_PARAM_LOAD_SIZE + \
STM32MP1_HEADER_SIZE))
#if STACK_PROTECTOR_ENABLED
#define STM32MP1_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */
#else
#define STM32MP1_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */
#endif
#define STM32MP1_BL32_BASE (STM32MP1_SRAM_BASE + \
STM32MP1_SRAM_SIZE - \
STM32MP1_BL32_SIZE)
#if STACK_PROTECTOR_ENABLED
#define STM32MP1_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */
#else
#define STM32MP1_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */
#endif
#define STM32MP1_BL2_BASE (STM32MP1_BL32_BASE - \
STM32MP1_BL2_SIZE)
/* BL2 and BL32/sp_min require 5 tables */
#define MAX_XLAT_TABLES 5
/*
* MAX_MMAP_REGIONS is usually:
* BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
*/
#if defined(IMAGE_BL2)
#define MAX_MMAP_REGIONS 11
#endif
#if defined(IMAGE_BL32)
#define MAX_MMAP_REGIONS 6
#endif
/* DTB initialization value */
#define STM32MP1_DTB_SIZE U(0x00004000) /* 16Ko for DTB */
#define STM32MP1_DTB_BASE (STM32MP1_BL2_BASE - \
STM32MP1_DTB_SIZE)
#define STM32MP1_BL33_BASE (STM32MP1_DDR_BASE + U(0x100000))
/*******************************************************************************
* STM32MP1 device/io map related constants (used for MMU)
******************************************************************************/
#define STM32MP1_DEVICE1_BASE U(0x40000000)
#define STM32MP1_DEVICE1_SIZE U(0x40000000)
#define STM32MP1_DEVICE2_BASE U(0x80000000)
#define STM32MP1_DEVICE2_SIZE U(0x40000000)
/*******************************************************************************
* STM32MP1 RCC
******************************************************************************/
#define RCC_BASE U(0x50000000)
/*******************************************************************************
* STM32MP1 PWR
******************************************************************************/
#define PWR_BASE U(0x50001000)
/*******************************************************************************
* STM32MP1 UART
******************************************************************************/
#define USART1_BASE U(0x5C000000)
#define USART2_BASE U(0x4000E000)
#define USART3_BASE U(0x4000F000)
#define UART4_BASE U(0x40010000)
#define UART5_BASE U(0x40011000)
#define USART6_BASE U(0x44003000)
#define UART7_BASE U(0x40018000)
#define UART8_BASE U(0x40019000)
#define STM32MP1_DEBUG_USART_BASE UART4_BASE
#define STM32MP1_UART_BAUDRATE 115200
/*******************************************************************************
* STM32MP1 GIC-400
******************************************************************************/
#define STM32MP1_GICD_BASE U(0xA0021000)
#define STM32MP1_GICC_BASE U(0xA0022000)
#define STM32MP1_GICH_BASE U(0xA0024000)
#define STM32MP1_GICV_BASE U(0xA0026000)
/*******************************************************************************
* STM32MP1 TZC (TZ400)
******************************************************************************/
#define STM32MP1_TZC_BASE U(0x5C006000)
#define STM32MP1_TZC_A7_ID U(0)
#define STM32MP1_TZC_LCD_ID U(3)
#define STM32MP1_TZC_GPU_ID U(4)
#define STM32MP1_TZC_MDMA_ID U(5)
#define STM32MP1_TZC_DMA_ID U(6)
#define STM32MP1_TZC_USB_HOST_ID U(7)
#define STM32MP1_TZC_USB_OTG_ID U(8)
#define STM32MP1_TZC_SDMMC_ID U(9)
#define STM32MP1_TZC_ETH_ID U(10)
#define STM32MP1_TZC_DAP_ID U(15)
#define STM32MP1_MEMORY_NS 0
#define STM32MP1_MEMORY_SECURE 1
#define STM32MP1_FILTER_BIT_ALL 3
/*******************************************************************************
* STM32MP1 SDMMC
******************************************************************************/
#define STM32MP1_SDMMC1_BASE U(0x58005000)
#define STM32MP1_SDMMC2_BASE U(0x58007000)
#define STM32MP1_SDMMC3_BASE U(0x48004000)
#define STM32MP1_SD_INIT_FREQ 400000 /*400 KHz*/
#define STM32MP1_SD_NORMAL_SPEED_MAX_FREQ 25000000 /*25 MHz*/
#define STM32MP1_SD_HIGH_SPEED_MAX_FREQ 50000000 /*50 MHz*/
#define STM32MP1_EMMC_INIT_FREQ STM32MP1_SD_INIT_FREQ
#define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ 26000000 /*26 MHz*/
#define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ 52000000 /*52 MHz*/
/*******************************************************************************
* STM32MP1 TAMP
******************************************************************************/
#define TAMP_BASE U(0x5C00A000)
#define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100))
#if !(defined(__LINKER__) || defined(__ASSEMBLY__))
static inline uint32_t tamp_bkpr(uint32_t idx)
{
return TAMP_BKP_REGISTER_BASE + (idx << 2);
}
#endif
/*******************************************************************************
* STM32MP1 DDRCTRL
******************************************************************************/
#define DDRCTRL_BASE U(0x5A003000)
/*******************************************************************************
* STM32MP1 DDRPHYC
******************************************************************************/
#define DDRPHYC_BASE U(0x5A004000)
/*******************************************************************************
* STM32MP1 I2C4
******************************************************************************/
#define I2C4_BASE U(0x5C002000)
#endif /* STM32MP1_DEF_H */
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <debug.h>
#include <libfdt.h>
#include <platform_def.h>
#include <stm32_gpio.h>
#include <stm32mp1_clk.h>
#include <stm32mp1_clkfunc.h>
#include <stm32mp1_ddr.h>
#include <stm32mp1_dt.h>
#include <stm32mp1_ram.h>
#define DT_GPIO_BANK_SHIFT 12
#define DT_GPIO_BANK_MASK 0x1F000U
#define DT_GPIO_PIN_SHIFT 8
#define DT_GPIO_PIN_MASK 0xF00U
#define DT_GPIO_MODE_MASK 0xFFU
static int fdt_checked;
static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE;
/*******************************************************************************
* This function gets the pin settings from DT information.
* When analyze and parsing is done, set the GPIO registers.
* Return 0 on success, else return a negative FDT_ERR_xxx error code.
******************************************************************************/
static int dt_set_gpio_config(int node)
{
const fdt32_t *cuint, *slewrate;
int len, pinctrl_node, pinctrl_subnode;
uint32_t i;
uint32_t speed = GPIO_SPEED_LOW;
uint32_t pull = GPIO_NO_PULL;
cuint = fdt_getprop(fdt, node, "pinmux", &len);
if (cuint == NULL) {
return -FDT_ERR_NOTFOUND;
}
pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
if (pinctrl_node < 0) {
return -FDT_ERR_NOTFOUND;
}
slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
if (slewrate != NULL) {
speed = fdt32_to_cpu(*slewrate);
}
if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
pull = GPIO_PULL_UP;
} else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
pull = GPIO_PULL_DOWN;
} else {
VERBOSE("No bias configured in node %d\n", node);
}
for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
uint32_t pincfg;
uint32_t bank;
uint32_t pin;
uint32_t mode;
uint32_t alternate = GPIO_ALTERNATE_0;
pincfg = fdt32_to_cpu(*cuint);
cuint++;
bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
mode = pincfg & DT_GPIO_MODE_MASK;
switch (mode) {
case 0:
mode = GPIO_MODE_INPUT;
break;
case 1 ... 16:
alternate = mode - 1U;
mode = GPIO_MODE_ALTERNATE;
break;
case 17:
mode = GPIO_MODE_ANALOG;
break;
default:
mode = GPIO_MODE_OUTPUT;
break;
}
if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
mode |= GPIO_OPEN_DRAIN;
}
fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
uint32_t bank_offset;
const fdt32_t *cuint2;
if (fdt_getprop(fdt, pinctrl_subnode,
"gpio-controller", NULL) == NULL) {
continue;
}
cuint2 = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
if (cuint2 == NULL) {
continue;
}
if (bank == GPIO_BANK_Z) {
bank_offset = 0;
} else {
bank_offset = bank * STM32_GPIO_BANK_OFFSET;
}
if (fdt32_to_cpu(*cuint2) == bank_offset) {
int clk_id = fdt_get_clock_id(pinctrl_subnode);
if (clk_id < 0) {
return -FDT_ERR_NOTFOUND;
}
if (stm32mp1_clk_enable((unsigned long)clk_id) <
0) {
return -FDT_ERR_BADVALUE;
}
break;
}
}
set_gpio(bank, pin, mode, speed, pull, alternate);
}
return 0;
}
/*******************************************************************************
* This function checks device tree file with its header.
* Returns 0 if success, and a negative value else.
******************************************************************************/
int dt_open_and_check(void)
{
int ret = fdt_check_header(fdt);
if (ret == 0) {
fdt_checked = 1;
}
return ret;
}
/*******************************************************************************
* This function gets the address of the DT.
* If DT is OK, fdt_addr is filled with DT address.
* Returns 1 if success, 0 otherwise.
******************************************************************************/
int fdt_get_address(void **fdt_addr)
{
if (fdt_checked == 1) {
*fdt_addr = fdt;
}
return fdt_checked;
}
/*******************************************************************************
* This function check the presence of a node (generic use of fdt library).
* Returns true if present, false else.
******************************************************************************/
bool fdt_check_node(int node)
{
int len;
const char *cchar;
cchar = fdt_get_name(fdt, node, &len);
return (cchar != NULL) && (len >= 0);
}
/*******************************************************************************
* This function check the status of a node (generic use of fdt library).
* Returns true if "okay" or missing, false else.
******************************************************************************/
bool fdt_check_status(int node)
{
int len;
const char *cchar;
cchar = fdt_getprop(fdt, node, "status", &len);
if (cchar == NULL) {
return true;
}
return strncmp(cchar, "okay", (size_t)len) == 0;
}
/*******************************************************************************
* This function check the secure-status of a node (generic use of fdt library).
* Returns true if "okay" or missing, false else.
******************************************************************************/
bool fdt_check_secure_status(int node)
{
int len;
const char *cchar;
cchar = fdt_getprop(fdt, node, "secure-status", &len);
if (cchar == NULL) {
return true;
}
return strncmp(cchar, "okay", (size_t)len) == 0;
}
/*******************************************************************************
* This function reads a value of a node property (generic use of fdt
* library).
* Returns value if success, and a default value if property not found.
* Default value is passed as parameter.
******************************************************************************/
uint32_t fdt_read_uint32_default(int node, const char *prop_name,
uint32_t dflt_value)
{
const fdt32_t *cuint;
int lenp;
cuint = fdt_getprop(fdt, node, prop_name, &lenp);
if (cuint == NULL) {
return dflt_value;
}
return fdt32_to_cpu(*cuint);
}
/*******************************************************************************
* This function reads a series of parameters in a node property
* (generic use of fdt library).
* It reads the values inside the device tree, from property name and node.
* The number of parameters is also indicated as entry parameter.
* Returns 0 if success, and a negative value else.
* If success, values are stored at the third parameter address.
******************************************************************************/
int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
uint32_t count)
{
const fdt32_t *cuint;
int len;
uint32_t i;
cuint = fdt_getprop(fdt, node, prop_name, &len);
if (cuint == NULL) {
return -FDT_ERR_NOTFOUND;
}
if ((uint32_t)len != (count * sizeof(uint32_t))) {
return -FDT_ERR_BADLAYOUT;
}
for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
*array = fdt32_to_cpu(*cuint);
array++;
cuint++;
}
return 0;
}
/*******************************************************************************
* This function gets the pin settings from DT information.
* When analyze and parsing is done, set the GPIO registers.
* Returns 0 if success, and a negative value else.
******************************************************************************/
int dt_set_pinctrl_config(int node)
{
const fdt32_t *cuint;
int lenp = 0;
uint32_t i;
if (!fdt_check_status(node)) {
return -FDT_ERR_NOTFOUND;
}
cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
if (cuint == NULL) {
return -FDT_ERR_NOTFOUND;
}
for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
int phandle_node, phandle_subnode;
phandle_node =
fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
if (phandle_node < 0) {
return -FDT_ERR_NOTFOUND;
}
fdt_for_each_subnode(phandle_subnode, fdt, phandle_node) {
int ret = dt_set_gpio_config(phandle_subnode);
if (ret < 0) {
return ret;
}
}
cuint++;
}
return 0;
}
/*******************************************************************************
* This function gets the stdout pin configuration information from the DT.
* And then calls the sub-function to treat it and set GPIO registers.
* Returns 0 if success, and a negative value else.
******************************************************************************/
int dt_set_stdout_pinctrl(void)
{
int node;
node = dt_get_stdout_node_offset();
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
return dt_set_pinctrl_config(node);
}
/*******************************************************************************
* This function fills the generic information from a given node.
******************************************************************************/
void dt_fill_device_info(struct dt_node_info *info, int node)
{
const fdt32_t *cuint;
cuint = fdt_getprop(fdt, node, "reg", NULL);
if (cuint != NULL) {
info->base = fdt32_to_cpu(*cuint);
} else {
info->base = 0;
}
cuint = fdt_getprop(fdt, node, "clocks", NULL);
if (cuint != NULL) {
cuint++;
info->clock = (int)fdt32_to_cpu(*cuint);
} else {
info->clock = -1;
}
cuint = fdt_getprop(fdt, node, "resets", NULL);
if (cuint != NULL) {
cuint++;
info->reset = (int)fdt32_to_cpu(*cuint);
} else {
info->reset = -1;
}
info->status = fdt_check_status(node);
info->sec_status = fdt_check_secure_status(node);
}
/*******************************************************************************
* This function retrieve the generic information from DT.
* Returns node if success, and a negative value else.
******************************************************************************/
int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
{
int node;
node = fdt_node_offset_by_compatible(fdt, offset, compat);
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
dt_fill_device_info(info, node);
return node;
}
/*******************************************************************************
* This function gets the UART instance info of stdout from the DT.
* Returns node if success, and a negative value else.
******************************************************************************/
int dt_get_stdout_uart_info(struct dt_node_info *info)
{
int node;
node = dt_get_stdout_node_offset();
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
dt_fill_device_info(info, node);
return node;
}
/*******************************************************************************
* This function gets the stdout path node.
* It reads the value indicated inside the device tree.
* Returns node if success, and a negative value else.
******************************************************************************/
int dt_get_stdout_node_offset(void)
{
int node;
const char *cchar;
node = fdt_path_offset(fdt, "/chosen");
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
if (cchar == NULL) {
return -FDT_ERR_NOTFOUND;
}
node = -FDT_ERR_NOTFOUND;
if (strchr(cchar, (int)':') != NULL) {
const char *name;
char *str = (char *)cchar;
int len = 0;
while (strncmp(":", str, 1)) {
len++;
str++;
}
name = fdt_get_alias_namelen(fdt, cchar, len);
if (name != NULL) {
node = fdt_path_offset(fdt, name);
}
} else {
node = fdt_path_offset(fdt, cchar);
}
return node;
}
/*******************************************************************************
* This function gets DDR size information from the DT.
* Returns value in bytes if success, and STM32MP1_DDR_SIZE_DFLT else.
******************************************************************************/
uint32_t dt_get_ddr_size(void)
{
int node;
node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
if (node < 0) {
INFO("%s: Cannot read DDR node in DT\n", __func__);
return STM32MP1_DDR_SIZE_DFLT;
}
return fdt_read_uint32_default(node, "st,mem-size",
STM32MP1_DDR_SIZE_DFLT);
}
/*******************************************************************************
* This function retrieves board model from DT
* Returns string taken from model node, NULL otherwise
******************************************************************************/
const char *dt_get_board_model(void)
{
int node = fdt_path_offset(fdt, "/");
if (node < 0) {
return NULL;
}
return (const char *)fdt_getprop(fdt, node, "model", NULL);
}
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl_common.h>
#include <gicv2.h>
#include <platform.h>
#include <platform_def.h>
#include <utils.h>
#include <stm32mp1_private.h>
/******************************************************************************
* On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
* interrupts.
*****************************************************************************/
static const interrupt_prop_t stm32mp1_interrupt_props[] = {
PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
};
static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
static const gicv2_driver_data_t platform_gic_data = {
.gicd_base = STM32MP1_GICD_BASE,
.gicc_base = STM32MP1_GICC_BASE,
.interrupt_props = stm32mp1_interrupt_props,
.interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props),
.target_masks = target_mask_array,
.target_masks_num = ARRAY_SIZE(target_mask_array),
};
void stm32mp1_gic_init(void)
{
gicv2_driver_init(&platform_gic_data);
gicv2_distif_init();
stm32mp1_gic_pcpu_init();
}
void stm32mp1_gic_pcpu_init(void)
{
gicv2_pcpu_distif_init();
gicv2_set_pe_target_mask(plat_my_core_pos());
gicv2_cpuif_enable();
}
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl_common.h>
#include <platform_def.h>
#include <stm32_gpio.h>
#include <stm32mp1_rcc.h>
#define GPIO_BANK_G_ADDRESS 0x50008000
#define GPIO_TX_PORT 11
#define GPIO_TX_SHIFT (GPIO_TX_PORT << 1)
#define GPIO_TX_ALT_SHIFT ((GPIO_TX_PORT - GPIO_ALT_LOWER_LIMIT) << 2)
#define STM32MP1_HSI_CLK 64000000
.globl platform_mem_init
.globl plat_report_exception
.globl plat_get_my_entrypoint
.globl plat_secondary_cold_boot_setup
.globl plat_reset_handler
.globl plat_is_my_cpu_primary
.globl plat_my_core_pos
.globl plat_crash_console_init
.globl plat_crash_console_flush
.globl plat_crash_console_putc
.globl plat_panic_handler
func platform_mem_init
/* Nothing to do, don't need to init SYSRAM */
bx lr
endfunc platform_mem_init
func plat_report_exception
bx lr
endfunc plat_report_exception
func plat_reset_handler
bx lr
endfunc plat_reset_handler
/* ------------------------------------------------------------------
* unsigned long plat_get_my_entrypoint (void);
*
* Main job of this routine is to distinguish between a cold and warm
* boot.
*
* Currently supports only cold boot
* ------------------------------------------------------------------
*/
func plat_get_my_entrypoint
mov r0, #0
bx lr
endfunc plat_get_my_entrypoint
/* ---------------------------------------------
* void plat_secondary_cold_boot_setup (void);
*
* Cold-booting secondary CPUs is not supported.
* ---------------------------------------------
*/
func plat_secondary_cold_boot_setup
b .
endfunc plat_secondary_cold_boot_setup
/* -----------------------------------------------------
* unsigned int plat_is_my_cpu_primary (void);
*
* Find out whether the current cpu is the primary cpu.
* -----------------------------------------------------
*/
func plat_is_my_cpu_primary
ldcopr r0, MPIDR
ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
and r0, r1
cmp r0, #STM32MP1_PRIMARY_CPU
moveq r0, #1
movne r0, #0
bx lr
endfunc plat_is_my_cpu_primary
/* -------------------------------------------
* int plat_stm32mp1_get_core_pos(int mpidr);
*
* Return CorePos = (ClusterId * 4) + CoreId
* -------------------------------------------
*/
func plat_stm32mp1_get_core_pos
and r1, r0, #MPIDR_CPU_MASK
and r0, r0, #MPIDR_CLUSTER_MASK
add r0, r1, r0, LSR #6
bx lr
endfunc plat_stm32mp1_get_core_pos
/* ------------------------------------
* unsigned int plat_my_core_pos(void)
* ------------------------------------
*/
func plat_my_core_pos
ldcopr r0, MPIDR
b plat_stm32mp1_get_core_pos
endfunc plat_my_core_pos
/* ---------------------------------------------
* int plat_crash_console_init(void)
*
* Initialize the crash console without a C Runtime stack.
* ---------------------------------------------
*/
func plat_crash_console_init
/* Enable GPIOs for UART4 TX */
ldr r1, =(RCC_BASE + RCC_MP_AHB4ENSETR)
ldr r2, [r1]
/* Configure GPIO G11 */
orr r2, r2, #RCC_MP_AHB4ENSETR_GPIOGEN
str r2, [r1]
ldr r1, =GPIO_BANK_G_ADDRESS
/* Set GPIO mode alternate */
ldr r2, [r1, #GPIO_MODE_OFFSET]
bic r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT)
orr r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT)
str r2, [r1, #GPIO_MODE_OFFSET]
/* Set GPIO speed low */
ldr r2, [r1, #GPIO_SPEED_OFFSET]
bic r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT)
str r2, [r1, #GPIO_SPEED_OFFSET]
/* Set no-pull */
ldr r2, [r1, #GPIO_PUPD_OFFSET]
bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT)
str r2, [r1, #GPIO_PUPD_OFFSET]
/* Set alternate AF6 */
ldr r2, [r1, #GPIO_AFRH_OFFSET]
bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT)
orr r2, r2, #(GPIO_ALTERNATE_6 << GPIO_TX_ALT_SHIFT)
str r2, [r1, #GPIO_AFRH_OFFSET]
/* Enable UART clock, with HSI source */
ldr r1, =(RCC_BASE + RCC_UART24CKSELR)
mov r2, #RCC_UART24CKSELR_HSI
str r2, [r1]
ldr r1, =(RCC_BASE + RCC_MP_APB1ENSETR)
ldr r2, [r1]
orr r2, r2, #RCC_MP_APB1ENSETR_UART4EN
str r2, [r1]
ldr r0, =STM32MP1_DEBUG_USART_BASE
ldr r1, =STM32MP1_HSI_CLK
ldr r2, =STM32MP1_UART_BAUDRATE
b console_core_init
endfunc plat_crash_console_init
/* ---------------------------------------------
* int plat_crash_console_flush(void)
*
* Flush the crash console without a C Runtime stack.
* ---------------------------------------------
*/
func plat_crash_console_flush
ldr r1, =STM32MP1_DEBUG_USART_BASE
b console_core_flush
endfunc plat_crash_console_flush
/* ---------------------------------------------
* int plat_crash_console_putc(int c)
*
* Print a character on the crash console without a C Runtime stack.
* Clobber list : r1 - r3
*
* In case of bootloading through uart, we keep console crash as this.
* Characters could be sent to the programmer, but will be ignored.
* No specific code in that case.
* ---------------------------------------------
*/
func plat_crash_console_putc
ldr r1, =STM32MP1_DEBUG_USART_BASE
b console_core_putc
endfunc plat_crash_console_putc
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <boot_api.h>
#include <debug.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <errno.h>
#include <gic_common.h>
#include <gicv2.h>
#include <mmio.h>
#include <platform_def.h>
#include <platform.h>
#include <psci.h>
#include <stm32mp1_clk.h>
#include <stm32mp1_private.h>
#include <stm32mp1_rcc.h>
static uint32_t stm32_sec_entrypoint;
static uint32_t cntfrq_core0;
#define SEND_SECURE_IT_TO_CORE_1 0x20000U
/*******************************************************************************
* STM32MP1 handler called when a CPU is about to enter standby.
* call by core 1 to enter in wfi
******************************************************************************/
static void stm32_cpu_standby(plat_local_state_t cpu_state)
{
uint32_t interrupt = GIC_SPURIOUS_INTERRUPT;
assert(cpu_state == ARM_LOCAL_STATE_RET);
/*
* Enter standby state
* dsb is good practice before using wfi to enter low power states
*/
dsb();
while (interrupt == GIC_SPURIOUS_INTERRUPT) {
wfi();
/* Acknoledge IT */
interrupt = gicv2_acknowledge_interrupt();
/* If Interrupt == 1022 it will be acknowledged by non secure */
if ((interrupt != PENDING_G1_INTID) &&
(interrupt != GIC_SPURIOUS_INTERRUPT)) {
gicv2_end_of_interrupt(interrupt);
}
}
}
/*******************************************************************************
* STM32MP1 handler called when a power domain is about to be turned on. The
* mpidr determines the CPU to be turned on.
* call by core 0 to activate core 1
******************************************************************************/
static int stm32_pwr_domain_on(u_register_t mpidr)
{
unsigned long current_cpu_mpidr = read_mpidr_el1();
uint32_t tamp_clk_off = 0;
uint32_t bkpr_core1_addr =
tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
uint32_t bkpr_core1_magic =
tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
if (mpidr == current_cpu_mpidr) {
return PSCI_E_INVALID_PARAMS;
}
if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) ||
(stm32_sec_entrypoint > (STM32MP1_SRAM_BASE +
(STM32MP1_SRAM_SIZE - 1)))) {
return PSCI_E_INVALID_ADDRESS;
}
if (!stm32mp1_clk_is_enabled(RTCAPB)) {
tamp_clk_off = 1;
if (stm32mp1_clk_enable(RTCAPB) != 0) {
panic();
}
}
cntfrq_core0 = read_cntfrq_el0();
/* Write entrypoint in backup RAM register */
mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint);
/* Write magic number in backup register */
mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER);
if (tamp_clk_off != 0U) {
if (stm32mp1_clk_disable(RTCAPB) != 0) {
panic();
}
}
/* Generate an IT to core 1 */
mmio_write_32(STM32MP1_GICD_BASE + GICD_SGIR,
SEND_SECURE_IT_TO_CORE_1 | ARM_IRQ_SEC_SGI_0);
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* STM32MP1 handler called when a power domain is about to be turned off. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
static void stm32_pwr_domain_off(const psci_power_state_t *target_state)
{
/* Nothing to do */
}
/*******************************************************************************
* STM32MP1 handler called when a power domain is about to be suspended. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state)
{
/* Nothing to do, power domain is not disabled */
}
/*******************************************************************************
* STM32MP1 handler called when a power domain has just been powered on after
* being turned off earlier. The target_state encodes the low power state that
* each level has woken up from.
* call by core 1 just after wake up
******************************************************************************/
static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
stm32mp1_gic_pcpu_init();
write_cntfrq_el0(cntfrq_core0);
}
/*******************************************************************************
* STM32MP1 handler called when a power domain has just been powered on after
* having been suspended earlier. The target_state encodes the low power state
* that each level has woken up from.
******************************************************************************/
static void stm32_pwr_domain_suspend_finish(const psci_power_state_t
*target_state)
{
/* Nothing to do, power domain is not disabled */
}
static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t
*target_state)
{
ERROR("stm32mpu1 Power Down WFI: operation not handled.\n");
panic();
}
static void __dead2 stm32_system_off(void)
{
ERROR("stm32mpu1 System Off: operation not handled.\n");
panic();
}
static void __dead2 stm32_system_reset(void)
{
mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST);
/* Loop in case system reset is not immediately caught */
for ( ; ; ) {
;
}
}
static int stm32_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pstate = psci_get_pstate_type(power_state);
if (pstate != 0) {
return PSCI_E_INVALID_PARAMS;
}
if (psci_get_pstate_pwrlvl(power_state)) {
return PSCI_E_INVALID_PARAMS;
}
if (psci_get_pstate_id(power_state)) {
return PSCI_E_INVALID_PARAMS;
}
req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET;
req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN;
return PSCI_E_SUCCESS;
}
static int stm32_validate_ns_entrypoint(uintptr_t entrypoint)
{
/* The non-secure entry point must be in DDR */
if (entrypoint < STM32MP1_DDR_BASE) {
return PSCI_E_INVALID_ADDRESS;
}
return PSCI_E_SUCCESS;
}
static int stm32_node_hw_state(u_register_t target_cpu,
unsigned int power_level)
{
/*
* The format of 'power_level' is implementation-defined, but 0 must
* mean a CPU. Only allow level 0.
*/
if (power_level != MPIDR_AFFLVL0) {
return PSCI_E_INVALID_PARAMS;
}
/*
* From psci view the CPU 0 is always ON,
* CPU 1 can be SUSPEND or RUNNING.
* Therefore do not manage POWER OFF state and always return HW_ON.
*/
return (int)HW_ON;
}
/*******************************************************************************
* Export the platform handlers. The ARM Standard platform layer will take care
* of registering the handlers with PSCI.
******************************************************************************/
static const plat_psci_ops_t stm32_psci_ops = {
.cpu_standby = stm32_cpu_standby,
.pwr_domain_on = stm32_pwr_domain_on,
.pwr_domain_off = stm32_pwr_domain_off,
.pwr_domain_suspend = stm32_pwr_domain_suspend,
.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
.system_off = stm32_system_off,
.system_reset = stm32_system_reset,
.validate_power_state = stm32_validate_power_state,
.validate_ns_entrypoint = stm32_validate_ns_entrypoint,
.get_node_hw_state = stm32_node_hw_state
};
/*******************************************************************************
* Export the platform specific power ops.
******************************************************************************/
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
stm32_sec_entrypoint = sec_entrypoint;
*psci_ops = &stm32_psci_ops;
return 0;
}
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