Commit 0289ab9e authored by Soby Mathew's avatar Soby Mathew Committed by TrustedFirmware Code Review
Browse files

Merge changes from topic "yg/stm32mp1_wdg_updates" into integration

* changes:
  mmc: stm32_sdmmc2: correctly manage block size
  mmc: stm32_sdmmc2: manage max-frequency property from DT
  stm32mp1: move check_header() to common code
  stm32mp1: keep console during runtime
  stm32mp1: sp_min: initialize MMU and cache earlier
  stm32mp1: add support for LpDDR3
  stm32mp1: use a common function to check spinlock is available
  clk: stm32mp: enable RTCAPB clock for dual-core chips
  stm32mp1: check if the SoC is single core
  stm32mp1: print information about board
  stm32mp1: print information about SoC
  stm32mp1: add watchdog support
parents 5dbdf8e4 d9d803e0
......@@ -32,20 +32,14 @@ static uintptr_t bsec_base;
static void bsec_lock(void)
{
const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
/* Lock is currently required only when MMU and cache are enabled */
if ((read_sctlr() & mask) == mask) {
if (stm32mp_lock_available()) {
spin_lock(&bsec_spinlock);
}
}
static void bsec_unlock(void)
{
const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
/* Unlock is required only when MMU and cache are enabled */
if ((read_sctlr() & mask) == mask) {
if (stm32mp_lock_available()) {
spin_unlock(&bsec_spinlock);
}
}
......
......@@ -541,29 +541,19 @@ static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
return &stm32mp1_clk_pll[idx];
}
static int stm32mp1_lock_available(void)
{
/* The spinlocks are used only when MMU is enabled */
return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT);
}
static void stm32mp1_clk_lock(struct spinlock *lock)
{
if (stm32mp1_lock_available() == 0U) {
return;
if (stm32mp_lock_available()) {
/* Assume interrupts are masked */
spin_lock(lock);
}
/* Assume interrupts are masked */
spin_lock(lock);
}
static void stm32mp1_clk_unlock(struct spinlock *lock)
{
if (stm32mp1_lock_available() == 0U) {
return;
if (stm32mp_lock_available()) {
spin_unlock(lock);
}
spin_unlock(lock);
}
bool stm32mp1_rcc_is_secure(void)
......@@ -1912,9 +1902,18 @@ static void stm32mp1_osc_init(void)
}
}
static void sync_earlyboot_clocks_state(void)
{
if (!stm32mp_is_single_core()) {
stm32mp1_clk_enable_secure(RTCAPB);
}
}
int stm32mp1_clk_probe(void)
{
stm32mp1_osc_init();
sync_earlyboot_clocks_state();
return 0;
}
......@@ -717,6 +717,8 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
ret = board_ddr_power_init(STM32MP_DDR3);
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
ret = board_ddr_power_init(STM32MP_LPDDR2);
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) != 0U) {
ret = board_ddr_power_init(STM32MP_LPDDR3);
} else {
ERROR("DDR type not supported\n");
}
......
......@@ -242,40 +242,6 @@ static int stm32image_partition_size(io_entity_t *entity, size_t *length)
return 0;
}
static int check_header(boot_api_image_header_t *header, uintptr_t buffer)
{
uint32_t i;
uint32_t img_checksum = 0;
/*
* Check header/payload validity:
* - Header magic
* - Header version
* - Payload checksum
*/
if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
ERROR("Header magic\n");
return -EINVAL;
}
if (header->header_version != BOOT_API_HEADER_VERSION) {
ERROR("Header version\n");
return -EINVAL;
}
for (i = 0; i < header->image_length; i++) {
img_checksum += *(uint8_t *)(buffer + i);
}
if (header->payload_checksum != img_checksum) {
ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
header->payload_checksum);
return -EINVAL;
}
return 0;
}
/* Read data from a partition */
static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
......@@ -368,7 +334,7 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
continue;
}
result = check_header(header, buffer);
result = stm32mp_check_header(header, buffer);
if (result != 0) {
ERROR("Header check failed\n");
*length_read = 0;
......
/*
* Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <libfdt.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32_iwdg.h>
#include <drivers/st/stm32mp_clkfunc.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
/* IWDG registers offsets */
#define IWDG_KR_OFFSET 0x00U
/* Registers values */
#define IWDG_KR_RELOAD_KEY 0xAAAA
struct stm32_iwdg_instance {
uintptr_t base;
unsigned long clock;
uint8_t flags;
int num_irq;
};
static struct stm32_iwdg_instance stm32_iwdg[IWDG_MAX_INSTANCE];
static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset)
{
int node;
node = dt_get_node(info, offset, DT_IWDG_COMPAT);
if (node < 0) {
if (offset == -1) {
VERBOSE("%s: No IDWG found\n", __func__);
}
return -FDT_ERR_NOTFOUND;
}
return node;
}
void stm32_iwdg_refresh(void)
{
uint8_t i;
for (i = 0U; i < IWDG_MAX_INSTANCE; i++) {
struct stm32_iwdg_instance *iwdg = &stm32_iwdg[i];
/* 0x00000000 is not a valid address for IWDG peripherals */
if (iwdg->base != 0U) {
stm32mp_clk_enable(iwdg->clock);
mmio_write_32(iwdg->base + IWDG_KR_OFFSET,
IWDG_KR_RELOAD_KEY);
stm32mp_clk_disable(iwdg->clock);
}
}
}
int stm32_iwdg_init(void)
{
int node = -1;
struct dt_node_info dt_info;
void *fdt;
uint32_t __unused count = 0;
if (fdt_get_address(&fdt) == 0) {
panic();
}
for (node = stm32_iwdg_get_dt_node(&dt_info, node);
node != -FDT_ERR_NOTFOUND;
node = stm32_iwdg_get_dt_node(&dt_info, node)) {
struct stm32_iwdg_instance *iwdg;
uint32_t hw_init;
uint32_t idx;
count++;
idx = stm32_iwdg_get_instance(dt_info.base);
iwdg = &stm32_iwdg[idx];
iwdg->base = dt_info.base;
iwdg->clock = (unsigned long)dt_info.clock;
/* DT can specify low power cases */
if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) ==
NULL) {
iwdg->flags |= IWDG_DISABLE_ON_STOP;
}
if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) ==
NULL) {
iwdg->flags |= IWDG_DISABLE_ON_STANDBY;
}
/* Explicit list of supported bit flags */
hw_init = stm32_iwdg_get_otp_config(idx);
if ((hw_init & IWDG_HW_ENABLED) != 0) {
if (dt_info.status == DT_DISABLED) {
ERROR("OTP enabled but iwdg%u DT-disabled\n",
idx + 1U);
panic();
}
iwdg->flags |= IWDG_HW_ENABLED;
}
if (dt_info.status == DT_DISABLED) {
zeromem((void *)iwdg,
sizeof(struct stm32_iwdg_instance));
continue;
}
if ((hw_init & IWDG_DISABLE_ON_STOP) != 0) {
iwdg->flags |= IWDG_DISABLE_ON_STOP;
}
if ((hw_init & IWDG_DISABLE_ON_STANDBY) != 0) {
iwdg->flags |= IWDG_DISABLE_ON_STANDBY;
}
VERBOSE("IWDG%u found, %ssecure\n", idx + 1U,
((dt_info.status & DT_NON_SECURE) != 0) ?
"non-" : "");
#if defined(IMAGE_BL2)
if (stm32_iwdg_shadow_update(idx, iwdg->flags) != BSEC_OK) {
return -1;
}
#endif
}
VERBOSE("%u IWDG instance%s found\n", count, (count > 1U) ? "s" : "");
return 0;
}
......@@ -71,20 +71,14 @@
#define SDMMC_DCTRLR_DTEN BIT(0)
#define SDMMC_DCTRLR_DTDIR BIT(1)
#define SDMMC_DCTRLR_DTMODE GENMASK(3, 2)
#define SDMMC_DCTRLR_DBLOCKSIZE_0 BIT(4)
#define SDMMC_DCTRLR_DBLOCKSIZE_1 BIT(5)
#define SDMMC_DCTRLR_DBLOCKSIZE_3 BIT(7)
#define SDMMC_DCTRLR_DBLOCKSIZE GENMASK(7, 4)
#define SDMMC_DCTRLR_DBLOCKSIZE_SHIFT 4
#define SDMMC_DCTRLR_FIFORST BIT(13)
#define SDMMC_DCTRLR_CLEAR_MASK (SDMMC_DCTRLR_DTEN | \
SDMMC_DCTRLR_DTDIR | \
SDMMC_DCTRLR_DTMODE | \
SDMMC_DCTRLR_DBLOCKSIZE)
#define SDMMC_DBLOCKSIZE_8 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \
SDMMC_DCTRLR_DBLOCKSIZE_1)
#define SDMMC_DBLOCKSIZE_512 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \
SDMMC_DCTRLR_DBLOCKSIZE_3)
/* SDMMC status register */
#define SDMMC_STAR_CCRCFAIL BIT(0)
......@@ -152,10 +146,14 @@ bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
static void stm32_sdmmc2_init(void)
{
uint32_t clock_div;
uint32_t freq = STM32MP_MMC_INIT_FREQ;
uintptr_t base = sdmmc2_params.reg_base;
clock_div = div_round_up(sdmmc2_params.clk_rate,
STM32MP_MMC_INIT_FREQ * 2);
if (sdmmc2_params.max_freq != 0U) {
freq = MIN(sdmmc2_params.max_freq, freq);
}
clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U);
mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
sdmmc2_params.negedge |
......@@ -406,7 +404,7 @@ static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width)
{
uintptr_t base = sdmmc2_params.reg_base;
uint32_t bus_cfg = 0;
uint32_t clock_div, max_freq;
uint32_t clock_div, max_freq, freq;
uint32_t clk_rate = sdmmc2_params.clk_rate;
uint32_t max_bus_freq = sdmmc2_params.device_info->max_bus_freq;
......@@ -438,7 +436,13 @@ static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width)
}
}
clock_div = div_round_up(clk_rate, max_freq * 2);
if (sdmmc2_params.max_freq != 0U) {
freq = MIN(sdmmc2_params.max_freq, max_freq);
} else {
freq = max_freq;
}
clock_div = div_round_up(clk_rate, freq * 2U);
mmio_write_32(base + SDMMC_CLKCR,
SDMMC_CLKCR_HWFC_EN | clock_div | bus_cfg |
......@@ -454,11 +458,14 @@ static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
int ret;
uintptr_t base = sdmmc2_params.reg_base;
uint32_t data_ctrl = SDMMC_DCTRLR_DTDIR;
uint32_t arg_size;
assert(size != 0U);
if (size == 8U) {
data_ctrl |= SDMMC_DBLOCKSIZE_8;
if (size > MMC_BLOCK_SIZE) {
arg_size = MMC_BLOCK_SIZE;
} else {
data_ctrl |= SDMMC_DBLOCKSIZE_512;
arg_size = size;
}
sdmmc2_params.use_dma = plat_sdmmc2_use_dma(base, buf);
......@@ -477,12 +484,7 @@ static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
zeromem(&cmd, sizeof(struct mmc_cmd));
cmd.cmd_idx = MMC_CMD(16);
if (size > MMC_BLOCK_SIZE) {
cmd.cmd_arg = MMC_BLOCK_SIZE;
} else {
cmd.cmd_arg = size;
}
cmd.cmd_arg = arg_size;
cmd.resp_type = MMC_RESPONSE_R1;
ret = stm32_sdmmc2_send_cmd(&cmd);
......@@ -504,6 +506,8 @@ static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
flush_dcache_range(buf, size);
}
data_ctrl |= __builtin_ctz(arg_size) << SDMMC_DCTRLR_DBLOCKSIZE_SHIFT;
mmio_clrsetbits_32(base + SDMMC_DCTRLR,
SDMMC_DCTRLR_CLEAR_MASK,
data_ctrl);
......@@ -692,6 +696,11 @@ static int stm32_sdmmc2_dt_get_config(void)
}
}
cuint = fdt_getprop(fdt, sdmmc_node, "max-frequency", NULL);
if (cuint != NULL) {
sdmmc2_params.max_freq = fdt32_to_cpu(*cuint);
}
return 0;
}
......
......@@ -299,6 +299,7 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
break;
case STM32MP_LPDDR2:
case STM32MP_LPDDR3:
/*
* Set LDO3 to 1.8V
* Set LDO3 to bypass mode if BUCK3 = 1.8V
......
/*
* Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef STM32_IWDG_H
#define STM32_IWDG_H
#include <stdint.h>
#define IWDG_HW_ENABLED BIT(0)
#define IWDG_DISABLE_ON_STOP BIT(1)
#define IWDG_DISABLE_ON_STANDBY BIT(2)
int stm32_iwdg_init(void);
void stm32_iwdg_refresh(void);
#endif /* STM32_IWDG_H */
/*
* Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
* Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
......@@ -22,6 +22,7 @@ struct stm32_sdmmc2_params {
unsigned int dirpol;
unsigned int clock_id;
unsigned int reset_id;
unsigned int max_freq;
bool use_dma;
};
......
......@@ -10,12 +10,16 @@
#include <stdbool.h>
#include <platform_def.h>
#include <arch_helpers.h>
/* Functions to save and get boot context address given by ROM code */
void stm32mp_save_boot_ctx_address(uintptr_t address);
uintptr_t stm32mp_get_boot_ctx_address(void);
bool stm32mp_is_single_core(void);
/* Return the base address of the DDR controller */
uintptr_t stm32mp_ddrctrl_base(void);
......@@ -28,6 +32,20 @@ uintptr_t stm32mp_pwr_base(void);
/* Return the base address of the RCC peripheral */
uintptr_t stm32mp_rcc_base(void);
/* Check MMU status to allow spinlock use */
bool stm32mp_lock_available(void);
/* Get IWDG platform instance ID from peripheral IO memory base address */
uint32_t stm32_iwdg_get_instance(uintptr_t base);
/* Return bitflag mask for expected IWDG configuration from OTP content */
uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst);
#if defined(IMAGE_BL2)
/* Update OTP shadow registers with IWDG configuration from device tree */
uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags);
#endif
/*
* Platform util functions for the GPIO driver
* @bank: Target GPIO bank ID as per DT bindings
......@@ -45,6 +63,12 @@ uintptr_t stm32_get_gpio_bank_base(unsigned int bank);
unsigned long stm32_get_gpio_bank_clock(unsigned int bank);
uint32_t stm32_get_gpio_bank_offset(unsigned int bank);
/* Print CPU information */
void stm32mp_print_cpuinfo(void);
/* Print board information */
void stm32mp_print_boardinfo(void);
/*
* Util for clock gating and to get clock rate for stm32 and platform drivers
* @id: Target clock ID, ID used in clock DT bindings
......@@ -72,4 +96,12 @@ static inline bool timeout_elapsed(uint64_t expire)
return read_cntpct_el0() > expire;
}
/*
* Check that the STM32 header of a .stm32 binary image is valid
* @param header: pointer to the stm32 image header
* @param buffer: address of the binary image (payload)
* @return: 0 on success, negative value in case of error
*/
int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer);
#endif /* STM32MP_COMMON_H */
......@@ -5,6 +5,7 @@
*/
#include <assert.h>
#include <errno.h>
#include <platform_def.h>
......@@ -87,6 +88,14 @@ uintptr_t stm32mp_rcc_base(void)
return rcc_base;
}
bool stm32mp_lock_available(void)
{
const uint32_t c_m_bits = SCTLR_M_BIT | SCTLR_C_BIT;
/* The spinlocks are used only when MMU and data cache are enabled */
return (read_sctlr() & c_m_bits) == c_m_bits;
}
uintptr_t stm32_get_gpio_bank_base(unsigned int bank)
{
if (bank == GPIO_BANK_Z) {
......@@ -108,3 +117,37 @@ uint32_t stm32_get_gpio_bank_offset(unsigned int bank)
return bank * GPIO_BANK_OFFSET;
}
int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer)
{
uint32_t i;
uint32_t img_checksum = 0U;
/*
* Check header/payload validity:
* - Header magic
* - Header version
* - Payload checksum
*/
if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
ERROR("Header magic\n");
return -EINVAL;
}
if (header->header_version != BOOT_API_HEADER_VERSION) {
ERROR("Header version\n");
return -EINVAL;
}
for (i = 0U; i < header->image_length; i++) {
img_checksum += *(uint8_t *)(buffer + i);
}
if (header->payload_checksum != img_checksum) {
ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
header->payload_checksum);
return -EINVAL;
}
return 0;
}
......@@ -17,6 +17,7 @@
#include <drivers/generic_delay_timer.h>
#include <drivers/st/bsec.h>
#include <drivers/st/stm32_console.h>
#include <drivers/st/stm32_iwdg.h>
#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32mp_reset.h>
#include <drivers/st/stm32mp1_clk.h>
......@@ -28,6 +29,7 @@
#include <plat/common/platform.h>
#include <stm32mp1_context.h>
#include <stm32mp1_dbgmcu.h>
static struct console_stm32 console;
......@@ -270,12 +272,26 @@ void bl2_el3_plat_arch_setup(void)
panic();
}
stm32mp_print_cpuinfo();
board_model = dt_get_board_model();
if (board_model != NULL) {
NOTICE("Model: %s\n", board_model);
}
stm32mp_print_boardinfo();
skip_console_init:
if (stm32_iwdg_init() < 0) {
panic();
}
stm32_iwdg_refresh();
result = stm32mp1_dbgmcu_freeze_iwdg2();
if (result != 0) {
INFO("IWDG2 freeze error : %i\n", result);
}
if (stm32_save_boot_interface(boot_context->boot_interface_selected,
boot_context->boot_interface_instance) !=
......
/*
* Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef STM32MP1_DBGMCU_H
#define STM32MP1_DBGMCU_H
#include <stdint.h>
/* Get chip version and ID from DBGMCU registers */
int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version);
int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id);
/*
* Freeze watchdog when a debugger is attached, if the security configuration
* allows it.
* Return 0 on success, a negative error value otherwise.
*/
int stm32mp1_dbgmcu_freeze_iwdg2(void);
#endif /* STM32MP1_DBGMCU_H */
......@@ -57,11 +57,13 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \
drivers/st/ddr/stm32mp1_ddr_helpers.c \
drivers/st/gpio/stm32_gpio.c \
drivers/st/i2c/stm32_i2c.c \
drivers/st/iwdg/stm32_iwdg.c \
drivers/st/pmic/stm32mp_pmic.c \
drivers/st/pmic/stpmic1.c \
drivers/st/reset/stm32mp1_reset.c \
plat/st/common/stm32mp_dt.c \
plat/st/stm32mp1/stm32mp1_context.c \
plat/st/stm32mp1/stm32mp1_dbgmcu.c \
plat/st/stm32mp1/stm32mp1_helper.S \
plat/st/stm32mp1/stm32mp1_security.c \
plat/st/stm32mp1/stm32mp1_syscfg.c
......
......@@ -19,6 +19,7 @@
#include <drivers/st/bsec.h>
#include <drivers/st/stm32_console.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32_iwdg.h>
#include <drivers/st/stm32mp1_clk.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <lib/el3_runtime/context_mgmt.h>
......@@ -88,6 +89,12 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* Imprecise aborts can be masked in NonSecure */
write_scr(read_scr() | SCR_AW_BIT);
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
BL_CODE_END - BL_CODE_BASE,
MT_CODE | MT_SECURE);
configure_mmu();
assert(params_from_bl2 != NULL);
assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
assert(params_from_bl2->h.version >= VERSION_2);
......@@ -127,6 +134,11 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
0) {
panic();
}
#ifdef DEBUG
console_set_scope(&console.console,
CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
#endif
}
}
......@@ -135,12 +147,6 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
******************************************************************************/
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();
......@@ -157,6 +163,10 @@ void sp_min_platform_setup(void)
for (uint32_t pin = 0U; pin < STM32MP_GPIOZ_PIN_MAX_COUNT; pin++) {
set_gpio_secure_cfg(GPIO_BANK_Z, pin, false);
}
if (stm32_iwdg_init() < 0) {
panic();
}
}
void sp_min_plat_arch_setup(void)
......
/*
* Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <platform_def.h>
#include <common/debug.h>
#include <drivers/st/bsec.h>
#include <drivers/st/stm32mp1_rcc.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <stm32mp1_dbgmcu.h>
#define DBGMCU_IDC U(0x00)
#define DBGMCU_APB4FZ1 U(0x2C)
#define DBGMCU_IDC_DEV_ID_MASK GENMASK(11, 0)
#define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16)
#define DBGMCU_IDC_REV_ID_SHIFT 16
#define DBGMCU_APB4FZ1_IWDG2 BIT(2)
static uintptr_t get_rcc_base(void)
{
/* This is called before stm32mp_rcc_base() is available */
return RCC_BASE;
}
static int stm32mp1_dbgmcu_init(void)
{
uint32_t dbg_conf;
uintptr_t rcc_base = get_rcc_base();
dbg_conf = bsec_read_debug_conf();
if ((dbg_conf & BSEC_DBGSWGEN) == 0U) {
uint32_t result = bsec_write_debug_conf(dbg_conf |
BSEC_DBGSWGEN);
if (result != BSEC_OK) {
ERROR("Error enabling DBGSWGEN\n");
return -1;
}
}
mmio_setbits_32(rcc_base + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
return 0;
}
int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version)
{
if (stm32mp1_dbgmcu_init() != 0) {
return -EPERM;
}
*chip_version = (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
return 0;
}
int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id)
{
if (stm32mp1_dbgmcu_init() != 0) {
return -EPERM;
}
*chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
DBGMCU_IDC_DEV_ID_MASK;
return 0;
}
int stm32mp1_dbgmcu_freeze_iwdg2(void)
{
uint32_t dbg_conf;
if (stm32mp1_dbgmcu_init() != 0) {
return -EPERM;
}
dbg_conf = bsec_read_debug_conf();
if ((dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN)) != 0U) {
mmio_setbits_32(DBGMCU_BASE + DBGMCU_APB4FZ1,
DBGMCU_APB4FZ1_IWDG2);
}
return 0;
}
......@@ -15,15 +15,37 @@
#include <lib/xlat_tables/xlat_tables_defs.h>
#ifndef __ASSEMBLER__
#include <drivers/st/bsec.h>
#include <drivers/st/stm32mp1_clk.h>
#include <boot_api.h>
#include <stm32mp_common.h>
#include <stm32mp_dt.h>
#include <stm32mp_shres_helpers.h>
#include <stm32mp1_dbgmcu.h>
#include <stm32mp1_private.h>
#endif
/*******************************************************************************
* CHIP ID
******************************************************************************/
#define STM32MP157C_PART_NB U(0x05000000)
#define STM32MP157A_PART_NB U(0x05000001)
#define STM32MP153C_PART_NB U(0x05000024)
#define STM32MP153A_PART_NB U(0x05000025)
#define STM32MP151C_PART_NB U(0x0500002E)
#define STM32MP151A_PART_NB U(0x0500002F)
#define STM32MP1_REV_B U(0x2000)
/*******************************************************************************
* PACKAGE ID
******************************************************************************/
#define PKG_AA_LFBGA448 U(4)
#define PKG_AB_LFBGA354 U(3)
#define PKG_AC_TFBGA361 U(2)
#define PKG_AD_TFBGA257 U(1)
/*******************************************************************************
* STM32MP1 memory map related constants
******************************************************************************/
......@@ -44,6 +66,7 @@
enum ddr_type {
STM32MP_DDR3,
STM32MP_LPDDR2,
STM32MP_LPDDR3
};
#endif
......@@ -87,9 +110,9 @@ enum ddr_type {
#endif
#else
#if STACK_PROTECTOR_ENABLED
#define STM32MP_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */
#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */
#else
#define STM32MP_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */
#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */
#endif
#endif
......@@ -239,12 +262,27 @@ enum ddr_type {
/* OTP offsets */
#define DATA0_OTP U(0)
#define PART_NUMBER_OTP U(1)
#define PACKAGE_OTP U(16)
#define HW2_OTP U(18)
/* OTP mask */
/* DATA0 */
#define DATA0_OTP_SECURED BIT(6)
/* PART NUMBER */
#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0)
#define PART_NUMBER_OTP_PART_SHIFT 0
/* PACKAGE */
#define PACKAGE_OTP_PKG_MASK GENMASK_32(29, 27)
#define PACKAGE_OTP_PKG_SHIFT 27
/* IWDG OTP */
#define HW2_OTP_IWDG_HW_POS U(3)
#define HW2_OTP_IWDG_FZ_STOP_POS U(5)
#define HW2_OTP_IWDG_FZ_STANDBY_POS U(7)
/* HW2 OTP */
#define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13)
......@@ -271,14 +309,31 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
******************************************************************************/
#define DDRPHYC_BASE U(0x5A004000)
/*******************************************************************************
* STM32MP1 IWDG
******************************************************************************/
#define IWDG_MAX_INSTANCE U(2)
#define IWDG1_INST U(0)
#define IWDG2_INST U(1)
#define IWDG1_BASE U(0x5C003000)
#define IWDG2_BASE U(0x5A002000)
/*******************************************************************************
* STM32MP1 I2C4
******************************************************************************/
#define I2C4_BASE U(0x5C002000)
/*******************************************************************************
* STM32MP1 DBGMCU
******************************************************************************/
#define DBGMCU_BASE U(0x50081000)
/*******************************************************************************
* Device Tree defines
******************************************************************************/
#define DT_BSEC_COMPAT "st,stm32mp15-bsec"
#define DT_IWDG_COMPAT "st,stm32mp1-iwdg"
#define DT_PWR_COMPAT "st,stm32mp1-pwr"
#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
#define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg"
......
......@@ -6,10 +6,30 @@
#include <assert.h>
#include <libfdt.h>
#include <platform_def.h>
#include <drivers/st/stm32_iwdg.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
/* Internal layout of the 32bit OTP word board_id */
#define BOARD_ID_BOARD_NB_MASK GENMASK(31, 16)
#define BOARD_ID_BOARD_NB_SHIFT 16
#define BOARD_ID_VARIANT_MASK GENMASK(15, 12)
#define BOARD_ID_VARIANT_SHIFT 12
#define BOARD_ID_REVISION_MASK GENMASK(11, 8)
#define BOARD_ID_REVISION_SHIFT 8
#define BOARD_ID_BOM_MASK GENMASK(3, 0)
#define BOARD_ID2NB(_id) (((_id) & BOARD_ID_BOARD_NB_MASK) >> \
BOARD_ID_BOARD_NB_SHIFT)
#define BOARD_ID2VAR(_id) (((_id) & BOARD_ID_VARIANT_MASK) >> \
BOARD_ID_VARIANT_SHIFT)
#define BOARD_ID2REV(_id) (((_id) & BOARD_ID_REVISION_MASK) >> \
BOARD_ID_REVISION_SHIFT)
#define BOARD_ID2BOM(_id) ((_id) & BOARD_ID_BOM_MASK)
#define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \
STM32MP_SYSRAM_SIZE, \
MT_MEMORY | \
......@@ -66,3 +86,269 @@ unsigned long stm32_get_gpio_bank_clock(unsigned int bank)
return GPIOA + (bank - GPIO_BANK_A);
}
static int get_part_number(uint32_t *part_nb)
{
uint32_t part_number;
uint32_t dev_id;
if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) {
return -1;
}
if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) {
ERROR("BSEC: PART_NUMBER_OTP Error\n");
return -1;
}
part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >>
PART_NUMBER_OTP_PART_SHIFT;
*part_nb = part_number | (dev_id << 16);
return 0;
}
static int get_cpu_package(uint32_t *cpu_package)
{
uint32_t package;
if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) {
ERROR("BSEC: PACKAGE_OTP Error\n");
return -1;
}
*cpu_package = (package & PACKAGE_OTP_PKG_MASK) >>
PACKAGE_OTP_PKG_SHIFT;
return 0;
}
void stm32mp_print_cpuinfo(void)
{
const char *cpu_s, *cpu_r, *pkg;
uint32_t part_number;
uint32_t cpu_package;
uint32_t chip_dev_id;
int ret;
/* MPUs Part Numbers */
ret = get_part_number(&part_number);
if (ret < 0) {
WARN("Cannot get part number\n");
return;
}
switch (part_number) {
case STM32MP157C_PART_NB:
cpu_s = "157C";
break;
case STM32MP157A_PART_NB:
cpu_s = "157A";
break;
case STM32MP153C_PART_NB:
cpu_s = "153C";
break;
case STM32MP153A_PART_NB:
cpu_s = "153A";
break;
case STM32MP151C_PART_NB:
cpu_s = "151C";
break;
case STM32MP151A_PART_NB:
cpu_s = "151A";
break;
default:
cpu_s = "????";
break;
}
/* Package */
ret = get_cpu_package(&cpu_package);
if (ret < 0) {
WARN("Cannot get CPU package\n");
return;
}
switch (cpu_package) {
case PKG_AA_LFBGA448:
pkg = "AA";
break;
case PKG_AB_LFBGA354:
pkg = "AB";
break;
case PKG_AC_TFBGA361:
pkg = "AC";
break;
case PKG_AD_TFBGA257:
pkg = "AD";
break;
default:
pkg = "??";
break;
}
/* REVISION */
ret = stm32mp1_dbgmcu_get_chip_version(&chip_dev_id);
if (ret < 0) {
WARN("Cannot get CPU version\n");
return;
}
switch (chip_dev_id) {
case STM32MP1_REV_B:
cpu_r = "B";
break;
default:
cpu_r = "?";
break;
}
NOTICE("CPU: STM32MP%s%s Rev.%s\n", cpu_s, pkg, cpu_r);
}
void stm32mp_print_boardinfo(void)
{
uint32_t board_id;
uint32_t board_otp;
int bsec_node, bsec_board_id_node;
void *fdt;
const fdt32_t *cuint;
if (fdt_get_address(&fdt) == 0) {
panic();
}
bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
if (bsec_node < 0) {
return;
}
bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id");
if (bsec_board_id_node <= 0) {
return;
}
cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL);
if (cuint == NULL) {
panic();
}
board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) {
ERROR("BSEC: PART_NUMBER_OTP Error\n");
return;
}
if (board_id != 0U) {
char rev[2];
rev[0] = BOARD_ID2REV(board_id) - 1 + 'A';
rev[1] = '\0';
NOTICE("Board: MB%04x Var%d Rev.%s-%02d\n",
BOARD_ID2NB(board_id),
BOARD_ID2VAR(board_id),
rev,
BOARD_ID2BOM(board_id));
}
}
/* Return true when SoC provides a single Cortex-A7 core, and false otherwise */
bool stm32mp_is_single_core(void)
{
uint32_t part_number;
bool ret = false;
if (get_part_number(&part_number) < 0) {
ERROR("Invalid part number, assume single core chip");
return true;
}
switch (part_number) {
case STM32MP151A_PART_NB:
case STM32MP151C_PART_NB:
ret = true;
break;
default:
break;
}
return ret;
}
uint32_t stm32_iwdg_get_instance(uintptr_t base)
{
switch (base) {
case IWDG1_BASE:
return IWDG1_INST;
case IWDG2_BASE:
return IWDG2_INST;
default:
panic();
}
}
uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst)
{
uint32_t iwdg_cfg = 0U;
uint32_t otp_value;
#if defined(IMAGE_BL2)
if (bsec_shadow_register(HW2_OTP) != BSEC_OK) {
panic();
}
#endif
if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
panic();
}
if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_HW_POS)) != 0U) {
iwdg_cfg |= IWDG_HW_ENABLED;
}
if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS)) != 0U) {
iwdg_cfg |= IWDG_DISABLE_ON_STOP;
}
if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS)) != 0U) {
iwdg_cfg |= IWDG_DISABLE_ON_STANDBY;
}
return iwdg_cfg;
}
#if defined(IMAGE_BL2)
uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags)
{
uint32_t otp;
uint32_t result;
if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) {
panic();
}
if ((flags & IWDG_DISABLE_ON_STOP) != 0U) {
otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
}
if ((flags & IWDG_DISABLE_ON_STANDBY) != 0U) {
otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
}
result = bsec_write_otp(otp, HW2_OTP);
if (result != BSEC_OK) {
return result;
}
/* Sticky lock OTP_IWDG (read and write) */
if (!bsec_write_sr_lock(HW2_OTP, 1U) ||
!bsec_write_sw_lock(HW2_OTP, 1U)) {
return BSEC_LOCK_FAIL;
}
return BSEC_OK;
}
#endif
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