mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-11 13:56:30 +00:00
8729b1ae2c
At present these functions return 0 on success. For some devices we want to know how many bytes were transferred. It seems useful to adjust the API to be more like the POSIX read() and write() functions. Update these two methods, a test and all users. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Patrick Delaunay <patrick.delaunay@st.com>
363 lines
8.4 KiB
C
363 lines
8.4 KiB
C
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
/*
|
|
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <debug_uart.h>
|
|
#include <environment.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_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
|
|
|
|
/* 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_SERIAL 13
|
|
#define BSEC_OTP_MAC 57
|
|
|
|
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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) */
|
|
|
|
static u32 get_bootmode(void)
|
|
{
|
|
u32 boot_mode;
|
|
#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
|
|
u32 bootrom_itf = readl(BOOTROM_PARAM_ADDR);
|
|
u32 bootrom_device, bootrom_instance;
|
|
|
|
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);
|
|
#else
|
|
/* read TAMP backup register */
|
|
boot_mode = (readl(TAMP_BOOT_CONTEXT) & TAMP_BOOT_MODE_MASK) >>
|
|
TAMP_BOOT_MODE_SHIFT;
|
|
#endif
|
|
return boot_mode;
|
|
}
|
|
|
|
/*
|
|
* 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();
|
|
|
|
security_init();
|
|
#endif
|
|
|
|
/* get bootmode from BootRom context: saved in TAMP register */
|
|
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_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;
|
|
}
|
|
|
|
u32 get_cpu_type(void)
|
|
{
|
|
return (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
|
|
}
|
|
|
|
#if defined(CONFIG_DISPLAY_CPUINFO)
|
|
int print_cpuinfo(void)
|
|
{
|
|
char *cpu_s, *cpu_r;
|
|
|
|
switch (get_cpu_type()) {
|
|
case CPU_STMP32MP15x:
|
|
cpu_s = "15x";
|
|
break;
|
|
default:
|
|
cpu_s = "?";
|
|
break;
|
|
}
|
|
|
|
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\n", cpu_s, cpu_r);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_DISPLAY_CPUINFO */
|
|
|
|
static void setup_boot_mode(void)
|
|
{
|
|
char cmd[60];
|
|
u32 boot_ctx = readl(TAMP_BOOT_CONTEXT);
|
|
u32 boot_mode =
|
|
(boot_ctx & TAMP_BOOT_MODE_MASK) >> TAMP_BOOT_MODE_SHIFT;
|
|
int instance = (boot_mode & TAMP_BOOT_INSTANCE_MASK) - 1;
|
|
|
|
pr_debug("%s: boot_ctx=0x%x => boot_mode=%x, instance=%d\n",
|
|
__func__, boot_ctx, boot_mode, instance);
|
|
|
|
switch (boot_mode & TAMP_BOOT_DEVICE_MASK) {
|
|
case BOOT_SERIAL_UART:
|
|
sprintf(cmd, "%d", instance);
|
|
env_set("boot_device", "uart");
|
|
env_set("boot_instance", cmd);
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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, BSEC_OTP_MAC * 4 + STM32_BSEC_OTP_OFFSET,
|
|
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", 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, BSEC_OTP_SERIAL * 4 + STM32_BSEC_OTP_OFFSET,
|
|
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;
|
|
}
|