GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
if ARCH_STM32MP
|
||||
|
||||
config SPL
|
||||
select SPL_BOARD_INIT
|
||||
select SPL_CLK
|
||||
select SPL_DM
|
||||
select SPL_DM_SEQ_ALIAS
|
||||
select SPL_DRIVERS_MISC_SUPPORT
|
||||
select SPL_FRAMEWORK
|
||||
select SPL_GPIO_SUPPORT
|
||||
select SPL_LIBCOMMON_SUPPORT
|
||||
select SPL_LIBGENERIC_SUPPORT
|
||||
select SPL_OF_CONTROL
|
||||
select SPL_OF_TRANSLATE
|
||||
select SPL_PINCTRL
|
||||
select SPL_REGMAP
|
||||
select SPL_DM_RESET
|
||||
select SPL_SERIAL_SUPPORT
|
||||
select SPL_SPI_LOAD
|
||||
select SPL_SYSCON
|
||||
select SPL_WATCHDOG_SUPPORT if WATCHDOG
|
||||
imply BOOTSTAGE_STASH if SPL_BOOTSTAGE
|
||||
imply SPL_BOOTSTAGE if BOOTSTAGE
|
||||
imply SPL_DISPLAY_PRINT
|
||||
imply SPL_LIBDISK_SUPPORT
|
||||
|
||||
config SYS_SOC
|
||||
default "stm32mp"
|
||||
|
||||
config SYS_MALLOC_LEN
|
||||
default 0x2000000
|
||||
|
||||
config ENV_SIZE
|
||||
default 0x2000
|
||||
|
||||
config TARGET_STM32MP1
|
||||
bool "Support stm32mp1xx"
|
||||
select ARCH_SUPPORT_PSCI if !STM32MP1_TRUSTED
|
||||
select CPU_V7A
|
||||
select CPU_V7_HAS_NONSEC if !STM32MP1_TRUSTED
|
||||
select CPU_V7_HAS_VIRT
|
||||
select OF_BOARD_SETUP
|
||||
select PINCTRL_STM32
|
||||
select STM32_RCC
|
||||
select STM32_RESET
|
||||
select STM32_SERIAL
|
||||
select SYS_ARCH_TIMER
|
||||
imply BOOTCOUNT_LIMIT
|
||||
imply CMD_BOOTCOUNT
|
||||
imply CMD_CLS if CMD_BMP
|
||||
imply DISABLE_CONSOLE
|
||||
imply PRE_CONSOLE_BUFFER
|
||||
imply SILENT_CONSOLE
|
||||
imply SYSRESET_PSCI if STM32MP1_TRUSTED
|
||||
imply SYSRESET_SYSCON if !STM32MP1_TRUSTED
|
||||
help
|
||||
target STMicroelectronics SOC STM32MP1 family
|
||||
STM32MP157, STM32MP153 or STM32MP151
|
||||
STMicroelectronics MPU with core ARMv7
|
||||
dual core A7 for STM32MP157/3, monocore for STM32MP151
|
||||
|
||||
config STM32MP1_TRUSTED
|
||||
bool "Support trusted boot with TF-A"
|
||||
default y if !SPL
|
||||
select ARM_SMCCC
|
||||
help
|
||||
Say Y here to enable boot with TF-A
|
||||
Trusted boot chain is :
|
||||
BootRom => TF-A.stm32 (clock & DDR) => U-Boot.stm32
|
||||
TF-A monitor provides proprietary SMC to manage secure devices
|
||||
|
||||
config STM32MP1_OPTEE
|
||||
bool "Support trusted boot with TF-A and OP-TEE"
|
||||
depends on STM32MP1_TRUSTED
|
||||
default n
|
||||
help
|
||||
Say Y here to enable boot with TF-A and OP-TEE
|
||||
Trusted boot chain is :
|
||||
BootRom => TF-A.stm32 (clock & DDR) => OP-TEE => U-Boot.stm32
|
||||
OP-TEE monitor provides ST SMC to access to secure resources
|
||||
|
||||
config SYS_TEXT_BASE
|
||||
prompt "U-Boot base address"
|
||||
default 0xC0100000
|
||||
help
|
||||
configure the U-Boot base address
|
||||
when DDR driver is used:
|
||||
DDR + 1MB (0xC0100000)
|
||||
|
||||
config NR_DRAM_BANKS
|
||||
default 1
|
||||
|
||||
config SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2
|
||||
hex "Partition on MMC2 to use to load U-Boot from"
|
||||
depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
|
||||
default 1
|
||||
help
|
||||
Partition on the second MMC to load U-Boot from when the MMC is being
|
||||
used in raw mode
|
||||
|
||||
config STM32_ETZPC
|
||||
bool "STM32 Extended TrustZone Protection"
|
||||
depends on TARGET_STM32MP1
|
||||
default y
|
||||
help
|
||||
Say y to enable STM32 Extended TrustZone Protection
|
||||
|
||||
config CMD_STM32KEY
|
||||
bool "command stm32key to fuse public key hash"
|
||||
default y
|
||||
depends on CMD_FUSE
|
||||
help
|
||||
fuse public key hash in corresponding fuse used to authenticate
|
||||
binary.
|
||||
|
||||
|
||||
config PRE_CON_BUF_ADDR
|
||||
default 0xC02FF000
|
||||
|
||||
config PRE_CON_BUF_SZ
|
||||
default 4096
|
||||
|
||||
config BOOTSTAGE_STASH_ADDR
|
||||
default 0xC3000000
|
||||
|
||||
if BOOTCOUNT_LIMIT
|
||||
config SYS_BOOTCOUNT_SINGLEWORD
|
||||
default y
|
||||
|
||||
# TAMP_BOOTCOUNT = TAMP_BACKUP_REGISTER(21)
|
||||
config SYS_BOOTCOUNT_ADDR
|
||||
default 0x5C00A154
|
||||
endif
|
||||
|
||||
if DEBUG_UART
|
||||
|
||||
config DEBUG_UART_BOARD_INIT
|
||||
default y
|
||||
|
||||
# debug on UART4 by default
|
||||
config DEBUG_UART_BASE
|
||||
default 0x40010000
|
||||
|
||||
# clock source is HSI on reset
|
||||
config DEBUG_UART_CLOCK
|
||||
default 64000000
|
||||
endif
|
||||
|
||||
source "board/st/stm32mp1/Kconfig"
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += dram_init.o
|
||||
obj-y += syscon.o
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-y += spl.o
|
||||
else
|
||||
obj-y += bsec.o
|
||||
obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
|
||||
obj-$(CONFIG_ARMV7_PSCI) += psci.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o
|
||||
obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o
|
||||
@@ -0,0 +1,470 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <misc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/stm32mp1_smc.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#define BSEC_OTP_MAX_VALUE 95
|
||||
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
#define BSEC_TIMEOUT_US 10000
|
||||
|
||||
/* BSEC REGISTER OFFSET (base relative) */
|
||||
#define BSEC_OTP_CONF_OFF 0x000
|
||||
#define BSEC_OTP_CTRL_OFF 0x004
|
||||
#define BSEC_OTP_WRDATA_OFF 0x008
|
||||
#define BSEC_OTP_STATUS_OFF 0x00C
|
||||
#define BSEC_OTP_LOCK_OFF 0x010
|
||||
#define BSEC_DISTURBED_OFF 0x01C
|
||||
#define BSEC_ERROR_OFF 0x034
|
||||
#define BSEC_SPLOCK_OFF 0x064 /* Program safmem sticky lock */
|
||||
#define BSEC_SWLOCK_OFF 0x07C /* write in OTP sticky lock */
|
||||
#define BSEC_SRLOCK_OFF 0x094 /* shadowing sticky lock */
|
||||
#define BSEC_OTP_DATA_OFF 0x200
|
||||
|
||||
/* BSEC_CONFIGURATION Register MASK */
|
||||
#define BSEC_CONF_POWER_UP 0x001
|
||||
|
||||
/* BSEC_CONTROL Register */
|
||||
#define BSEC_READ 0x000
|
||||
#define BSEC_WRITE 0x100
|
||||
|
||||
/* LOCK Register */
|
||||
#define OTP_LOCK_MASK 0x1F
|
||||
#define OTP_LOCK_BANK_SHIFT 0x05
|
||||
#define OTP_LOCK_BIT_MASK 0x01
|
||||
|
||||
/* STATUS Register */
|
||||
#define BSEC_MODE_BUSY_MASK 0x08
|
||||
#define BSEC_MODE_PROGFAIL_MASK 0x10
|
||||
#define BSEC_MODE_PWR_MASK 0x20
|
||||
|
||||
/*
|
||||
* OTP Lock services definition
|
||||
* Value must corresponding to the bit number in the register
|
||||
*/
|
||||
#define BSEC_LOCK_PROGRAM 0x04
|
||||
|
||||
/**
|
||||
* bsec_check_error() - Check status of one otp
|
||||
* @base: base address of bsec IP
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: 0 if no error, -EAGAIN or -ENOTSUPP
|
||||
*/
|
||||
static u32 bsec_check_error(u32 base, u32 otp)
|
||||
{
|
||||
u32 bit;
|
||||
u32 bank;
|
||||
|
||||
bit = 1 << (otp & OTP_LOCK_MASK);
|
||||
bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
|
||||
|
||||
if (readl(base + BSEC_DISTURBED_OFF + bank) & bit)
|
||||
return -EAGAIN;
|
||||
else if (readl(base + BSEC_ERROR_OFF + bank) & bit)
|
||||
return -ENOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_lock() - manage lock for each type SR/SP/SW
|
||||
* @address: address of bsec IP register
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_lock(u32 address, u32 otp)
|
||||
{
|
||||
u32 bit;
|
||||
u32 bank;
|
||||
|
||||
bit = 1 << (otp & OTP_LOCK_MASK);
|
||||
bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
|
||||
|
||||
return !!(readl(address + bank) & bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_read_SR_lock() - read SR lock (Shadowing)
|
||||
* @base: base address of bsec IP
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_SR_lock(u32 base, u32 otp)
|
||||
{
|
||||
return bsec_read_lock(base + BSEC_SRLOCK_OFF, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_read_SP_lock() - read SP lock (program Lock)
|
||||
* @base: base address of bsec IP
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_SP_lock(u32 base, u32 otp)
|
||||
{
|
||||
return bsec_read_lock(base + BSEC_SPLOCK_OFF, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_SW_lock() - manage SW lock (Write in Shadow)
|
||||
* @base: base address of bsec IP
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: true if locked else false
|
||||
*/
|
||||
static bool bsec_read_SW_lock(u32 base, u32 otp)
|
||||
{
|
||||
return bsec_read_lock(base + BSEC_SWLOCK_OFF, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_power_safmem() - Activate or deactivate safmem power
|
||||
* @base: base address of bsec IP
|
||||
* @power: true to power up , false to power down
|
||||
* Return: 0 if succeed
|
||||
*/
|
||||
static int bsec_power_safmem(u32 base, bool power)
|
||||
{
|
||||
u32 val;
|
||||
u32 mask;
|
||||
|
||||
if (power) {
|
||||
setbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP);
|
||||
mask = BSEC_MODE_PWR_MASK;
|
||||
} else {
|
||||
clrbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP);
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
/* waiting loop */
|
||||
return readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
|
||||
val, (val & BSEC_MODE_PWR_MASK) == mask,
|
||||
BSEC_TIMEOUT_US);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_shadow_register() - copy safmen otp to bsec data
|
||||
* @base: base address of bsec IP
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: 0 if no error
|
||||
*/
|
||||
static int bsec_shadow_register(u32 base, u32 otp)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
bool power_up = false;
|
||||
|
||||
/* check if shadowing of otp is locked */
|
||||
if (bsec_read_SR_lock(base, otp))
|
||||
pr_debug("bsec : OTP %d is locked and refreshed with 0\n", otp);
|
||||
|
||||
/* check if safemem is power up */
|
||||
val = readl(base + BSEC_OTP_STATUS_OFF);
|
||||
if (!(val & BSEC_MODE_PWR_MASK)) {
|
||||
ret = bsec_power_safmem(base, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
power_up = true;
|
||||
}
|
||||
/* set BSEC_OTP_CTRL_OFF with the otp value*/
|
||||
writel(otp | BSEC_READ, base + BSEC_OTP_CTRL_OFF);
|
||||
|
||||
/* check otp status*/
|
||||
ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
|
||||
val, (val & BSEC_MODE_BUSY_MASK) == 0,
|
||||
BSEC_TIMEOUT_US);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bsec_check_error(base, otp);
|
||||
|
||||
if (power_up)
|
||||
bsec_power_safmem(base, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_read_shadow() - read an otp data value from shadow
|
||||
* @base: base address of bsec IP
|
||||
* @val: read value
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: 0 if no error
|
||||
*/
|
||||
static int bsec_read_shadow(u32 base, u32 *val, u32 otp)
|
||||
{
|
||||
*val = readl(base + BSEC_OTP_DATA_OFF + otp * sizeof(u32));
|
||||
|
||||
return bsec_check_error(base, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_write_shadow() - write value in BSEC data register in shadow
|
||||
* @base: base address of bsec IP
|
||||
* @val: value to write
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* Return: 0 if no error
|
||||
*/
|
||||
static int bsec_write_shadow(u32 base, u32 val, u32 otp)
|
||||
{
|
||||
/* check if programming of otp is locked */
|
||||
if (bsec_read_SW_lock(base, otp))
|
||||
pr_debug("bsec : OTP %d is lock, write will be ignore\n", otp);
|
||||
|
||||
writel(val, base + BSEC_OTP_DATA_OFF + otp * sizeof(u32));
|
||||
|
||||
return bsec_check_error(base, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* bsec_program_otp() - program a bit in SAFMEM
|
||||
* @base: base address of bsec IP
|
||||
* @val: value to program
|
||||
* @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
|
||||
* after the function the otp data is not refreshed in shadow
|
||||
* Return: 0 if no error
|
||||
*/
|
||||
static int bsec_program_otp(long base, u32 val, u32 otp)
|
||||
{
|
||||
u32 ret;
|
||||
bool power_up = false;
|
||||
|
||||
if (bsec_read_SP_lock(base, otp))
|
||||
pr_debug("bsec : OTP %d locked, prog will be ignore\n", otp);
|
||||
|
||||
if (readl(base + BSEC_OTP_LOCK_OFF) & (1 << BSEC_LOCK_PROGRAM))
|
||||
pr_debug("bsec : Global lock, prog will be ignore\n");
|
||||
|
||||
/* check if safemem is power up */
|
||||
if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) {
|
||||
ret = bsec_power_safmem(base, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
power_up = true;
|
||||
}
|
||||
/* set value in write register*/
|
||||
writel(val, base + BSEC_OTP_WRDATA_OFF);
|
||||
|
||||
/* set BSEC_OTP_CTRL_OFF with the otp value */
|
||||
writel(otp | BSEC_WRITE, base + BSEC_OTP_CTRL_OFF);
|
||||
|
||||
/* check otp status*/
|
||||
ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
|
||||
val, (val & BSEC_MODE_BUSY_MASK) == 0,
|
||||
BSEC_TIMEOUT_US);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & BSEC_MODE_PROGFAIL_MASK)
|
||||
ret = -EACCES;
|
||||
else
|
||||
ret = bsec_check_error(base, otp);
|
||||
|
||||
if (power_up)
|
||||
bsec_power_safmem(base, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_STM32MP1_TRUSTED */
|
||||
|
||||
/* BSEC MISC driver *******************************************************/
|
||||
struct stm32mp_bsec_platdata {
|
||||
u32 base;
|
||||
};
|
||||
|
||||
static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp)
|
||||
{
|
||||
#ifdef CONFIG_STM32MP1_TRUSTED
|
||||
return stm32_smc(STM32_SMC_BSEC,
|
||||
STM32_SMC_READ_OTP,
|
||||
otp, 0, val);
|
||||
#else
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
u32 tmp_data = 0;
|
||||
int ret;
|
||||
|
||||
/* read current shadow value */
|
||||
ret = bsec_read_shadow(plat->base, &tmp_data, otp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* copy otp in shadow */
|
||||
ret = bsec_shadow_register(plat->base, otp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bsec_read_shadow(plat->base, val, otp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* restore shadow value */
|
||||
ret = bsec_write_shadow(plat->base, tmp_data, otp);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp)
|
||||
{
|
||||
#ifdef CONFIG_STM32MP1_TRUSTED
|
||||
return stm32_smc(STM32_SMC_BSEC,
|
||||
STM32_SMC_READ_SHADOW,
|
||||
otp, 0, val);
|
||||
#else
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
return bsec_read_shadow(plat->base, val, otp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp)
|
||||
{
|
||||
#ifdef CONFIG_STM32MP1_TRUSTED
|
||||
return stm32_smc_exec(STM32_SMC_BSEC,
|
||||
STM32_SMC_PROG_OTP,
|
||||
otp, val);
|
||||
#else
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
return bsec_program_otp(plat->base, val, otp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
|
||||
{
|
||||
#ifdef CONFIG_STM32MP1_TRUSTED
|
||||
return stm32_smc_exec(STM32_SMC_BSEC,
|
||||
STM32_SMC_WRITE_SHADOW,
|
||||
otp, val);
|
||||
#else
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
return bsec_write_shadow(plat->base, val, otp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int stm32mp_bsec_read(struct udevice *dev, int offset,
|
||||
void *buf, int size)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
bool shadow = true;
|
||||
int nb_otp = size / sizeof(u32);
|
||||
int otp;
|
||||
unsigned int offs = offset;
|
||||
|
||||
if (offs >= STM32_BSEC_OTP_OFFSET) {
|
||||
offs -= STM32_BSEC_OTP_OFFSET;
|
||||
shadow = false;
|
||||
}
|
||||
|
||||
if (offs < 0 || (offs % 4) || (size % 4))
|
||||
return -EINVAL;
|
||||
|
||||
otp = offs / sizeof(u32);
|
||||
|
||||
for (i = otp; i < (otp + nb_otp) && i <= BSEC_OTP_MAX_VALUE; i++) {
|
||||
u32 *addr = &((u32 *)buf)[i - otp];
|
||||
|
||||
if (shadow)
|
||||
ret = stm32mp_bsec_read_shadow(dev, addr, i);
|
||||
else
|
||||
ret = stm32mp_bsec_read_otp(dev, addr, i);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return (i - otp) * 4;
|
||||
}
|
||||
|
||||
static int stm32mp_bsec_write(struct udevice *dev, int offset,
|
||||
const void *buf, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
bool shadow = true;
|
||||
int nb_otp = size / sizeof(u32);
|
||||
int otp;
|
||||
unsigned int offs = offset;
|
||||
|
||||
if (offs >= STM32_BSEC_OTP_OFFSET) {
|
||||
offs -= STM32_BSEC_OTP_OFFSET;
|
||||
shadow = false;
|
||||
}
|
||||
|
||||
if (offs < 0 || (offs % 4) || (size % 4))
|
||||
return -EINVAL;
|
||||
|
||||
otp = offs / sizeof(u32);
|
||||
|
||||
for (i = otp; i < otp + nb_otp && i <= BSEC_OTP_MAX_VALUE; i++) {
|
||||
u32 *val = &((u32 *)buf)[i - otp];
|
||||
|
||||
if (shadow)
|
||||
ret = stm32mp_bsec_write_shadow(dev, *val, i);
|
||||
else
|
||||
ret = stm32mp_bsec_write_otp(dev, *val, i);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return (i - otp) * 4;
|
||||
}
|
||||
|
||||
static const struct misc_ops stm32mp_bsec_ops = {
|
||||
.read = stm32mp_bsec_read,
|
||||
.write = stm32mp_bsec_write,
|
||||
};
|
||||
|
||||
static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->base = (u32)dev_read_addr_ptr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
static int stm32mp_bsec_probe(struct udevice *dev)
|
||||
{
|
||||
int otp;
|
||||
struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
/* update unlocked shadow for OTP cleared by the rom code */
|
||||
for (otp = 57; otp <= BSEC_OTP_MAX_VALUE; otp++)
|
||||
if (!bsec_read_SR_lock(plat->base, otp))
|
||||
bsec_shadow_register(plat->base, otp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct udevice_id stm32mp_bsec_ids[] = {
|
||||
{ .compatible = "st,stm32mp15-bsec" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(stm32mp_bsec) = {
|
||||
.name = "stm32mp_bsec",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = stm32mp_bsec_ids,
|
||||
.ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata),
|
||||
.ops = &stm32mp_bsec_ops,
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
.probe = stm32mp_bsec_probe,
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <console.h>
|
||||
#include <misc.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/uclass.h>
|
||||
|
||||
#define STM32_OTP_HASH_KEY_START 24
|
||||
#define STM32_OTP_HASH_KEY_SIZE 8
|
||||
|
||||
static void read_hash_value(u32 addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < STM32_OTP_HASH_KEY_SIZE; i++) {
|
||||
printf("OTP value %i: %x\n", STM32_OTP_HASH_KEY_START + i,
|
||||
__be32_to_cpu(*(u32 *)addr));
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void fuse_hash_value(u32 addr, bool print)
|
||||
{
|
||||
struct udevice *dev;
|
||||
u32 word, val;
|
||||
int i, ret;
|
||||
|
||||
ret = uclass_get_device_by_driver(UCLASS_MISC,
|
||||
DM_GET_DRIVER(stm32mp_bsec),
|
||||
&dev);
|
||||
if (ret) {
|
||||
pr_err("Can't find stm32mp_bsec driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < STM32_OTP_HASH_KEY_SIZE; i++) {
|
||||
if (print)
|
||||
printf("Fuse OTP %i : %x\n",
|
||||
STM32_OTP_HASH_KEY_START + i,
|
||||
__be32_to_cpu(*(u32 *)addr));
|
||||
|
||||
word = STM32_OTP_HASH_KEY_START + i;
|
||||
val = __be32_to_cpu(*(u32 *)addr);
|
||||
misc_write(dev, STM32_BSEC_OTP(word), &val, 4);
|
||||
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static int confirm_prog(void)
|
||||
{
|
||||
puts("Warning: Programming fuses is an irreversible operation!\n"
|
||||
" This may brick your system.\n"
|
||||
" Use this command only if you are sure of what you are doing!\n"
|
||||
"\nReally perform this fuse programming? <y/N>\n");
|
||||
|
||||
if (confirm_yesno())
|
||||
return 1;
|
||||
|
||||
puts("Fuse programming aborted\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_stm32key(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
u32 addr;
|
||||
const char *op = argc >= 2 ? argv[1] : NULL;
|
||||
int confirmed = argc > 3 && !strcmp(argv[2], "-y");
|
||||
|
||||
argc -= 2 + confirmed;
|
||||
argv += 2 + confirmed;
|
||||
|
||||
if (argc < 1)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
addr = simple_strtoul(argv[0], NULL, 16);
|
||||
if (!addr)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (!strcmp(op, "read"))
|
||||
read_hash_value(addr);
|
||||
|
||||
if (!strcmp(op, "fuse")) {
|
||||
if (!confirmed && !confirm_prog())
|
||||
return CMD_RET_FAILURE;
|
||||
fuse_hash_value(addr, !confirmed);
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(stm32key, 4, 1, do_stm32key,
|
||||
"Fuse ST Hash key",
|
||||
"read <addr>: Read the hash store at addr in memory\n"
|
||||
"stm32key fuse [-y] <addr> : Fuse hash store at addr in otp\n");
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
#
|
||||
# Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
#
|
||||
|
||||
ifndef CONFIG_SPL
|
||||
ALL-y += u-boot.stm32
|
||||
else
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
ALL-y += u-boot-spl.stm32
|
||||
endif
|
||||
endif
|
||||
|
||||
MKIMAGEFLAGS_u-boot.stm32 = -T stm32image -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE)
|
||||
|
||||
u-boot.stm32: MKIMAGEOUTPUT = u-boot.stm32.log
|
||||
|
||||
u-boot.stm32: u-boot.bin FORCE
|
||||
$(call if_changed,mkimage)
|
||||
|
||||
MKIMAGEFLAGS_u-boot-spl.stm32 = -T stm32image -a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE)
|
||||
|
||||
spl/u-boot-spl.stm32: MKIMAGEOUTPUT = spl/u-boot-spl.stm32.log
|
||||
|
||||
spl/u-boot-spl.stm32: spl/u-boot-spl.bin FORCE
|
||||
$(call if_changed,mkimage)
|
||||
|
||||
u-boot-spl.stm32 : spl/u-boot-spl.stm32
|
||||
$(call if_changed,copy)
|
||||
@@ -0,0 +1,527 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <cpu_func.h>
|
||||
#include <debug_uart.h>
|
||||
#include <env.h>
|
||||
#include <misc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/stm32.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/uclass.h>
|
||||
|
||||
/* RCC register */
|
||||
#define RCC_TZCR (STM32_RCC_BASE + 0x00)
|
||||
#define RCC_DBGCFGR (STM32_RCC_BASE + 0x080C)
|
||||
#define RCC_BDCR (STM32_RCC_BASE + 0x0140)
|
||||
#define RCC_MP_APB5ENSETR (STM32_RCC_BASE + 0x0208)
|
||||
#define RCC_MP_AHB5ENSETR (STM32_RCC_BASE + 0x0210)
|
||||
#define RCC_BDCR_VSWRST BIT(31)
|
||||
#define RCC_BDCR_RTCSRC GENMASK(17, 16)
|
||||
#define RCC_DBGCFGR_DBGCKEN BIT(8)
|
||||
|
||||
/* Security register */
|
||||
#define ETZPC_TZMA1_SIZE (STM32_ETZPC_BASE + 0x04)
|
||||
#define ETZPC_DECPROT0 (STM32_ETZPC_BASE + 0x10)
|
||||
|
||||
#define TZC_GATE_KEEPER (STM32_TZC_BASE + 0x008)
|
||||
#define TZC_REGION_ATTRIBUTE0 (STM32_TZC_BASE + 0x110)
|
||||
#define TZC_REGION_ID_ACCESS0 (STM32_TZC_BASE + 0x114)
|
||||
|
||||
#define TAMP_CR1 (STM32_TAMP_BASE + 0x00)
|
||||
|
||||
#define PWR_CR1 (STM32_PWR_BASE + 0x00)
|
||||
#define PWR_CR1_DBP BIT(8)
|
||||
|
||||
/* DBGMCU register */
|
||||
#define DBGMCU_IDC (STM32_DBGMCU_BASE + 0x00)
|
||||
#define DBGMCU_APB4FZ1 (STM32_DBGMCU_BASE + 0x2C)
|
||||
#define DBGMCU_APB4FZ1_IWDG2 BIT(2)
|
||||
#define DBGMCU_IDC_DEV_ID_MASK GENMASK(11, 0)
|
||||
#define DBGMCU_IDC_DEV_ID_SHIFT 0
|
||||
#define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16)
|
||||
#define DBGMCU_IDC_REV_ID_SHIFT 16
|
||||
|
||||
/* GPIOZ registers */
|
||||
#define GPIOZ_SECCFGR 0x54004030
|
||||
|
||||
/* boot interface from Bootrom
|
||||
* - boot instance = bit 31:16
|
||||
* - boot device = bit 15:0
|
||||
*/
|
||||
#define BOOTROM_PARAM_ADDR 0x2FFC0078
|
||||
#define BOOTROM_MODE_MASK GENMASK(15, 0)
|
||||
#define BOOTROM_MODE_SHIFT 0
|
||||
#define BOOTROM_INSTANCE_MASK GENMASK(31, 16)
|
||||
#define BOOTROM_INSTANCE_SHIFT 16
|
||||
|
||||
/* BSEC OTP index */
|
||||
#define BSEC_OTP_RPN 1
|
||||
#define BSEC_OTP_SERIAL 13
|
||||
#define BSEC_OTP_PKG 16
|
||||
#define BSEC_OTP_MAC 57
|
||||
|
||||
/* Device Part Number (RPN) = OTP_DATA1 lower 8 bits */
|
||||
#define RPN_SHIFT 0
|
||||
#define RPN_MASK GENMASK(7, 0)
|
||||
|
||||
/* Package = bit 27:29 of OTP16
|
||||
* - 100: LBGA448 (FFI) => AA = LFBGA 18x18mm 448 balls p. 0.8mm
|
||||
* - 011: LBGA354 (LCI) => AB = LFBGA 16x16mm 359 balls p. 0.8mm
|
||||
* - 010: TFBGA361 (FFC) => AC = TFBGA 12x12mm 361 balls p. 0.5mm
|
||||
* - 001: TFBGA257 (LCC) => AD = TFBGA 10x10mm 257 balls p. 0.5mm
|
||||
* - others: Reserved
|
||||
*/
|
||||
#define PKG_SHIFT 27
|
||||
#define PKG_MASK GENMASK(2, 0)
|
||||
|
||||
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
static void security_init(void)
|
||||
{
|
||||
/* Disable the backup domain write protection */
|
||||
/* the protection is enable at each reset by hardware */
|
||||
/* And must be disable by software */
|
||||
setbits_le32(PWR_CR1, PWR_CR1_DBP);
|
||||
|
||||
while (!(readl(PWR_CR1) & PWR_CR1_DBP))
|
||||
;
|
||||
|
||||
/* If RTC clock isn't enable so this is a cold boot then we need
|
||||
* to reset the backup domain
|
||||
*/
|
||||
if (!(readl(RCC_BDCR) & RCC_BDCR_RTCSRC)) {
|
||||
setbits_le32(RCC_BDCR, RCC_BDCR_VSWRST);
|
||||
while (!(readl(RCC_BDCR) & RCC_BDCR_VSWRST))
|
||||
;
|
||||
clrbits_le32(RCC_BDCR, RCC_BDCR_VSWRST);
|
||||
}
|
||||
|
||||
/* allow non secure access in Write/Read for all peripheral */
|
||||
writel(GENMASK(25, 0), ETZPC_DECPROT0);
|
||||
|
||||
/* Open SYSRAM for no secure access */
|
||||
writel(0x0, ETZPC_TZMA1_SIZE);
|
||||
|
||||
/* enable TZC1 TZC2 clock */
|
||||
writel(BIT(11) | BIT(12), RCC_MP_APB5ENSETR);
|
||||
|
||||
/* Region 0 set to no access by default */
|
||||
/* bit 0 / 16 => nsaid0 read/write Enable
|
||||
* bit 1 / 17 => nsaid1 read/write Enable
|
||||
* ...
|
||||
* bit 15 / 31 => nsaid15 read/write Enable
|
||||
*/
|
||||
writel(0xFFFFFFFF, TZC_REGION_ID_ACCESS0);
|
||||
/* bit 30 / 31 => Secure Global Enable : write/read */
|
||||
/* bit 0 / 1 => Region Enable for filter 0/1 */
|
||||
writel(BIT(0) | BIT(1) | BIT(30) | BIT(31), TZC_REGION_ATTRIBUTE0);
|
||||
|
||||
/* Enable Filter 0 and 1 */
|
||||
setbits_le32(TZC_GATE_KEEPER, BIT(0) | BIT(1));
|
||||
|
||||
/* RCC trust zone deactivated */
|
||||
writel(0x0, RCC_TZCR);
|
||||
|
||||
/* TAMP: deactivate the internal tamper
|
||||
* Bit 23 ITAMP8E: monotonic counter overflow
|
||||
* Bit 20 ITAMP5E: RTC calendar overflow
|
||||
* Bit 19 ITAMP4E: HSE monitoring
|
||||
* Bit 18 ITAMP3E: LSE monitoring
|
||||
* Bit 16 ITAMP1E: RTC power domain supply monitoring
|
||||
*/
|
||||
writel(0x0, TAMP_CR1);
|
||||
|
||||
/* GPIOZ: deactivate the security */
|
||||
writel(BIT(0), RCC_MP_AHB5ENSETR);
|
||||
writel(0x0, GPIOZ_SECCFGR);
|
||||
}
|
||||
#endif /* CONFIG_STM32MP1_TRUSTED */
|
||||
|
||||
/*
|
||||
* Debug init
|
||||
*/
|
||||
static void dbgmcu_init(void)
|
||||
{
|
||||
setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
|
||||
|
||||
/* Freeze IWDG2 if Cortex-A7 is in debug mode */
|
||||
setbits_le32(DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2);
|
||||
}
|
||||
#endif /* !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) */
|
||||
|
||||
#if !defined(CONFIG_STM32MP1_TRUSTED) && \
|
||||
(!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD))
|
||||
/* get bootmode from ROM code boot context: saved in TAMP register */
|
||||
static void update_bootmode(void)
|
||||
{
|
||||
u32 boot_mode;
|
||||
u32 bootrom_itf = readl(BOOTROM_PARAM_ADDR);
|
||||
u32 bootrom_device, bootrom_instance;
|
||||
|
||||
/* enable TAMP clock = RTCAPBEN */
|
||||
writel(BIT(8), RCC_MP_APB5ENSETR);
|
||||
|
||||
/* read bootrom context */
|
||||
bootrom_device =
|
||||
(bootrom_itf & BOOTROM_MODE_MASK) >> BOOTROM_MODE_SHIFT;
|
||||
bootrom_instance =
|
||||
(bootrom_itf & BOOTROM_INSTANCE_MASK) >> BOOTROM_INSTANCE_SHIFT;
|
||||
boot_mode =
|
||||
((bootrom_device << BOOT_TYPE_SHIFT) & BOOT_TYPE_MASK) |
|
||||
((bootrom_instance << BOOT_INSTANCE_SHIFT) &
|
||||
BOOT_INSTANCE_MASK);
|
||||
|
||||
/* save the boot mode in TAMP backup register */
|
||||
clrsetbits_le32(TAMP_BOOT_CONTEXT,
|
||||
TAMP_BOOT_MODE_MASK,
|
||||
boot_mode << TAMP_BOOT_MODE_SHIFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 get_bootmode(void)
|
||||
{
|
||||
/* read bootmode from TAMP backup register */
|
||||
return (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >>
|
||||
TAMP_BOOT_MODE_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Early system init
|
||||
*/
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
u32 boot_mode;
|
||||
|
||||
/* early armv7 timer init: needed for polling */
|
||||
timer_init();
|
||||
|
||||
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
|
||||
dbgmcu_init();
|
||||
#ifndef CONFIG_STM32MP1_TRUSTED
|
||||
security_init();
|
||||
update_bootmode();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
boot_mode = get_bootmode();
|
||||
|
||||
if ((boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART)
|
||||
gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
|
||||
#if defined(CONFIG_DEBUG_UART) && \
|
||||
!defined(CONFIG_STM32MP1_TRUSTED) && \
|
||||
(!defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD))
|
||||
else
|
||||
debug_uart_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Enable D-cache. I-cache is already enabled in start.S */
|
||||
dcache_enable();
|
||||
}
|
||||
|
||||
static u32 read_idc(void)
|
||||
{
|
||||
setbits_le32(RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
|
||||
|
||||
return readl(DBGMCU_IDC);
|
||||
}
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
return (read_idc() & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
|
||||
}
|
||||
|
||||
static u32 get_otp(int index, int shift, int mask)
|
||||
{
|
||||
int ret;
|
||||
struct udevice *dev;
|
||||
u32 otp = 0;
|
||||
|
||||
ret = uclass_get_device_by_driver(UCLASS_MISC,
|
||||
DM_GET_DRIVER(stm32mp_bsec),
|
||||
&dev);
|
||||
|
||||
if (!ret)
|
||||
ret = misc_read(dev, STM32_BSEC_SHADOW(index),
|
||||
&otp, sizeof(otp));
|
||||
|
||||
return (otp >> shift) & mask;
|
||||
}
|
||||
|
||||
/* Get Device Part Number (RPN) from OTP */
|
||||
static u32 get_cpu_rpn(void)
|
||||
{
|
||||
return get_otp(BSEC_OTP_RPN, RPN_SHIFT, RPN_MASK);
|
||||
}
|
||||
|
||||
u32 get_cpu_type(void)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
id = (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
|
||||
|
||||
return (id << 16) | get_cpu_rpn();
|
||||
}
|
||||
|
||||
/* Get Package options from OTP */
|
||||
u32 get_cpu_package(void)
|
||||
{
|
||||
return get_otp(BSEC_OTP_PKG, PKG_SHIFT, PKG_MASK);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DISPLAY_CPUINFO)
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
char *cpu_s, *cpu_r, *pkg;
|
||||
|
||||
/* MPUs Part Numbers */
|
||||
switch (get_cpu_type()) {
|
||||
case CPU_STM32MP157Cxx:
|
||||
cpu_s = "157C";
|
||||
break;
|
||||
case CPU_STM32MP157Axx:
|
||||
cpu_s = "157A";
|
||||
break;
|
||||
case CPU_STM32MP153Cxx:
|
||||
cpu_s = "153C";
|
||||
break;
|
||||
case CPU_STM32MP153Axx:
|
||||
cpu_s = "153A";
|
||||
break;
|
||||
case CPU_STM32MP151Cxx:
|
||||
cpu_s = "151C";
|
||||
break;
|
||||
case CPU_STM32MP151Axx:
|
||||
cpu_s = "151A";
|
||||
break;
|
||||
default:
|
||||
cpu_s = "????";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Package */
|
||||
switch (get_cpu_package()) {
|
||||
case PKG_AA_LBGA448:
|
||||
pkg = "AA";
|
||||
break;
|
||||
case PKG_AB_LBGA354:
|
||||
pkg = "AB";
|
||||
break;
|
||||
case PKG_AC_TFBGA361:
|
||||
pkg = "AC";
|
||||
break;
|
||||
case PKG_AD_TFBGA257:
|
||||
pkg = "AD";
|
||||
break;
|
||||
default:
|
||||
pkg = "??";
|
||||
break;
|
||||
}
|
||||
|
||||
/* REVISION */
|
||||
switch (get_cpu_rev()) {
|
||||
case CPU_REVA:
|
||||
cpu_r = "A";
|
||||
break;
|
||||
case CPU_REVB:
|
||||
cpu_r = "B";
|
||||
break;
|
||||
default:
|
||||
cpu_r = "?";
|
||||
break;
|
||||
}
|
||||
|
||||
printf("CPU: STM32MP%s%s Rev.%s\n", cpu_s, pkg, cpu_r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DISPLAY_CPUINFO */
|
||||
|
||||
static void setup_boot_mode(void)
|
||||
{
|
||||
const u32 serial_addr[] = {
|
||||
STM32_USART1_BASE,
|
||||
STM32_USART2_BASE,
|
||||
STM32_USART3_BASE,
|
||||
STM32_UART4_BASE,
|
||||
STM32_UART5_BASE,
|
||||
STM32_USART6_BASE,
|
||||
STM32_UART7_BASE,
|
||||
STM32_UART8_BASE
|
||||
};
|
||||
char cmd[60];
|
||||
u32 boot_ctx = readl(TAMP_BOOT_CONTEXT);
|
||||
u32 boot_mode =
|
||||
(boot_ctx & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT;
|
||||
unsigned int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1;
|
||||
u32 forced_mode = (boot_ctx & TAMP_BOOT_FORCED_MASK);
|
||||
struct udevice *dev;
|
||||
int alias;
|
||||
|
||||
pr_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d forced=%x\n",
|
||||
__func__, boot_ctx, boot_mode, instance, forced_mode);
|
||||
switch (boot_mode & TAMP_BOOT_DEVICE_MASK) {
|
||||
case BOOT_SERIAL_UART:
|
||||
if (instance > ARRAY_SIZE(serial_addr))
|
||||
break;
|
||||
/* serial : search associated alias in devicetree */
|
||||
sprintf(cmd, "serial@%x", serial_addr[instance]);
|
||||
if (uclass_get_device_by_name(UCLASS_SERIAL, cmd, &dev))
|
||||
break;
|
||||
if (fdtdec_get_alias_seq(gd->fdt_blob, "serial",
|
||||
dev_of_offset(dev), &alias))
|
||||
break;
|
||||
sprintf(cmd, "%d", alias);
|
||||
env_set("boot_device", "serial");
|
||||
env_set("boot_instance", cmd);
|
||||
|
||||
/* restore console on uart when not used */
|
||||
if (gd->cur_serial_dev != dev) {
|
||||
gd->flags &= ~(GD_FLG_SILENT |
|
||||
GD_FLG_DISABLE_CONSOLE);
|
||||
printf("serial boot with console enabled!\n");
|
||||
}
|
||||
break;
|
||||
case BOOT_SERIAL_USB:
|
||||
env_set("boot_device", "usb");
|
||||
env_set("boot_instance", "0");
|
||||
break;
|
||||
case BOOT_FLASH_SD:
|
||||
case BOOT_FLASH_EMMC:
|
||||
sprintf(cmd, "%d", instance);
|
||||
env_set("boot_device", "mmc");
|
||||
env_set("boot_instance", cmd);
|
||||
break;
|
||||
case BOOT_FLASH_NAND:
|
||||
env_set("boot_device", "nand");
|
||||
env_set("boot_instance", "0");
|
||||
break;
|
||||
case BOOT_FLASH_NOR:
|
||||
env_set("boot_device", "nor");
|
||||
env_set("boot_instance", "0");
|
||||
break;
|
||||
default:
|
||||
pr_debug("unexpected boot mode = %x\n", boot_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (forced_mode) {
|
||||
case BOOT_FASTBOOT:
|
||||
printf("Enter fastboot!\n");
|
||||
env_set("preboot", "env set preboot; fastboot 0");
|
||||
break;
|
||||
case BOOT_STM32PROG:
|
||||
env_set("boot_device", "usb");
|
||||
env_set("boot_instance", "0");
|
||||
break;
|
||||
case BOOT_UMS_MMC0:
|
||||
case BOOT_UMS_MMC1:
|
||||
case BOOT_UMS_MMC2:
|
||||
printf("Enter UMS!\n");
|
||||
instance = forced_mode - BOOT_UMS_MMC0;
|
||||
sprintf(cmd, "env set preboot; ums 0 mmc %d", instance);
|
||||
env_set("preboot", cmd);
|
||||
break;
|
||||
case BOOT_RECOVERY:
|
||||
env_set("preboot", "env set preboot; run altbootcmd");
|
||||
break;
|
||||
case BOOT_NORMAL:
|
||||
break;
|
||||
default:
|
||||
pr_debug("unexpected forced boot mode = %x\n", forced_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear TAMP for next reboot */
|
||||
clrsetbits_le32(TAMP_BOOT_CONTEXT, TAMP_BOOT_FORCED_MASK, BOOT_NORMAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no MAC address in the environment, then it will be initialized
|
||||
* (silently) from the value in the OTP.
|
||||
*/
|
||||
static int setup_mac_address(void)
|
||||
{
|
||||
#if defined(CONFIG_NET)
|
||||
int ret;
|
||||
int i;
|
||||
u32 otp[2];
|
||||
uchar enetaddr[6];
|
||||
struct udevice *dev;
|
||||
|
||||
/* MAC already in environment */
|
||||
if (eth_env_get_enetaddr("ethaddr", enetaddr))
|
||||
return 0;
|
||||
|
||||
ret = uclass_get_device_by_driver(UCLASS_MISC,
|
||||
DM_GET_DRIVER(stm32mp_bsec),
|
||||
&dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_MAC),
|
||||
otp, sizeof(otp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
enetaddr[i] = ((uint8_t *)&otp)[i];
|
||||
|
||||
if (!is_valid_ethaddr(enetaddr)) {
|
||||
pr_err("invalid MAC address in OTP %pM\n", enetaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_debug("OTP MAC address = %pM\n", enetaddr);
|
||||
ret = !eth_env_set_enetaddr("ethaddr", enetaddr);
|
||||
if (!ret)
|
||||
pr_err("Failed to set mac address %pM from OTP: %d\n",
|
||||
enetaddr, ret);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_serial_number(void)
|
||||
{
|
||||
char serial_string[25];
|
||||
u32 otp[3] = {0, 0, 0 };
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
if (env_get("serial#"))
|
||||
return 0;
|
||||
|
||||
ret = uclass_get_device_by_driver(UCLASS_MISC,
|
||||
DM_GET_DRIVER(stm32mp_bsec),
|
||||
&dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = misc_read(dev, STM32_BSEC_SHADOW(BSEC_OTP_SERIAL),
|
||||
otp, sizeof(otp));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
sprintf(serial_string, "%08X%08X%08X", otp[0], otp[1], otp[2]);
|
||||
env_set("serial#", serial_string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
setup_boot_mode();
|
||||
setup_mac_address();
|
||||
setup_serial_number();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <ram.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
struct ram_info ram;
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
|
||||
if (ret) {
|
||||
debug("RAM init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = ram_get_info(dev, &ram);
|
||||
if (ret) {
|
||||
debug("Cannot get RAM size: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
debug("RAM init base=%lx, size=%x\n", ram.base, ram.size);
|
||||
|
||||
gd->ram_size = ram.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdt_support.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <dt-bindings/pinctrl/stm32-pinfunc.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define ETZPC_DECPROT(n) (STM32_ETZPC_BASE + 0x10 + 4 * (n))
|
||||
#define ETZPC_DECPROT_NB 6
|
||||
|
||||
#define DECPROT_MASK 0x03
|
||||
#define NB_PROT_PER_REG 0x10
|
||||
#define DECPROT_NB_BITS 2
|
||||
|
||||
#define DECPROT_SECURED 0x00
|
||||
#define DECPROT_WRITE_SECURE 0x01
|
||||
#define DECPROT_MCU_ISOLATION 0x02
|
||||
#define DECPROT_NON_SECURED 0x03
|
||||
|
||||
#define ETZPC_RESERVED 0xffffffff
|
||||
|
||||
static const u32 stm32mp1_ip_addr[] = {
|
||||
0x5c008000, /* 00 stgenc */
|
||||
0x54000000, /* 01 bkpsram */
|
||||
0x5c003000, /* 02 iwdg1 */
|
||||
0x5c000000, /* 03 usart1 */
|
||||
0x5c001000, /* 04 spi6 */
|
||||
0x5c002000, /* 05 i2c4 */
|
||||
ETZPC_RESERVED, /* 06 reserved */
|
||||
0x54003000, /* 07 rng1 */
|
||||
0x54002000, /* 08 hash1 */
|
||||
0x54001000, /* 09 cryp1 */
|
||||
0x5a003000, /* 0A ddrctrl */
|
||||
0x5a004000, /* 0B ddrphyc */
|
||||
0x5c009000, /* 0C i2c6 */
|
||||
ETZPC_RESERVED, /* 0D reserved */
|
||||
ETZPC_RESERVED, /* 0E reserved */
|
||||
ETZPC_RESERVED, /* 0F reserved */
|
||||
0x40000000, /* 10 tim2 */
|
||||
0x40001000, /* 11 tim3 */
|
||||
0x40002000, /* 12 tim4 */
|
||||
0x40003000, /* 13 tim5 */
|
||||
0x40004000, /* 14 tim6 */
|
||||
0x40005000, /* 15 tim7 */
|
||||
0x40006000, /* 16 tim12 */
|
||||
0x40007000, /* 17 tim13 */
|
||||
0x40008000, /* 18 tim14 */
|
||||
0x40009000, /* 19 lptim1 */
|
||||
0x4000a000, /* 1A wwdg1 */
|
||||
0x4000b000, /* 1B spi2 */
|
||||
0x4000c000, /* 1C spi3 */
|
||||
0x4000d000, /* 1D spdifrx */
|
||||
0x4000e000, /* 1E usart2 */
|
||||
0x4000f000, /* 1F usart3 */
|
||||
0x40010000, /* 20 uart4 */
|
||||
0x40011000, /* 21 uart5 */
|
||||
0x40012000, /* 22 i2c1 */
|
||||
0x40013000, /* 23 i2c2 */
|
||||
0x40014000, /* 24 i2c3 */
|
||||
0x40015000, /* 25 i2c5 */
|
||||
0x40016000, /* 26 cec */
|
||||
0x40017000, /* 27 dac */
|
||||
0x40018000, /* 28 uart7 */
|
||||
0x40019000, /* 29 uart8 */
|
||||
ETZPC_RESERVED, /* 2A reserved */
|
||||
ETZPC_RESERVED, /* 2B reserved */
|
||||
0x4001c000, /* 2C mdios */
|
||||
ETZPC_RESERVED, /* 2D reserved */
|
||||
ETZPC_RESERVED, /* 2E reserved */
|
||||
ETZPC_RESERVED, /* 2F reserved */
|
||||
0x44000000, /* 30 tim1 */
|
||||
0x44001000, /* 31 tim8 */
|
||||
ETZPC_RESERVED, /* 32 reserved */
|
||||
0x44003000, /* 33 usart6 */
|
||||
0x44004000, /* 34 spi1 */
|
||||
0x44005000, /* 35 spi4 */
|
||||
0x44006000, /* 36 tim15 */
|
||||
0x44007000, /* 37 tim16 */
|
||||
0x44008000, /* 38 tim17 */
|
||||
0x44009000, /* 39 spi5 */
|
||||
0x4400a000, /* 3A sai1 */
|
||||
0x4400b000, /* 3B sai2 */
|
||||
0x4400c000, /* 3C sai3 */
|
||||
0x4400d000, /* 3D dfsdm */
|
||||
0x4400e000, /* 3E tt_fdcan */
|
||||
ETZPC_RESERVED, /* 3F reserved */
|
||||
0x50021000, /* 40 lptim2 */
|
||||
0x50022000, /* 41 lptim3 */
|
||||
0x50023000, /* 42 lptim4 */
|
||||
0x50024000, /* 43 lptim5 */
|
||||
0x50027000, /* 44 sai4 */
|
||||
0x50025000, /* 45 vrefbuf */
|
||||
0x4c006000, /* 46 dcmi */
|
||||
0x4c004000, /* 47 crc2 */
|
||||
0x48003000, /* 48 adc */
|
||||
0x4c002000, /* 49 hash2 */
|
||||
0x4c003000, /* 4A rng2 */
|
||||
0x4c005000, /* 4B cryp2 */
|
||||
ETZPC_RESERVED, /* 4C reserved */
|
||||
ETZPC_RESERVED, /* 4D reserved */
|
||||
ETZPC_RESERVED, /* 4E reserved */
|
||||
ETZPC_RESERVED, /* 4F reserved */
|
||||
ETZPC_RESERVED, /* 50 sram1 */
|
||||
ETZPC_RESERVED, /* 51 sram2 */
|
||||
ETZPC_RESERVED, /* 52 sram3 */
|
||||
ETZPC_RESERVED, /* 53 sram4 */
|
||||
ETZPC_RESERVED, /* 54 retram */
|
||||
0x49000000, /* 55 otg */
|
||||
0x48004000, /* 56 sdmmc3 */
|
||||
0x48005000, /* 57 dlybsd3 */
|
||||
0x48000000, /* 58 dma1 */
|
||||
0x48001000, /* 59 dma2 */
|
||||
0x48002000, /* 5A dmamux */
|
||||
0x58002000, /* 5B fmc */
|
||||
0x58003000, /* 5C qspi */
|
||||
0x58004000, /* 5D dlybq */
|
||||
0x5800a000, /* 5E eth */
|
||||
ETZPC_RESERVED, /* 5F reserved */
|
||||
};
|
||||
|
||||
/* fdt helper */
|
||||
static bool fdt_disable_subnode_by_address(void *fdt, int offset, u32 addr)
|
||||
{
|
||||
int node;
|
||||
|
||||
for (node = fdt_first_subnode(fdt, offset);
|
||||
node >= 0;
|
||||
node = fdt_next_subnode(fdt, node)) {
|
||||
if (addr == (u32)fdt_getprop(fdt, node, "reg", 0)) {
|
||||
if (fdtdec_get_is_enabled(fdt, node)) {
|
||||
fdt_status_disabled(fdt, node);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int stm32_fdt_fixup_etzpc(void *fdt)
|
||||
{
|
||||
const u32 *array;
|
||||
int array_size, i;
|
||||
int soc_node, offset, shift;
|
||||
u32 addr, status, decprot[ETZPC_DECPROT_NB];
|
||||
|
||||
array = stm32mp1_ip_addr;
|
||||
array_size = ARRAY_SIZE(stm32mp1_ip_addr);
|
||||
|
||||
for (i = 0; i < ETZPC_DECPROT_NB; i++)
|
||||
decprot[i] = readl(ETZPC_DECPROT(i));
|
||||
|
||||
soc_node = fdt_path_offset(fdt, "/soc");
|
||||
if (soc_node < 0)
|
||||
return soc_node;
|
||||
|
||||
for (i = 0; i < array_size; i++) {
|
||||
offset = i / NB_PROT_PER_REG;
|
||||
shift = (i % NB_PROT_PER_REG) * DECPROT_NB_BITS;
|
||||
status = (decprot[offset] >> shift) & DECPROT_MASK;
|
||||
addr = array[i];
|
||||
|
||||
debug("ETZPC: 0x%08x decprot %d=%d\n", addr, i, status);
|
||||
|
||||
if (addr == ETZPC_RESERVED ||
|
||||
status == DECPROT_NON_SECURED)
|
||||
continue;
|
||||
|
||||
if (fdt_disable_subnode_by_address(fdt, soc_node, addr))
|
||||
printf("ETZPC: 0x%08x node disabled, decprot %d=%d\n",
|
||||
addr, i, status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called right before the kernel is booted. "blob" is the
|
||||
* device tree that will be passed to the kernel.
|
||||
*/
|
||||
int ft_system_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 pkg;
|
||||
|
||||
if (CONFIG_IS_ENABLED(STM32_ETZPC)) {
|
||||
ret = stm32_fdt_fixup_etzpc(blob);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (get_cpu_package()) {
|
||||
case PKG_AA_LBGA448:
|
||||
pkg = STM32MP_PKG_AA;
|
||||
break;
|
||||
case PKG_AB_LBGA354:
|
||||
pkg = STM32MP_PKG_AB;
|
||||
break;
|
||||
case PKG_AC_TFBGA361:
|
||||
pkg = STM32MP_PKG_AC;
|
||||
break;
|
||||
case PKG_AD_TFBGA257:
|
||||
pkg = STM32MP_PKG_AD;
|
||||
break;
|
||||
default:
|
||||
pkg = 0;
|
||||
break;
|
||||
}
|
||||
if (pkg) {
|
||||
do_fixup_by_compat_u32(blob, "st,stm32mp157-pinctrl",
|
||||
"st,package", pkg, false);
|
||||
do_fixup_by_compat_u32(blob, "st,stm32mp157-z-pinctrl",
|
||||
"st,package", pkg, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#ifndef __MACH_STM32MP_DDR_H_
|
||||
#define __MACH_STM32MP_DDR_H_
|
||||
|
||||
/* DDR power initializations */
|
||||
enum ddr_type {
|
||||
STM32MP_DDR3,
|
||||
STM32MP_LPDDR2,
|
||||
STM32MP_LPDDR3,
|
||||
};
|
||||
|
||||
int board_ddr_power_init(enum ddr_type ddr_type);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2016
|
||||
* Vikas Manocha, <vikas.manocha@st.com>
|
||||
*/
|
||||
|
||||
#ifndef _STM32_GPIO_H_
|
||||
#define _STM32_GPIO_H_
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define STM32_GPIOS_PER_BANK 16
|
||||
|
||||
enum stm32_gpio_port {
|
||||
STM32_GPIO_PORT_A = 0,
|
||||
STM32_GPIO_PORT_B,
|
||||
STM32_GPIO_PORT_C,
|
||||
STM32_GPIO_PORT_D,
|
||||
STM32_GPIO_PORT_E,
|
||||
STM32_GPIO_PORT_F,
|
||||
STM32_GPIO_PORT_G,
|
||||
STM32_GPIO_PORT_H,
|
||||
STM32_GPIO_PORT_I
|
||||
};
|
||||
|
||||
enum stm32_gpio_pin {
|
||||
STM32_GPIO_PIN_0 = 0,
|
||||
STM32_GPIO_PIN_1,
|
||||
STM32_GPIO_PIN_2,
|
||||
STM32_GPIO_PIN_3,
|
||||
STM32_GPIO_PIN_4,
|
||||
STM32_GPIO_PIN_5,
|
||||
STM32_GPIO_PIN_6,
|
||||
STM32_GPIO_PIN_7,
|
||||
STM32_GPIO_PIN_8,
|
||||
STM32_GPIO_PIN_9,
|
||||
STM32_GPIO_PIN_10,
|
||||
STM32_GPIO_PIN_11,
|
||||
STM32_GPIO_PIN_12,
|
||||
STM32_GPIO_PIN_13,
|
||||
STM32_GPIO_PIN_14,
|
||||
STM32_GPIO_PIN_15
|
||||
};
|
||||
|
||||
enum stm32_gpio_mode {
|
||||
STM32_GPIO_MODE_IN = 0,
|
||||
STM32_GPIO_MODE_OUT,
|
||||
STM32_GPIO_MODE_AF,
|
||||
STM32_GPIO_MODE_AN
|
||||
};
|
||||
|
||||
enum stm32_gpio_otype {
|
||||
STM32_GPIO_OTYPE_PP = 0,
|
||||
STM32_GPIO_OTYPE_OD
|
||||
};
|
||||
|
||||
enum stm32_gpio_speed {
|
||||
STM32_GPIO_SPEED_2M = 0,
|
||||
STM32_GPIO_SPEED_25M,
|
||||
STM32_GPIO_SPEED_50M,
|
||||
STM32_GPIO_SPEED_100M
|
||||
};
|
||||
|
||||
enum stm32_gpio_pupd {
|
||||
STM32_GPIO_PUPD_NO = 0,
|
||||
STM32_GPIO_PUPD_UP,
|
||||
STM32_GPIO_PUPD_DOWN
|
||||
};
|
||||
|
||||
enum stm32_gpio_af {
|
||||
STM32_GPIO_AF0 = 0,
|
||||
STM32_GPIO_AF1,
|
||||
STM32_GPIO_AF2,
|
||||
STM32_GPIO_AF3,
|
||||
STM32_GPIO_AF4,
|
||||
STM32_GPIO_AF5,
|
||||
STM32_GPIO_AF6,
|
||||
STM32_GPIO_AF7,
|
||||
STM32_GPIO_AF8,
|
||||
STM32_GPIO_AF9,
|
||||
STM32_GPIO_AF10,
|
||||
STM32_GPIO_AF11,
|
||||
STM32_GPIO_AF12,
|
||||
STM32_GPIO_AF13,
|
||||
STM32_GPIO_AF14,
|
||||
STM32_GPIO_AF15
|
||||
};
|
||||
|
||||
struct stm32_gpio_dsc {
|
||||
enum stm32_gpio_port port;
|
||||
enum stm32_gpio_pin pin;
|
||||
};
|
||||
|
||||
struct stm32_gpio_ctl {
|
||||
enum stm32_gpio_mode mode;
|
||||
enum stm32_gpio_otype otype;
|
||||
enum stm32_gpio_speed speed;
|
||||
enum stm32_gpio_pupd pupd;
|
||||
enum stm32_gpio_af af;
|
||||
};
|
||||
|
||||
struct stm32_gpio_regs {
|
||||
u32 moder; /* GPIO port mode */
|
||||
u32 otyper; /* GPIO port output type */
|
||||
u32 ospeedr; /* GPIO port output speed */
|
||||
u32 pupdr; /* GPIO port pull-up/pull-down */
|
||||
u32 idr; /* GPIO port input data */
|
||||
u32 odr; /* GPIO port output data */
|
||||
u32 bsrr; /* GPIO port bit set/reset */
|
||||
u32 lckr; /* GPIO port configuration lock */
|
||||
u32 afr[2]; /* GPIO alternate function */
|
||||
};
|
||||
|
||||
struct stm32_gpio_priv {
|
||||
struct stm32_gpio_regs *regs;
|
||||
unsigned int gpio_range;
|
||||
};
|
||||
|
||||
int stm32_offset_to_index(struct udevice *dev, unsigned int offset);
|
||||
|
||||
#endif /* _STM32_GPIO_H_ */
|
||||
@@ -0,0 +1,118 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#ifndef _MACH_STM32_H_
|
||||
#define _MACH_STM32_H_
|
||||
|
||||
/*
|
||||
* Peripheral memory map
|
||||
* only address used before device tree parsing
|
||||
*/
|
||||
#define STM32_RCC_BASE 0x50000000
|
||||
#define STM32_PWR_BASE 0x50001000
|
||||
#define STM32_DBGMCU_BASE 0x50081000
|
||||
#define STM32_TZC_BASE 0x5C006000
|
||||
#define STM32_ETZPC_BASE 0x5C007000
|
||||
#define STM32_STGEN_BASE 0x5C008000
|
||||
#define STM32_TAMP_BASE 0x5C00A000
|
||||
|
||||
#define STM32_USART1_BASE 0x5C000000
|
||||
#define STM32_USART2_BASE 0x4000E000
|
||||
#define STM32_USART3_BASE 0x4000F000
|
||||
#define STM32_UART4_BASE 0x40010000
|
||||
#define STM32_UART5_BASE 0x40011000
|
||||
#define STM32_USART6_BASE 0x44003000
|
||||
#define STM32_UART7_BASE 0x40018000
|
||||
#define STM32_UART8_BASE 0x40019000
|
||||
|
||||
#define STM32_SYSRAM_BASE 0x2FFC0000
|
||||
#define STM32_SYSRAM_SIZE SZ_256K
|
||||
|
||||
#define STM32_DDR_BASE 0xC0000000
|
||||
#define STM32_DDR_SIZE SZ_1G
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* enumerated used to identify the SYSCON driver instance */
|
||||
enum {
|
||||
STM32MP_SYSCON_UNKNOWN,
|
||||
STM32MP_SYSCON_PWR,
|
||||
STM32MP_SYSCON_SYSCFG,
|
||||
};
|
||||
|
||||
/*
|
||||
* enumerated for boot interface from Bootrom, used in TAMP_BOOT_CONTEXT
|
||||
* - boot device = bit 8:4
|
||||
* - boot instance = bit 3:0
|
||||
*/
|
||||
#define BOOT_TYPE_MASK 0xF0
|
||||
#define BOOT_TYPE_SHIFT 4
|
||||
#define BOOT_INSTANCE_MASK 0x0F
|
||||
#define BOOT_INSTANCE_SHIFT 0
|
||||
|
||||
enum boot_device {
|
||||
BOOT_FLASH_SD = 0x10,
|
||||
BOOT_FLASH_SD_1 = 0x11,
|
||||
BOOT_FLASH_SD_2 = 0x12,
|
||||
BOOT_FLASH_SD_3 = 0x13,
|
||||
|
||||
BOOT_FLASH_EMMC = 0x20,
|
||||
BOOT_FLASH_EMMC_1 = 0x21,
|
||||
BOOT_FLASH_EMMC_2 = 0x22,
|
||||
BOOT_FLASH_EMMC_3 = 0x23,
|
||||
|
||||
BOOT_FLASH_NAND = 0x30,
|
||||
BOOT_FLASH_NAND_FMC = 0x31,
|
||||
|
||||
BOOT_FLASH_NOR = 0x40,
|
||||
BOOT_FLASH_NOR_QSPI = 0x41,
|
||||
|
||||
BOOT_SERIAL_UART = 0x50,
|
||||
BOOT_SERIAL_UART_1 = 0x51,
|
||||
BOOT_SERIAL_UART_2 = 0x52,
|
||||
BOOT_SERIAL_UART_3 = 0x53,
|
||||
BOOT_SERIAL_UART_4 = 0x54,
|
||||
BOOT_SERIAL_UART_5 = 0x55,
|
||||
BOOT_SERIAL_UART_6 = 0x56,
|
||||
BOOT_SERIAL_UART_7 = 0x57,
|
||||
BOOT_SERIAL_UART_8 = 0x58,
|
||||
|
||||
BOOT_SERIAL_USB = 0x60,
|
||||
BOOT_SERIAL_USB_OTG = 0x62,
|
||||
};
|
||||
|
||||
/* TAMP registers */
|
||||
#define TAMP_BACKUP_REGISTER(x) (STM32_TAMP_BASE + 0x100 + 4 * x)
|
||||
#define TAMP_BACKUP_MAGIC_NUMBER TAMP_BACKUP_REGISTER(4)
|
||||
#define TAMP_BACKUP_BRANCH_ADDRESS TAMP_BACKUP_REGISTER(5)
|
||||
#define TAMP_BOOT_CONTEXT TAMP_BACKUP_REGISTER(20)
|
||||
#define TAMP_BOOTCOUNT TAMP_BACKUP_REGISTER(21)
|
||||
|
||||
#define TAMP_BOOT_MODE_MASK GENMASK(15, 8)
|
||||
#define TAMP_BOOT_MODE_SHIFT 8
|
||||
#define TAMP_BOOT_DEVICE_MASK GENMASK(7, 4)
|
||||
#define TAMP_BOOT_INSTANCE_MASK GENMASK(3, 0)
|
||||
#define TAMP_BOOT_FORCED_MASK GENMASK(7, 0)
|
||||
#define TAMP_BOOT_DEBUG_ON BIT(16)
|
||||
|
||||
enum forced_boot_mode {
|
||||
BOOT_NORMAL = 0x00,
|
||||
BOOT_FASTBOOT = 0x01,
|
||||
BOOT_RECOVERY = 0x02,
|
||||
BOOT_STM32PROG = 0x03,
|
||||
BOOT_UMS_MMC0 = 0x10,
|
||||
BOOT_UMS_MMC1 = 0x11,
|
||||
BOOT_UMS_MMC2 = 0x12,
|
||||
};
|
||||
|
||||
/* offset used for BSEC driver: misc_read and misc_write */
|
||||
#define STM32_BSEC_SHADOW_OFFSET 0x0
|
||||
#define STM32_BSEC_SHADOW(id) (STM32_BSEC_SHADOW_OFFSET + (id) * 4)
|
||||
#define STM32_BSEC_OTP_OFFSET 0x80000000
|
||||
#define STM32_BSEC_OTP(id) (STM32_BSEC_OTP_OFFSET + (id) * 4)
|
||||
|
||||
#define BSEC_OTP_BOARD 59
|
||||
|
||||
#endif /* __ASSEMBLY__*/
|
||||
#endif /* _MACH_STM32_H_ */
|
||||
@@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#ifndef __STM32MP1_SMC_H__
|
||||
#define __STM32MP1_SMC_H__
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
|
||||
/*
|
||||
* SMC function IDs for STM32 Service queries
|
||||
* STM32 SMC services use the space between 0x82000000 and 0x8200FFFF
|
||||
* like this is defined in SMC calling Convention by ARM
|
||||
* for SiP (silicon Partner)
|
||||
* http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
|
||||
*/
|
||||
#define STM32_SMC_VERSION 0x82000000
|
||||
|
||||
/* Secure Service access from Non-secure */
|
||||
#define STM32_SMC_BSEC 0x82001003
|
||||
|
||||
/* Service for BSEC */
|
||||
#define STM32_SMC_READ_SHADOW 0x01
|
||||
#define STM32_SMC_PROG_OTP 0x02
|
||||
#define STM32_SMC_WRITE_SHADOW 0x03
|
||||
#define STM32_SMC_READ_OTP 0x04
|
||||
#define STM32_SMC_READ_ALL 0x05
|
||||
#define STM32_SMC_WRITE_ALL 0x06
|
||||
|
||||
/* SMC error codes */
|
||||
#define STM32_SMC_OK 0x0
|
||||
#define STM32_SMC_NOT_SUPPORTED -1
|
||||
#define STM32_SMC_FAILED -2
|
||||
#define STM32_SMC_INVALID_PARAMS -3
|
||||
|
||||
#define stm32_smc_exec(svc, op, data1, data2) \
|
||||
stm32_smc(svc, op, data1, data2, NULL)
|
||||
|
||||
#ifdef CONFIG_ARM_SMCCC
|
||||
static inline u32 stm32_smc(u32 svc, u8 op, u32 data1, u32 data2, u32 *result)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
arm_smccc_smc(svc, op, data1, data2, 0, 0, 0, 0, &res);
|
||||
|
||||
if (res.a0) {
|
||||
pr_err("%s: Failed to exec in secure mode (err = %ld)\n",
|
||||
__func__, res.a0);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (result)
|
||||
*result = (u32)res.a1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline u32 stm32_smc(u32 svc, u8 op, u32 data1, u32 data2, u32 *result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32MP1_SMC_H__ */
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2015-2017, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
/* ID = Device Version (bit31:16) + Device Part Number (RPN) (bit15:0)*/
|
||||
#define CPU_STM32MP157Cxx 0x05000000
|
||||
#define CPU_STM32MP157Axx 0x05000001
|
||||
#define CPU_STM32MP153Cxx 0x05000024
|
||||
#define CPU_STM32MP153Axx 0x05000025
|
||||
#define CPU_STM32MP151Cxx 0x0500002E
|
||||
#define CPU_STM32MP151Axx 0x0500002F
|
||||
|
||||
/* return CPU_STMP32MP...Xxx constants */
|
||||
u32 get_cpu_type(void);
|
||||
|
||||
#define CPU_REVA 0x1000
|
||||
#define CPU_REVB 0x2000
|
||||
|
||||
/* return CPU_REV constants */
|
||||
u32 get_cpu_rev(void);
|
||||
|
||||
/* Get Package options from OTP */
|
||||
u32 get_cpu_package(void);
|
||||
|
||||
#define PKG_AA_LBGA448 4
|
||||
#define PKG_AB_LBGA354 3
|
||||
#define PKG_AC_TFBGA361 2
|
||||
#define PKG_AD_TFBGA257 1
|
||||
|
||||
/* return boot mode */
|
||||
u32 get_bootmode(void);
|
||||
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/secure.h>
|
||||
|
||||
#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0
|
||||
#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1
|
||||
|
||||
#define MPIDR_AFF0 GENMASK(7, 0)
|
||||
|
||||
#define RCC_MP_GRSTCSETR (STM32_RCC_BASE + 0x0404)
|
||||
#define RCC_MP_GRSTCSETR_MPUP1RST BIT(5)
|
||||
#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4)
|
||||
#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0)
|
||||
|
||||
#define STM32MP1_PSCI_NR_CPUS 2
|
||||
#if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS
|
||||
#error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS"
|
||||
#endif
|
||||
|
||||
u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = {
|
||||
PSCI_AFFINITY_LEVEL_ON,
|
||||
PSCI_AFFINITY_LEVEL_OFF};
|
||||
|
||||
static inline void psci_set_state(int cpu, u8 state)
|
||||
{
|
||||
psci_state[cpu] = state;
|
||||
dsb();
|
||||
isb();
|
||||
}
|
||||
|
||||
static u32 __secure stm32mp_get_gicd_base_address(void)
|
||||
{
|
||||
u32 periphbase;
|
||||
|
||||
/* get the GIC base address from the CBAR register */
|
||||
asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase));
|
||||
|
||||
return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET;
|
||||
}
|
||||
|
||||
static void __secure stm32mp_raise_sgi0(int cpu)
|
||||
{
|
||||
u32 gic_dist_addr;
|
||||
|
||||
gic_dist_addr = stm32mp_get_gicd_base_address();
|
||||
|
||||
/* ask cpu with SGI0 */
|
||||
writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR);
|
||||
}
|
||||
|
||||
void __secure psci_arch_cpu_entry(void)
|
||||
{
|
||||
u32 cpu = psci_get_cpu_id();
|
||||
|
||||
psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
|
||||
|
||||
/* reset magic in TAMP register */
|
||||
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
|
||||
}
|
||||
|
||||
s32 __secure psci_features(u32 function_id, u32 psci_fid)
|
||||
{
|
||||
switch (psci_fid) {
|
||||
case ARM_PSCI_0_2_FN_PSCI_VERSION:
|
||||
case ARM_PSCI_0_2_FN_CPU_OFF:
|
||||
case ARM_PSCI_0_2_FN_CPU_ON:
|
||||
case ARM_PSCI_0_2_FN_AFFINITY_INFO:
|
||||
case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
|
||||
case ARM_PSCI_0_2_FN_SYSTEM_OFF:
|
||||
case ARM_PSCI_0_2_FN_SYSTEM_RESET:
|
||||
return 0x0;
|
||||
}
|
||||
return ARM_PSCI_RET_NI;
|
||||
}
|
||||
|
||||
u32 __secure psci_version(void)
|
||||
{
|
||||
return ARM_PSCI_VER_1_0;
|
||||
}
|
||||
|
||||
s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity,
|
||||
u32 lowest_affinity_level)
|
||||
{
|
||||
u32 cpu = target_affinity & MPIDR_AFF0;
|
||||
|
||||
if (lowest_affinity_level > 0)
|
||||
return ARM_PSCI_RET_INVAL;
|
||||
|
||||
if (target_affinity & ~MPIDR_AFF0)
|
||||
return ARM_PSCI_RET_INVAL;
|
||||
|
||||
if (cpu >= STM32MP1_PSCI_NR_CPUS)
|
||||
return ARM_PSCI_RET_INVAL;
|
||||
|
||||
return psci_state[cpu];
|
||||
}
|
||||
|
||||
u32 __secure psci_migrate_info_type(void)
|
||||
{
|
||||
/*
|
||||
* in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
|
||||
* return 2 = Trusted OS is either not present or does not require
|
||||
* migration, system of this type does not require the caller
|
||||
* to use the MIGRATE function.
|
||||
* MIGRATE function calls return NOT_SUPPORTED.
|
||||
*/
|
||||
return 2;
|
||||
}
|
||||
|
||||
s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
|
||||
u32 context_id)
|
||||
{
|
||||
u32 cpu = target_cpu & MPIDR_AFF0;
|
||||
|
||||
if (target_cpu & ~MPIDR_AFF0)
|
||||
return ARM_PSCI_RET_INVAL;
|
||||
|
||||
if (cpu >= STM32MP1_PSCI_NR_CPUS)
|
||||
return ARM_PSCI_RET_INVAL;
|
||||
|
||||
if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON)
|
||||
return ARM_PSCI_RET_ALREADY_ON;
|
||||
|
||||
/* reset magic in TAMP register */
|
||||
if (readl(TAMP_BACKUP_MAGIC_NUMBER))
|
||||
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
|
||||
/*
|
||||
* ROM code need a first SGI0 after core reset
|
||||
* core is ready when magic is set to 0 in ROM code
|
||||
*/
|
||||
while (readl(TAMP_BACKUP_MAGIC_NUMBER))
|
||||
stm32mp_raise_sgi0(cpu);
|
||||
|
||||
/* store target PC and context id*/
|
||||
psci_save(cpu, pc, context_id);
|
||||
|
||||
/* write entrypoint in backup RAM register */
|
||||
writel((u32)&psci_cpu_entry, TAMP_BACKUP_BRANCH_ADDRESS);
|
||||
psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING);
|
||||
|
||||
/* write magic number in backup register */
|
||||
if (cpu == 0x01)
|
||||
writel(BOOT_API_A7_CORE1_MAGIC_NUMBER,
|
||||
TAMP_BACKUP_MAGIC_NUMBER);
|
||||
else
|
||||
writel(BOOT_API_A7_CORE0_MAGIC_NUMBER,
|
||||
TAMP_BACKUP_MAGIC_NUMBER);
|
||||
|
||||
/* Generate an IT to start the core */
|
||||
stm32mp_raise_sgi0(cpu);
|
||||
|
||||
return ARM_PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
s32 __secure psci_cpu_off(void)
|
||||
{
|
||||
u32 cpu;
|
||||
|
||||
cpu = psci_get_cpu_id();
|
||||
|
||||
psci_cpu_off_common();
|
||||
psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);
|
||||
|
||||
/* reset core: wfi is managed by BootRom */
|
||||
if (cpu == 0x01)
|
||||
writel(RCC_MP_GRSTCSETR_MPUP1RST, RCC_MP_GRSTCSETR);
|
||||
else
|
||||
writel(RCC_MP_GRSTCSETR_MPUP0RST, RCC_MP_GRSTCSETR);
|
||||
|
||||
/* just waiting reset */
|
||||
while (1)
|
||||
wfi();
|
||||
}
|
||||
|
||||
void __secure psci_system_reset(void)
|
||||
{
|
||||
/* System reset */
|
||||
writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
|
||||
/* just waiting reset */
|
||||
while (1)
|
||||
wfi();
|
||||
}
|
||||
|
||||
void __secure psci_system_off(void)
|
||||
{
|
||||
/* System Off is not managed, waiting user power off
|
||||
* TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
|
||||
*/
|
||||
while (1)
|
||||
wfi();
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <regmap.h>
|
||||
#include <syscon.h>
|
||||
#include <power/pmic.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
#define STM32MP_PWR_CR3 0xc
|
||||
#define STM32MP_PWR_CR3_USB33DEN BIT(24)
|
||||
#define STM32MP_PWR_CR3_USB33RDY BIT(26)
|
||||
#define STM32MP_PWR_CR3_REG18DEN BIT(28)
|
||||
#define STM32MP_PWR_CR3_REG18RDY BIT(29)
|
||||
#define STM32MP_PWR_CR3_REG11DEN BIT(30)
|
||||
#define STM32MP_PWR_CR3_REG11RDY BIT(31)
|
||||
|
||||
struct stm32mp_pwr_reg_info {
|
||||
u32 enable;
|
||||
u32 ready;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct stm32mp_pwr_priv {
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int stm32mp_pwr_write(struct udevice *dev, uint reg,
|
||||
const uint8_t *buff, int len)
|
||||
{
|
||||
struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
|
||||
u32 val = *(u32 *)buff;
|
||||
|
||||
if (len != 4)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_write(priv->regmap, STM32MP_PWR_CR3, val);
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
|
||||
int len)
|
||||
{
|
||||
struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (len != 4)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_read(priv->regmap, STM32MP_PWR_CR3, (u32 *)buff);
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("%s: unable to find regmap (%ld)\n", __func__,
|
||||
PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
priv->regmap = regmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pmic_child_info pwr_children_info[] = {
|
||||
{ .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
|
||||
{ .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
|
||||
{ },
|
||||
};
|
||||
|
||||
static int stm32mp_pwr_bind(struct udevice *dev)
|
||||
{
|
||||
int children;
|
||||
|
||||
children = pmic_bind_children(dev, dev->node, pwr_children_info);
|
||||
if (!children)
|
||||
dev_dbg(dev, "no child found\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dm_pmic_ops stm32mp_pwr_ops = {
|
||||
.read = stm32mp_pwr_read,
|
||||
.write = stm32mp_pwr_write,
|
||||
};
|
||||
|
||||
static const struct udevice_id stm32mp_pwr_ids[] = {
|
||||
{ .compatible = "st,stm32mp1,pwr-reg" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
|
||||
.name = "stm32mp_pwr_pmic",
|
||||
.id = UCLASS_PMIC,
|
||||
.of_match = stm32mp_pwr_ids,
|
||||
.bind = stm32mp_pwr_bind,
|
||||
.ops = &stm32mp_pwr_ops,
|
||||
.ofdata_to_platdata = stm32mp_pwr_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct stm32mp_pwr_priv),
|
||||
};
|
||||
|
||||
static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
|
||||
.enable = STM32MP_PWR_CR3_REG11DEN,
|
||||
.ready = STM32MP_PWR_CR3_REG11RDY,
|
||||
.name = "reg11"
|
||||
};
|
||||
|
||||
static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
|
||||
.enable = STM32MP_PWR_CR3_REG18DEN,
|
||||
.ready = STM32MP_PWR_CR3_REG18RDY,
|
||||
.name = "reg18"
|
||||
};
|
||||
|
||||
static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
|
||||
.enable = STM32MP_PWR_CR3_USB33DEN,
|
||||
.ready = STM32MP_PWR_CR3_USB33RDY,
|
||||
.name = "usb33"
|
||||
};
|
||||
|
||||
static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
|
||||
&stm32mp_pwr_reg11,
|
||||
&stm32mp_pwr_reg18,
|
||||
&stm32mp_pwr_usb33,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int stm32mp_pwr_regulator_probe(struct udevice *dev)
|
||||
{
|
||||
const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos;
|
||||
struct dm_regulator_uclass_platdata *uc_pdata;
|
||||
|
||||
uc_pdata = dev_get_uclass_platdata(dev);
|
||||
|
||||
while (*p) {
|
||||
int rc;
|
||||
|
||||
rc = dev_read_stringlist_search(dev, "regulator-name",
|
||||
(*p)->name);
|
||||
if (rc >= 0) {
|
||||
dev_dbg(dev, "found regulator %s\n", (*p)->name);
|
||||
break;
|
||||
} else if (rc != -ENODATA) {
|
||||
return rc;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (!*p) {
|
||||
int i = 0;
|
||||
const char *s;
|
||||
|
||||
dev_dbg(dev, "regulator ");
|
||||
while (dev_read_string_index(dev, "regulator-name",
|
||||
i++, &s) >= 0)
|
||||
dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
|
||||
dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uc_pdata->type = REGULATOR_TYPE_FIXED;
|
||||
dev->priv = (void *)*p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
|
||||
{
|
||||
struct dm_regulator_uclass_platdata *uc_pdata;
|
||||
|
||||
uc_pdata = dev_get_uclass_platdata(dev);
|
||||
if (!uc_pdata)
|
||||
return -ENXIO;
|
||||
|
||||
if (uc_pdata->min_uV != uV) {
|
||||
dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
|
||||
{
|
||||
struct dm_regulator_uclass_platdata *uc_pdata;
|
||||
|
||||
uc_pdata = dev_get_uclass_platdata(dev);
|
||||
if (!uc_pdata)
|
||||
return -ENXIO;
|
||||
|
||||
if (uc_pdata->min_uV != uc_pdata->max_uV) {
|
||||
dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return uc_pdata->min_uV;
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
|
||||
{
|
||||
const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
|
||||
int rc;
|
||||
u32 reg;
|
||||
|
||||
rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
|
||||
|
||||
return (reg & p->enable) != 0;
|
||||
}
|
||||
|
||||
static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
|
||||
{
|
||||
const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
|
||||
int rc;
|
||||
u32 reg;
|
||||
u32 time_start;
|
||||
|
||||
dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
|
||||
|
||||
rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* if regulator is already in the wanted state, nothing to do */
|
||||
if (!!(reg & p->enable) == enable)
|
||||
return 0;
|
||||
|
||||
reg &= ~p->enable;
|
||||
if (enable)
|
||||
reg |= p->enable;
|
||||
|
||||
rc = pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!enable)
|
||||
return 0;
|
||||
|
||||
/* waiting ready for enable */
|
||||
time_start = get_timer(0);
|
||||
while (1) {
|
||||
rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
|
||||
if (rc)
|
||||
return rc;
|
||||
if (reg & p->ready)
|
||||
break;
|
||||
if (get_timer(time_start) > CONFIG_SYS_HZ) {
|
||||
dev_dbg(dev, "%s: timeout\n", p->name);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
|
||||
.set_value = stm32mp_pwr_regulator_set_value,
|
||||
.get_value = stm32mp_pwr_regulator_get_value,
|
||||
.get_enable = stm32mp_pwr_regulator_get_enable,
|
||||
.set_enable = stm32mp_pwr_regulator_set_enable,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
|
||||
.name = "stm32mp_pwr_regulator",
|
||||
.id = UCLASS_REGULATOR,
|
||||
.ops = &stm32mp_pwr_regulator_ops,
|
||||
.probe = stm32mp_pwr_regulator_probe,
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <spl.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <linux/libfdt.h>
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
u32 boot_mode;
|
||||
|
||||
boot_mode = get_bootmode();
|
||||
|
||||
switch (boot_mode) {
|
||||
case BOOT_FLASH_SD_1:
|
||||
case BOOT_FLASH_EMMC_1:
|
||||
return BOOT_DEVICE_MMC1;
|
||||
case BOOT_FLASH_SD_2:
|
||||
case BOOT_FLASH_EMMC_2:
|
||||
return BOOT_DEVICE_MMC2;
|
||||
case BOOT_SERIAL_UART_1:
|
||||
case BOOT_SERIAL_UART_2:
|
||||
case BOOT_SERIAL_UART_3:
|
||||
case BOOT_SERIAL_UART_4:
|
||||
case BOOT_SERIAL_UART_5:
|
||||
case BOOT_SERIAL_UART_6:
|
||||
case BOOT_SERIAL_UART_7:
|
||||
case BOOT_SERIAL_UART_8:
|
||||
return BOOT_DEVICE_UART;
|
||||
case BOOT_SERIAL_USB_OTG:
|
||||
return BOOT_DEVICE_USB;
|
||||
case BOOT_FLASH_NAND_FMC:
|
||||
return BOOT_DEVICE_NAND;
|
||||
case BOOT_FLASH_NOR_QSPI:
|
||||
return BOOT_DEVICE_SPI;
|
||||
}
|
||||
|
||||
return BOOT_DEVICE_MMC1;
|
||||
}
|
||||
|
||||
u32 spl_boot_mode(const u32 boot_device)
|
||||
{
|
||||
return MMCSD_MODE_RAW;
|
||||
}
|
||||
|
||||
int spl_boot_partition(const u32 boot_device)
|
||||
{
|
||||
switch (boot_device) {
|
||||
case BOOT_DEVICE_MMC1:
|
||||
return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION;
|
||||
case BOOT_DEVICE_MMC2:
|
||||
return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION_MMC2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_DISPLAY_PRINT
|
||||
void spl_display_print(void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
const char *model;
|
||||
|
||||
/* same code than show_board_info() but not compiled for SPL
|
||||
* see CONFIG_DISPLAY_BOARDINFO & common/board_info.c
|
||||
*/
|
||||
model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
|
||||
if (model)
|
||||
printf("Model: %s\n", model);
|
||||
}
|
||||
#endif
|
||||
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
arch_cpu_init();
|
||||
|
||||
ret = spl_early_init();
|
||||
if (ret) {
|
||||
debug("spl_early_init() failed: %d\n", ret);
|
||||
hang();
|
||||
}
|
||||
|
||||
ret = uclass_get_device(UCLASS_CLK, 0, &dev);
|
||||
if (ret) {
|
||||
debug("Clock init failed: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = uclass_get_device(UCLASS_RESET, 0, &dev);
|
||||
if (ret) {
|
||||
debug("Reset init failed: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = uclass_get_device(UCLASS_PINCTRL, 0, &dev);
|
||||
if (ret) {
|
||||
debug("%s: Cannot find pinctrl device\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable console uart printing */
|
||||
preloader_console_init();
|
||||
|
||||
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
|
||||
if (ret) {
|
||||
printf("DRAM init failed: %d\n", ret);
|
||||
hang();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/arch/stm32.h>
|
||||
|
||||
static const struct udevice_id stm32mp_syscon_ids[] = {
|
||||
{ .compatible = "st,stm32mp1-pwr", .data = STM32MP_SYSCON_PWR },
|
||||
{ .compatible = "st,stm32mp157-syscfg",
|
||||
.data = STM32MP_SYSCON_SYSCFG },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(syscon_stm32mp) = {
|
||||
.name = "stmp32mp_syscon",
|
||||
.id = UCLASS_SYSCON,
|
||||
.of_match = stm32mp_syscon_ids,
|
||||
.bind = dm_scan_fdt_dev,
|
||||
};
|
||||
Reference in New Issue
Block a user