diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/arch/arm/mach-imx/imx8 | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/arch/arm/mach-imx/imx8')
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/Kconfig | 130 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/Makefile | 14 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/ahab.c | 351 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/clock.c | 22 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/cpu.c | 658 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/fdt.c | 304 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/image.c | 249 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/iomux.c | 45 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/lowlevel_init.S | 36 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/misc.c | 65 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/parse-container.c | 208 | ||||
-rw-r--r-- | roms/u-boot/arch/arm/mach-imx/imx8/snvs_security_sc.c | 925 |
12 files changed, 3007 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/Kconfig b/roms/u-boot/arch/arm/mach-imx/imx8/Kconfig new file mode 100644 index 000000000..71221d8d0 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/Kconfig @@ -0,0 +1,130 @@ +if ARCH_IMX8 + +config AHAB_BOOT + bool "Support i.MX8 AHAB features" + imply CMD_DEKBLOB + help + This option enables the support for AHAB secure boot. + +config IMX8 + bool + +config MU_BASE_SPL + hex "MU base address used in SPL" + default 0x5d1b0000 + help + SPL runs in EL3 mode, it use MU0_A to communicate with SCU. + So we could not reuse the one in dts which is for normal U-Boot. + +config IMX8QM + select IMX8 + select SUPPORT_SPL + select SPL_RECOVER_DATA_SECTION + bool + +config IMX8QXP + select IMX8 + select SUPPORT_SPL + select SPL_RECOVER_DATA_SECTION + bool + +config SYS_SOC + default "imx8" + +config SPL_LOAD_IMX_CONTAINER + bool "Enable SPL loading U-Boot as a i.MX Container image" + depends on SPL + help + This is to let SPL could load i.MX8 Container image + +config IMX_CONTAINER_CFG + string "i.MX Container config file" + depends on SPL + help + This is to specific the cfg file for generating container + image which will be loaded by SPL. + +config BOOTAUX_RESERVED_MEM_BASE + hex "i.MX auxiliary core dram memory base" + default 0 + +config BOOTAUX_RESERVED_MEM_SIZE + hex "i.MX auxiliary core dram memory size" + default 0 + +choice + prompt "i.MX8 board select" + optional + +config TARGET_APALIS_IMX8 + bool "Support Apalis iMX8 module" + select BOARD_LATE_INIT + select IMX8QM + +config TARGET_COLIBRI_IMX8X + bool "Support Colibri iMX8X module" + select BOARD_LATE_INIT + select IMX8QXP + +config TARGET_APALIS_IMX8X + bool "Support Apalis iMX8X module" + select BOARD_LATE_INIT + select IMX8QXP + +config TARGET_DENEB + bool "Support i.MX8QXP Capricorn Deneb board" + select BOARD_LATE_INIT + select IMX8QXP + +config TARGET_GIEDI + bool "Support i.MX8QXP Capricorn Giedi board" + select BOARD_LATE_INIT + select IMX8QXP + +config TARGET_IMX8QM_MEK + bool "Support i.MX8QM MEK board" + select BOARD_LATE_INIT + select IMX8QM + +config TARGET_CONGA_QMX8 + bool "Support congatec conga-QMX8 board" + select BOARD_LATE_INIT + select SUPPORT_SPL + select IMX8QM + +config TARGET_IMX8QM_ROM7720_A1 + bool "Support i.MX8QM ROM-7720-A1" + select BOARD_LATE_INIT + select SUPPORT_SPL + select IMX8QM + +config TARGET_IMX8QXP_MEK + bool "Support i.MX8QXP MEK board" + select BOARD_LATE_INIT + select IMX8QXP + +endchoice + +source "board/freescale/imx8qm_mek/Kconfig" +source "board/freescale/imx8qxp_mek/Kconfig" +source "board/congatec/cgtqmx8/Kconfig" +source "board/advantech/imx8qm_rom7720_a1/Kconfig" +source "board/toradex/apalis-imx8/Kconfig" +source "board/toradex/colibri-imx8x/Kconfig" +source "board/toradex/apalis-imx8x/Kconfig" +source "board/siemens/capricorn/Kconfig" + +config IMX_SNVS_SEC_SC + bool "Support SNVS configuration" + help + Allow to configure the SNVS via SCU API to configure tampers and secure + violation. + +config IMX_SNVS_SEC_SC_AUTO + bool "Support SNVS configuration command" + depends on IMX_SNVS_SEC_SC + help + This configuration will apply the selected configurations automatically + at boot. + +endif diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/Makefile b/roms/u-boot/arch/arm/mach-imx/imx8/Makefile new file mode 100644 index 000000000..bbb41adbe --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/Makefile @@ -0,0 +1,14 @@ +# +# Copyright 2018 NXP +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += cpu.o iomux.o misc.o lowlevel_init.o +obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o +obj-$(CONFIG_AHAB_BOOT) += ahab.o + +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image.o parse-container.o +endif +obj-$(CONFIG_IMX_SNVS_SEC_SC) += snvs_security_sc.o diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/ahab.c b/roms/u-boot/arch/arm/mach-imx/imx8/ahab.c new file mode 100644 index 000000000..6392fe267 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/ahab.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/sci/sci.h> +#include <asm/mach-imx/sys_proto.h> +#include <asm/arch-imx/cpu.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/image.h> +#include <console.h> +#include <cpu_func.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define SEC_SECURE_RAM_BASE (0x31800000UL) +#define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) +#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE (0x60000000UL) + +#define SECO_PT 2U + +static inline bool check_in_dram(ulong addr) +{ + int i; + struct bd_info *bd = gd->bd; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { + if (bd->bi_dram[i].size) { + if (addr >= bd->bi_dram[i].start && + addr < (bd->bi_dram[i].start + bd->bi_dram[i].size)) + return true; + } + } + + return false; +} + +int authenticate_os_container(ulong addr) +{ + struct container_hdr *phdr; + int i, ret = 0; + int err; + sc_rm_mr_t mr; + sc_faddr_t start, end; + u16 length; + struct boot_img_t *img; + unsigned long s, e; + + if (addr % 4) { + puts("Error: Image's address is not 4 byte aligned\n"); + return -EINVAL; + } + + if (!check_in_dram(addr)) { + puts("Error: Image's address is invalid\n"); + return -EINVAL; + } + + phdr = (struct container_hdr *)addr; + if (phdr->tag != 0x87 && phdr->version != 0x0) { + printf("Error: Wrong container header\n"); + return -EFAULT; + } + + if (!phdr->num_images) { + printf("Error: Wrong container, no image found\n"); + return -EFAULT; + } + + length = phdr->length_lsb + (phdr->length_msb << 8); + + debug("container length %u\n", length); + memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)addr, + ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); + + err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER, + SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); + if (err) { + printf("Authenticate container hdr failed, return %d\n", + err); + ret = -EIO; + goto exit; + } + + /* Copy images to dest address */ + for (i = 0; i < phdr->num_images; i++) { + img = (struct boot_img_t *)(addr + + sizeof(struct container_hdr) + + i * sizeof(struct boot_img_t)); + + debug("img %d, dst 0x%x, src 0x%lux, size 0x%x\n", + i, (uint32_t) img->dst, img->offset + addr, img->size); + + memcpy((void *)img->dst, (const void *)(img->offset + addr), + img->size); + + s = img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1); + e = ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1; + + flush_dcache_range(s, e); + + /* Find the memreg and set permission for seco pt */ + err = sc_rm_find_memreg(-1, &mr, s, e); + if (err) { + printf("Error: can't find memreg for image load address 0x%llx, error %d\n", img->dst, err); + ret = -ENOMEM; + goto exit; + } + + err = sc_rm_get_memreg_info(-1, mr, &start, &end); + if (!err) + debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end); + + err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, + SC_RM_PERM_FULL); + if (err) { + printf("Set permission failed for img %d, error %d\n", + i, err); + ret = -EPERM; + goto exit; + } + + err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE, + (1 << i)); + if (err) { + printf("Authenticate img %d failed, return %d\n", + i, err); + ret = -EIO; + } + + err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT, + SC_RM_PERM_NONE); + if (err) { + printf("Remove permission failed for img %d, err %d\n", + i, err); + ret = -EPERM; + } + + if (ret) + goto exit; + } + +exit: + if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0) != SC_ERR_NONE) + printf("Error: release container failed!\n"); + + return ret; +} + +static int do_authenticate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr; + + if (argc < 2) + return CMD_RET_USAGE; + + addr = simple_strtoul(argv[1], NULL, 16); + + printf("Authenticate OS container at 0x%lx\n", addr); + + if (authenticate_os_container(addr)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static void display_life_cycle(u16 lc) +{ + printf("Lifecycle: 0x%04X, ", lc); + switch (lc) { + case 0x1: + printf("Pristine\n\n"); + break; + case 0x2: + printf("Fab\n\n"); + break; + case 0x8: + printf("Open\n\n"); + break; + case 0x20: + printf("NXP closed\n\n"); + break; + case 0x80: + printf("OEM closed\n\n"); + break; + case 0x100: + printf("Partial field return\n\n"); + break; + case 0x200: + printf("Full field return\n\n"); + break; + case 0x400: + printf("No return\n\n"); + break; + default: + printf("Unknown\n\n"); + break; + } +} + +#define AHAB_AUTH_CONTAINER_REQ 0x87 +#define AHAB_VERIFY_IMAGE_REQ 0x88 + +#define AHAB_NO_AUTHENTICATION_IND 0xee +#define AHAB_BAD_KEY_HASH_IND 0xfa +#define AHAB_INVALID_KEY_IND 0xf9 +#define AHAB_BAD_SIGNATURE_IND 0xf0 +#define AHAB_BAD_HASH_IND 0xf1 + +static void display_ahab_auth_event(u32 event) +{ + u8 cmd = (event >> 16) & 0xff; + u8 resp_ind = (event >> 8) & 0xff; + + switch (cmd) { + case AHAB_AUTH_CONTAINER_REQ: + printf("\tCMD = AHAB_AUTH_CONTAINER_REQ (0x%02X)\n", cmd); + printf("\tIND = "); + break; + case AHAB_VERIFY_IMAGE_REQ: + printf("\tCMD = AHAB_VERIFY_IMAGE_REQ (0x%02X)\n", cmd); + printf("\tIND = "); + break; + default: + return; + } + + switch (resp_ind) { + case AHAB_NO_AUTHENTICATION_IND: + printf("AHAB_NO_AUTHENTICATION_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_KEY_HASH_IND: + printf("AHAB_BAD_KEY_HASH_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_INVALID_KEY_IND: + printf("AHAB_INVALID_KEY_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_SIGNATURE_IND: + printf("AHAB_BAD_SIGNATURE_IND (0x%02X)\n\n", resp_ind); + break; + case AHAB_BAD_HASH_IND: + printf("AHAB_BAD_HASH_IND (0x%02X)\n\n", resp_ind); + break; + default: + printf("Unknown Indicator (0x%02X)\n\n", resp_ind); + break; + } +} + +static int do_ahab_status(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int err; + u8 idx = 0U; + u32 event; + u16 lc; + + err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); + if (err != SC_ERR_NONE) { + printf("Error in get lifecycle\n"); + return -EIO; + } + + display_life_cycle(lc); + + err = sc_seco_get_event(-1, idx, &event); + while (err == SC_ERR_NONE) { + printf("SECO Event[%u] = 0x%08X\n", idx, event); + display_ahab_auth_event(event); + + idx++; + err = sc_seco_get_event(-1, idx, &event); + } + + if (idx == 0) + printf("No SECO Events Found!\n\n"); + + return 0; +} + +static int confirm_close(void) +{ + puts("Warning: Please ensure your sample is in NXP closed state, " + "OEM SRK hash has been fused, \n" + " and you are able to boot a signed image successfully " + "without any SECO events reported.\n" + " If not, your sample will be unrecoverable.\n" + "\nReally perform this operation? <y/N>\n"); + + if (confirm_yesno()) + return 1; + + puts("Ahab close aborted\n"); + return 0; +} + +static int do_ahab_close(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int confirmed = argc >= 2 && !strcmp(argv[1], "-y"); + int err; + u16 lc; + + if (!confirmed && !confirm_close()) + return -EACCES; + + err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); + if (err != SC_ERR_NONE) { + printf("Error in get lifecycle\n"); + return -EIO; + } + + if (lc != 0x20) { + puts("Current lifecycle is NOT NXP closed, can't move to OEM closed\n"); + display_life_cycle(lc); + return -EPERM; + } + + err = sc_seco_forward_lifecycle(-1, 16); + if (err != SC_ERR_NONE) { + printf("Error in forward lifecycle to OEM closed\n"); + return -EIO; + } + + printf("Change to OEM closed successfully\n"); + + return 0; +} + +U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate, + "autenticate OS container via AHAB", + "addr\n" + "addr - OS container hex address\n" +); + +U_BOOT_CMD(ahab_status, CONFIG_SYS_MAXARGS, 1, do_ahab_status, + "display AHAB lifecycle and events from seco", + "" +); + +U_BOOT_CMD(ahab_close, CONFIG_SYS_MAXARGS, 1, do_ahab_close, + "Change AHAB lifecycle to OEM closed", + "" +); diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/clock.c b/roms/u-boot/arch/arm/mach-imx/imx8/clock.c new file mode 100644 index 000000000..9941b57b4 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/clock.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include <common.h> +#include <asm/global_data.h> +#include <linux/errno.h> +#include <asm/arch/clock.h> + +DECLARE_GLOBAL_DATA_PTR; + +u32 mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + default: + printf("Unsupported mxc_clock %d\n", clk); + break; + } + + return 0; +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/cpu.c b/roms/u-boot/arch/arm/mach-imx/imx8/cpu.c new file mode 100644 index 000000000..02db322f5 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/cpu.c @@ -0,0 +1,658 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include <common.h> +#include <clk.h> +#include <cpu.h> +#include <cpu_func.h> +#include <dm.h> +#include <init.h> +#include <log.h> +#include <asm/cache.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass.h> +#include <errno.h> +#include <spl.h> +#include <thermal.h> +#include <asm/arch/sci/sci.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch-imx/cpu.h> +#include <asm/armv8/cpu.h> +#include <asm/armv8/mmu.h> +#include <asm/setup.h> +#include <asm/mach-imx/boot_mode.h> +#include <spl.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define BT_PASSOVER_TAG 0x504F +struct pass_over_info_t *get_pass_over_info(void) +{ + struct pass_over_info_t *p = + (struct pass_over_info_t *)PASS_OVER_INFO_ADDR; + + if (p->barker != BT_PASSOVER_TAG || + p->len != sizeof(struct pass_over_info_t)) + return NULL; + + return p; +} + +int arch_cpu_init(void) +{ +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_RECOVER_DATA_SECTION) + spl_save_restore_data(); +#endif + +#ifdef CONFIG_SPL_BUILD + struct pass_over_info_t *pass_over; + + if (is_soc_rev(CHIP_REV_A)) { + pass_over = get_pass_over_info(); + if (pass_over && pass_over->g_ap_mu == 0) { + /* + * When ap_mu is 0, means the U-Boot booted + * from first container + */ + sc_misc_boot_status(-1, SC_MISC_BOOT_STATUS_SUCCESS); + } + } +#endif + + return 0; +} + +int arch_cpu_init_dm(void) +{ + struct udevice *devp; + int node, ret; + + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx8-mu"); + + ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp); + if (ret) { + printf("could not get scu %d\n", ret); + return ret; + } + + if (is_imx8qm()) { + ret = sc_pm_set_resource_power_mode(-1, SC_R_SMMU, + SC_PM_PW_MODE_ON); + if (ret) + return ret; + } + + return 0; +} + +int print_bootinfo(void) +{ + enum boot_device bt_dev = get_boot_device(); + + puts("Boot: "); + switch (bt_dev) { + case SD1_BOOT: + puts("SD0\n"); + break; + case SD2_BOOT: + puts("SD1\n"); + break; + case SD3_BOOT: + puts("SD2\n"); + break; + case MMC1_BOOT: + puts("MMC0\n"); + break; + case MMC2_BOOT: + puts("MMC1\n"); + break; + case MMC3_BOOT: + puts("MMC2\n"); + break; + case FLEXSPI_BOOT: + puts("FLEXSPI\n"); + break; + case SATA_BOOT: + puts("SATA\n"); + break; + case NAND_BOOT: + puts("NAND\n"); + break; + case USB_BOOT: + puts("USB\n"); + break; + default: + printf("Unknown device %u\n", bt_dev); + break; + } + + return 0; +} + +enum boot_device get_boot_device(void) +{ + enum boot_device boot_dev = SD1_BOOT; + + sc_rsrc_t dev_rsrc; + + sc_misc_get_boot_dev(-1, &dev_rsrc); + + switch (dev_rsrc) { + case SC_R_SDHC_0: + boot_dev = MMC1_BOOT; + break; + case SC_R_SDHC_1: + boot_dev = SD2_BOOT; + break; + case SC_R_SDHC_2: + boot_dev = SD3_BOOT; + break; + case SC_R_NAND: + boot_dev = NAND_BOOT; + break; + case SC_R_FSPI_0: + boot_dev = FLEXSPI_BOOT; + break; + case SC_R_SATA_0: + boot_dev = SATA_BOOT; + break; + case SC_R_USB_0: + case SC_R_USB_1: + case SC_R_USB_2: + boot_dev = USB_BOOT; + break; + default: + break; + } + + return boot_dev; +} + +#ifdef CONFIG_SERIAL_TAG +#define FUSE_UNIQUE_ID_WORD0 16 +#define FUSE_UNIQUE_ID_WORD1 17 +void get_board_serial(struct tag_serialnr *serialnr) +{ + sc_err_t err; + u32 val1 = 0, val2 = 0; + u32 word1, word2; + + if (!serialnr) + return; + + word1 = FUSE_UNIQUE_ID_WORD0; + word2 = FUSE_UNIQUE_ID_WORD1; + + err = sc_misc_otp_fuse_read(-1, word1, &val1); + if (err != SC_ERR_NONE) { + printf("%s fuse %d read error: %d\n", __func__, word1, err); + return; + } + + err = sc_misc_otp_fuse_read(-1, word2, &val2); + if (err != SC_ERR_NONE) { + printf("%s fuse %d read error: %d\n", __func__, word2, err); + return; + } + serialnr->low = val1; + serialnr->high = val2; +} +#endif /*CONFIG_SERIAL_TAG*/ + +#ifdef CONFIG_ENV_IS_IN_MMC +__weak int board_mmc_get_env_dev(int devno) +{ + return CONFIG_SYS_MMC_ENV_DEV; +} + +int mmc_get_env_dev(void) +{ + sc_rsrc_t dev_rsrc; + int devno; + + sc_misc_get_boot_dev(-1, &dev_rsrc); + + switch (dev_rsrc) { + case SC_R_SDHC_0: + devno = 0; + break; + case SC_R_SDHC_1: + devno = 1; + break; + case SC_R_SDHC_2: + devno = 2; + break; + default: + /* If not boot from sd/mmc, use default value */ + return CONFIG_SYS_MMC_ENV_DEV; + } + + return board_mmc_get_env_dev(devno); +} +#endif + +#define MEMSTART_ALIGNMENT SZ_2M /* Align the memory start with 2MB */ + +static int get_owned_memreg(sc_rm_mr_t mr, sc_faddr_t *addr_start, + sc_faddr_t *addr_end) +{ + sc_faddr_t start, end; + int ret; + bool owned; + + owned = sc_rm_is_memreg_owned(-1, mr); + if (owned) { + ret = sc_rm_get_memreg_info(-1, mr, &start, &end); + if (ret) { + printf("Memreg get info failed, %d\n", ret); + return -EINVAL; + } + debug("0x%llx -- 0x%llx\n", start, end); + *addr_start = start; + *addr_end = end; + + return 0; + } + + return -EINVAL; +} + +__weak void board_mem_get_layout(u64 *phys_sdram_1_start, + u64 *phys_sdram_1_size, + u64 *phys_sdram_2_start, + u64 *phys_sdram_2_size) +{ + *phys_sdram_1_start = PHYS_SDRAM_1; + *phys_sdram_1_size = PHYS_SDRAM_1_SIZE; + *phys_sdram_2_start = PHYS_SDRAM_2; + *phys_sdram_2_size = PHYS_SDRAM_2_SIZE; +} + +phys_size_t get_effective_memsize(void) +{ + sc_rm_mr_t mr; + sc_faddr_t start, end, end1, start_aligned; + u64 phys_sdram_1_start, phys_sdram_1_size; + u64 phys_sdram_2_start, phys_sdram_2_size; + int err; + + board_mem_get_layout(&phys_sdram_1_start, &phys_sdram_1_size, + &phys_sdram_2_start, &phys_sdram_2_size); + + + end1 = (sc_faddr_t)phys_sdram_1_start + phys_sdram_1_size; + for (mr = 0; mr < 64; mr++) { + err = get_owned_memreg(mr, &start, &end); + if (!err) { + start_aligned = roundup(start, MEMSTART_ALIGNMENT); + /* Too small memory region, not use it */ + if (start_aligned > end) + continue; + + /* Find the memory region runs the U-Boot */ + if (start >= phys_sdram_1_start && start <= end1 && + (start <= CONFIG_SYS_TEXT_BASE && + end >= CONFIG_SYS_TEXT_BASE)) { + if ((end + 1) <= + ((sc_faddr_t)phys_sdram_1_start + + phys_sdram_1_size)) + return (end - phys_sdram_1_start + 1); + else + return phys_sdram_1_size; + } + } + } + + return phys_sdram_1_size; +} + +int dram_init(void) +{ + sc_rm_mr_t mr; + sc_faddr_t start, end, end1, end2; + u64 phys_sdram_1_start, phys_sdram_1_size; + u64 phys_sdram_2_start, phys_sdram_2_size; + int err; + + board_mem_get_layout(&phys_sdram_1_start, &phys_sdram_1_size, + &phys_sdram_2_start, &phys_sdram_2_size); + + end1 = (sc_faddr_t)phys_sdram_1_start + phys_sdram_1_size; + end2 = (sc_faddr_t)phys_sdram_2_start + phys_sdram_2_size; + for (mr = 0; mr < 64; mr++) { + err = get_owned_memreg(mr, &start, &end); + if (!err) { + start = roundup(start, MEMSTART_ALIGNMENT); + /* Too small memory region, not use it */ + if (start > end) + continue; + + if (start >= phys_sdram_1_start && start <= end1) { + if ((end + 1) <= end1) + gd->ram_size += end - start + 1; + else + gd->ram_size += end1 - start; + } else if (start >= phys_sdram_2_start && + start <= end2) { + if ((end + 1) <= end2) + gd->ram_size += end - start + 1; + else + gd->ram_size += end2 - start; + } + } + } + + /* If error, set to the default value */ + if (!gd->ram_size) { + gd->ram_size = phys_sdram_1_size; + gd->ram_size += phys_sdram_2_size; + } + return 0; +} + +static void dram_bank_sort(int current_bank) +{ + phys_addr_t start; + phys_size_t size; + + while (current_bank > 0) { + if (gd->bd->bi_dram[current_bank - 1].start > + gd->bd->bi_dram[current_bank].start) { + start = gd->bd->bi_dram[current_bank - 1].start; + size = gd->bd->bi_dram[current_bank - 1].size; + + gd->bd->bi_dram[current_bank - 1].start = + gd->bd->bi_dram[current_bank].start; + gd->bd->bi_dram[current_bank - 1].size = + gd->bd->bi_dram[current_bank].size; + + gd->bd->bi_dram[current_bank].start = start; + gd->bd->bi_dram[current_bank].size = size; + } + current_bank--; + } +} + +int dram_init_banksize(void) +{ + sc_rm_mr_t mr; + sc_faddr_t start, end, end1, end2; + int i = 0; + u64 phys_sdram_1_start, phys_sdram_1_size; + u64 phys_sdram_2_start, phys_sdram_2_size; + int err; + + board_mem_get_layout(&phys_sdram_1_start, &phys_sdram_1_size, + &phys_sdram_2_start, &phys_sdram_2_size); + + end1 = (sc_faddr_t)phys_sdram_1_start + phys_sdram_1_size; + end2 = (sc_faddr_t)phys_sdram_2_start + phys_sdram_2_size; + for (mr = 0; mr < 64 && i < CONFIG_NR_DRAM_BANKS; mr++) { + err = get_owned_memreg(mr, &start, &end); + if (!err) { + start = roundup(start, MEMSTART_ALIGNMENT); + if (start > end) /* Small memory region, no use it */ + continue; + + if (start >= phys_sdram_1_start && start <= end1) { + gd->bd->bi_dram[i].start = start; + + if ((end + 1) <= end1) + gd->bd->bi_dram[i].size = + end - start + 1; + else + gd->bd->bi_dram[i].size = end1 - start; + + dram_bank_sort(i); + i++; + } else if (start >= phys_sdram_2_start && start <= end2) { + gd->bd->bi_dram[i].start = start; + + if ((end + 1) <= end2) + gd->bd->bi_dram[i].size = + end - start + 1; + else + gd->bd->bi_dram[i].size = end2 - start; + + dram_bank_sort(i); + i++; + } + } + } + + /* If error, set to the default value */ + if (!i) { + gd->bd->bi_dram[0].start = phys_sdram_1_start; + gd->bd->bi_dram[0].size = phys_sdram_1_size; + gd->bd->bi_dram[1].start = phys_sdram_2_start; + gd->bd->bi_dram[1].size = phys_sdram_2_size; + } + + return 0; +} + +static u64 get_block_attrs(sc_faddr_t addr_start) +{ + u64 attr = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN; + u64 phys_sdram_1_start, phys_sdram_1_size; + u64 phys_sdram_2_start, phys_sdram_2_size; + + board_mem_get_layout(&phys_sdram_1_start, &phys_sdram_1_size, + &phys_sdram_2_start, &phys_sdram_2_size); + + if ((addr_start >= phys_sdram_1_start && + addr_start <= ((sc_faddr_t)phys_sdram_1_start + phys_sdram_1_size)) || + (addr_start >= phys_sdram_2_start && + addr_start <= ((sc_faddr_t)phys_sdram_2_start + phys_sdram_2_size))) + return (PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_OUTER_SHARE); + + return attr; +} + +static u64 get_block_size(sc_faddr_t addr_start, sc_faddr_t addr_end) +{ + sc_faddr_t end1, end2; + u64 phys_sdram_1_start, phys_sdram_1_size; + u64 phys_sdram_2_start, phys_sdram_2_size; + + board_mem_get_layout(&phys_sdram_1_start, &phys_sdram_1_size, + &phys_sdram_2_start, &phys_sdram_2_size); + + + end1 = (sc_faddr_t)phys_sdram_1_start + phys_sdram_1_size; + end2 = (sc_faddr_t)phys_sdram_2_start + phys_sdram_2_size; + + if (addr_start >= phys_sdram_1_start && addr_start <= end1) { + if ((addr_end + 1) > end1) + return end1 - addr_start; + } else if (addr_start >= phys_sdram_2_start && addr_start <= end2) { + if ((addr_end + 1) > end2) + return end2 - addr_start; + } + + return (addr_end - addr_start + 1); +} + +#define MAX_PTE_ENTRIES 512 +#define MAX_MEM_MAP_REGIONS 16 + +static struct mm_region imx8_mem_map[MAX_MEM_MAP_REGIONS]; +struct mm_region *mem_map = imx8_mem_map; + +void enable_caches(void) +{ + sc_rm_mr_t mr; + sc_faddr_t start, end; + int err, i; + + /* Create map for registers access from 0x1c000000 to 0x80000000*/ + imx8_mem_map[0].virt = 0x1c000000UL; + imx8_mem_map[0].phys = 0x1c000000UL; + imx8_mem_map[0].size = 0x64000000UL; + imx8_mem_map[0].attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN; + + i = 1; + for (mr = 0; mr < 64 && i < MAX_MEM_MAP_REGIONS; mr++) { + err = get_owned_memreg(mr, &start, &end); + if (!err) { + imx8_mem_map[i].virt = start; + imx8_mem_map[i].phys = start; + imx8_mem_map[i].size = get_block_size(start, end); + imx8_mem_map[i].attrs = get_block_attrs(start); + i++; + } + } + + if (i < MAX_MEM_MAP_REGIONS) { + imx8_mem_map[i].size = 0; + imx8_mem_map[i].attrs = 0; + } else { + puts("Error, need more MEM MAP REGIONS reserved\n"); + icache_enable(); + return; + } + + for (i = 0; i < MAX_MEM_MAP_REGIONS; i++) { + debug("[%d] vir = 0x%llx phys = 0x%llx size = 0x%llx attrs = 0x%llx\n", + i, imx8_mem_map[i].virt, imx8_mem_map[i].phys, + imx8_mem_map[i].size, imx8_mem_map[i].attrs); + } + + icache_enable(); + dcache_enable(); +} + +#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) +u64 get_page_table_size(void) +{ + u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64); + u64 size = 0; + + /* + * For each memory region, the max table size: + * 2 level 3 tables + 2 level 2 tables + 1 level 1 table + */ + size = (2 + 2 + 1) * one_pt * MAX_MEM_MAP_REGIONS + one_pt; + + /* + * We need to duplicate our page table once to have an emergency pt to + * resort to when splitting page tables later on + */ + size *= 2; + + /* + * We may need to split page tables later on if dcache settings change, + * so reserve up to 4 (random pick) page tables for that. + */ + size += one_pt * 4; + + return size; +} +#endif + +#if defined(CONFIG_IMX8QM) +#define FUSE_MAC0_WORD0 452 +#define FUSE_MAC0_WORD1 453 +#define FUSE_MAC1_WORD0 454 +#define FUSE_MAC1_WORD1 455 +#elif defined(CONFIG_IMX8QXP) +#define FUSE_MAC0_WORD0 708 +#define FUSE_MAC0_WORD1 709 +#define FUSE_MAC1_WORD0 710 +#define FUSE_MAC1_WORD1 711 +#endif + +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + u32 word[2], val[2] = {}; + int i, ret; + + if (dev_id == 0) { + word[0] = FUSE_MAC0_WORD0; + word[1] = FUSE_MAC0_WORD1; + } else { + word[0] = FUSE_MAC1_WORD0; + word[1] = FUSE_MAC1_WORD1; + } + + for (i = 0; i < 2; i++) { + ret = sc_misc_otp_fuse_read(-1, word[i], &val[i]); + if (ret < 0) + goto err; + } + + mac[0] = val[0]; + mac[1] = val[0] >> 8; + mac[2] = val[0] >> 16; + mac[3] = val[0] >> 24; + mac[4] = val[1]; + mac[5] = val[1] >> 8; + + debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n", + __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return; +err: + printf("%s: fuse %d, err: %d\n", __func__, word[i], ret); +} + +u32 get_cpu_rev(void) +{ + u32 id = 0, rev = 0; + int ret; + + ret = sc_misc_get_control(-1, SC_R_SYSTEM, SC_C_ID, &id); + if (ret) + return 0; + + rev = (id >> 5) & 0xf; + id = (id & 0x1f) + MXC_SOC_IMX8; /* Dummy ID for chip */ + + return (id << 12) | rev; +} + +void board_boot_order(u32 *spl_boot_list) +{ + spl_boot_list[0] = spl_boot_device(); + + if (spl_boot_list[0] == BOOT_DEVICE_SPI) { + /* Check whether we own the flexspi0, if not, use NOR boot */ + if (!sc_rm_is_resource_owned(-1, SC_R_FSPI_0)) + spl_boot_list[0] = BOOT_DEVICE_NOR; + } +} + +bool m4_parts_booted(void) +{ + sc_rm_pt_t m4_parts[2]; + int err; + + err = sc_rm_get_resource_owner(-1, SC_R_M4_0_PID0, &m4_parts[0]); + if (err) { + printf("%s get resource [%d] owner error: %d\n", __func__, + SC_R_M4_0_PID0, err); + return false; + } + + if (sc_pm_is_partition_started(-1, m4_parts[0])) + return true; + + if (is_imx8qm()) { + err = sc_rm_get_resource_owner(-1, SC_R_M4_1_PID0, &m4_parts[1]); + if (err) { + printf("%s get resource [%d] owner error: %d\n", + __func__, SC_R_M4_1_PID0, err); + return false; + } + + if (sc_pm_is_partition_started(-1, m4_parts[1])) + return true; + } + + return false; +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/fdt.c b/roms/u-boot/arch/arm/mach-imx/imx8/fdt.c new file mode 100644 index 000000000..a132ce2e6 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/fdt.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <log.h> +#include <asm/arch/sci/sci.h> +#include <asm/arch/sys_proto.h> +#include <asm/global_data.h> +#include <dm/ofnode.h> +#include <fdt_support.h> +#include <linux/libfdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +static bool check_owned_resource(sc_rsrc_t rsrc_id) +{ + bool owned; + + owned = sc_rm_is_resource_owned(-1, rsrc_id); + + return owned; +} + +static int disable_fdt_node(void *blob, int nodeoffset) +{ + int rc, ret; + const char *status = "disabled"; + + do { + rc = fdt_setprop(blob, nodeoffset, "status", status, + strlen(status) + 1); + if (rc) { + if (rc == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(blob, 512); + if (ret) + return ret; + } + } + } while (rc == -FDT_ERR_NOSPACE); + + return rc; +} + +static void update_fdt_with_owned_resources(void *blob) +{ + /* + * Traverses the fdt nodes, check its power domain and use + * the resource id in the power domain for checking whether + * it is owned by current partition + */ + struct fdtdec_phandle_args args; + int offset = 0, depth = 0; + u32 rsrc_id; + int rc, i; + + for (offset = fdt_next_node(blob, offset, &depth); offset > 0; + offset = fdt_next_node(blob, offset, &depth)) { + debug("Node name: %s, depth %d\n", + fdt_get_name(blob, offset, NULL), depth); + + if (!fdt_get_property(blob, offset, "power-domains", NULL)) { + debug(" - ignoring node %s\n", + fdt_get_name(blob, offset, NULL)); + continue; + } + + if (!fdtdec_get_is_enabled(blob, offset)) { + debug(" - ignoring node %s\n", + fdt_get_name(blob, offset, NULL)); + continue; + } + + i = 0; + while (true) { + rc = fdtdec_parse_phandle_with_args(blob, offset, + "power-domains", + "#power-domain-cells", + 0, i++, &args); + if (rc == -ENOENT) { + break; + } else if (rc) { + printf("Parse power-domains of %s wrong: %d\n", + fdt_get_name(blob, offset, NULL), rc); + continue; + } + + rsrc_id = args.args[0]; + + if (!check_owned_resource(rsrc_id)) { + rc = disable_fdt_node(blob, offset); + if (!rc) { + printf("Disable %s rsrc %u not owned\n", + fdt_get_name(blob, offset, NULL), + rsrc_id); + } else { + printf("Unable to disable %s, err=%s\n", + fdt_get_name(blob, offset, NULL), + fdt_strerror(rc)); + } + } + } + } +} + +static int config_smmu_resource_sid(int rsrc, int sid) +{ + int err; + + err = sc_rm_set_master_sid(-1, rsrc, sid); + debug("set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err); + if (err != SC_ERR_NONE) { + if (!check_owned_resource(rsrc)) { + printf("%s rsrc[%d] not owned\n", __func__, rsrc); + return -1; + } + pr_err("fail set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err); + return -EINVAL; + } + + return 0; +} + +static int config_smmu_fdt_device_sid(void *blob, int device_offset, int sid) +{ + const char *name = fdt_get_name(blob, device_offset, NULL); + struct fdtdec_phandle_args args; + int rsrc, ret; + int proplen; + const fdt32_t *prop; + int i; + + prop = fdt_getprop(blob, device_offset, "fsl,sc_rsrc_id", &proplen); + if (prop) { + int i; + + debug("configure node %s sid 0x%x for %d resources\n", + name, sid, (int)(proplen / sizeof(fdt32_t))); + for (i = 0; i < proplen / sizeof(fdt32_t); ++i) { + ret = config_smmu_resource_sid(fdt32_to_cpu(prop[i]), + sid); + if (ret) + return ret; + } + + return 0; + } + + i = 0; + while (true) { + ret = fdtdec_parse_phandle_with_args(blob, device_offset, + "power-domains", + "#power-domain-cells", + 0, i++, &args); + if (ret == -ENOENT) { + break; + } else if (ret) { + printf("Parse power-domains of node %s wrong: %d\n", + fdt_get_name(blob, device_offset, NULL), ret); + continue; + } + + debug("configure node %s sid 0x%x rsrc=%d\n", + name, sid, rsrc); + rsrc = args.args[0]; + + ret = config_smmu_resource_sid(rsrc, sid); + if (ret) + break; + } + + return ret; +} + +static int config_smmu_fdt(void *blob) +{ + int offset, proplen, i, ret; + const fdt32_t *prop; + const char *name; + + /* Legacy smmu bindings, still used by xen. */ + offset = fdt_node_offset_by_compatible(blob, 0, "arm,mmu-500"); + prop = fdt_getprop(blob, offset, "mmu-masters", &proplen); + if (offset > 0 && prop) { + debug("found legacy mmu-masters property\n"); + + for (i = 0; i < proplen / 8; ++i) { + u32 phandle = fdt32_to_cpu(prop[2 * i]); + int sid = fdt32_to_cpu(prop[2 * i + 1]); + int device_offset; + + device_offset = fdt_node_offset_by_phandle(blob, + phandle); + if (device_offset < 0) { + pr_err("Not find device from mmu_masters: %d", + device_offset); + continue; + } + ret = config_smmu_fdt_device_sid(blob, device_offset, + sid); + if (ret) + return ret; + } + + /* Ignore new bindings if old bindings found, just like linux. */ + return 0; + } + + /* Generic smmu bindings */ + offset = 0; + while ((offset = fdt_next_node(blob, offset, NULL)) > 0) { + name = fdt_get_name(blob, offset, NULL); + prop = fdt_getprop(blob, offset, "iommus", &proplen); + if (!prop) + continue; + debug("node %s iommus proplen %d\n", name, proplen); + + if (proplen == 12) { + int sid = fdt32_to_cpu(prop[1]); + + config_smmu_fdt_device_sid(blob, offset, sid); + } else if (proplen != 4) { + debug("node %s ignore unexpected iommus proplen=%d\n", + name, proplen); + } + } + + return 0; +} + +static int ft_add_optee_node(void *fdt, struct bd_info *bd) +{ + const char *path, *subpath; + int offs; + + /* + * No TEE space allocated indicating no TEE running, so no + * need to add optee node in dts + */ + if (!boot_pointer[1]) + return 0; + + offs = fdt_increase_size(fdt, 512); + if (offs) { + printf("No Space for dtb\n"); + return 1; + } + + path = "/firmware"; + offs = fdt_path_offset(fdt, path); + if (offs < 0) { + path = "/"; + offs = fdt_path_offset(fdt, path); + + if (offs < 0) { + printf("Could not find root node.\n"); + return offs; + } + + subpath = "firmware"; + offs = fdt_add_subnode(fdt, offs, subpath); + if (offs < 0) { + printf("Could not create %s node.\n", subpath); + return offs; + } + } + + subpath = "optee"; + offs = fdt_add_subnode(fdt, offs, subpath); + if (offs < 0) { + printf("Could not create %s node.\n", subpath); + return offs; + } + + fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz"); + fdt_setprop_string(fdt, offs, "method", "smc"); + + return 0; +} + +int ft_system_setup(void *blob, struct bd_info *bd) +{ + int ret; + int off; + + if (CONFIG_BOOTAUX_RESERVED_MEM_BASE) { + off = fdt_add_mem_rsv(blob, CONFIG_BOOTAUX_RESERVED_MEM_BASE, + CONFIG_BOOTAUX_RESERVED_MEM_SIZE); + if (off < 0) + printf("Failed to reserve memory for bootaux: %s\n", + fdt_strerror(off)); + } + + update_fdt_with_owned_resources(blob); + + if (is_imx8qm()) { + ret = config_smmu_fdt(blob); + if (ret) + return ret; + } + + return ft_add_optee_node(blob, bd); +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/image.c b/roms/u-boot/arch/arm/mach-imx/imx8/image.c new file mode 100644 index 000000000..5abc0d3a3 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/image.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <errno.h> +#include <log.h> +#include <malloc.h> +#include <asm/io.h> +#include <mmc.h> +#include <spi_flash.h> +#include <nand.h> +#include <asm/arch/image.h> +#include <asm/arch/sys_proto.h> +#include <asm/mach-imx/boot_mode.h> + +#define MMC_DEV 0 +#define QSPI_DEV 1 +#define NAND_DEV 2 +#define QSPI_NOR_DEV 3 + +static int __get_container_size(ulong addr) +{ + struct container_hdr *phdr; + struct boot_img_t *img_entry; + struct signature_block_hdr *sign_hdr; + u8 i = 0; + u32 max_offset = 0, img_end; + + phdr = (struct container_hdr *)addr; + if (phdr->tag != 0x87 && phdr->version != 0x0) { + debug("Wrong container header\n"); + return -EFAULT; + } + + max_offset = sizeof(struct container_hdr); + + img_entry = (struct boot_img_t *)(addr + sizeof(struct container_hdr)); + for (i = 0; i < phdr->num_images; i++) { + img_end = img_entry->offset + img_entry->size; + if (img_end > max_offset) + max_offset = img_end; + + debug("img[%u], end = 0x%x\n", i, img_end); + + img_entry++; + } + + if (phdr->sig_blk_offset != 0) { + sign_hdr = (struct signature_block_hdr *)(addr + phdr->sig_blk_offset); + u16 len = sign_hdr->length_lsb + (sign_hdr->length_msb << 8); + + if (phdr->sig_blk_offset + len > max_offset) + max_offset = phdr->sig_blk_offset + len; + + debug("sigblk, end = 0x%x\n", phdr->sig_blk_offset + len); + } + + return max_offset; +} + +static int get_container_size(void *dev, int dev_type, unsigned long offset) +{ + u8 *buf = malloc(CONTAINER_HDR_ALIGNMENT); + int ret = 0; + + if (!buf) { + printf("Malloc buffer failed\n"); + return -ENOMEM; + } + +#ifdef CONFIG_SPL_MMC_SUPPORT + if (dev_type == MMC_DEV) { + unsigned long count = 0; + struct mmc *mmc = (struct mmc *)dev; + + count = blk_dread(mmc_get_blk_desc(mmc), + offset / mmc->read_bl_len, + CONTAINER_HDR_ALIGNMENT / mmc->read_bl_len, + buf); + if (count == 0) { + printf("Read container image from MMC/SD failed\n"); + return -EIO; + } + } +#endif + +#ifdef CONFIG_SPL_SPI_LOAD + if (dev_type == QSPI_DEV) { + struct spi_flash *flash = (struct spi_flash *)dev; + + ret = spi_flash_read(flash, offset, + CONTAINER_HDR_ALIGNMENT, buf); + if (ret != 0) { + printf("Read container image from QSPI failed\n"); + return -EIO; + } + } +#endif + +#ifdef CONFIG_SPL_NAND_SUPPORT + if (dev_type == NAND_DEV) { + ret = nand_spl_load_image(offset, CONTAINER_HDR_ALIGNMENT, + buf); + if (ret != 0) { + printf("Read container image from NAND failed\n"); + return -EIO; + } + } +#endif + +#ifdef CONFIG_SPL_NOR_SUPPORT + if (dev_type == QSPI_NOR_DEV) + memcpy(buf, (const void *)offset, CONTAINER_HDR_ALIGNMENT); +#endif + + ret = __get_container_size((ulong)buf); + + free(buf); + + return ret; +} + +static unsigned long get_boot_device_offset(void *dev, int dev_type) +{ + unsigned long offset = 0; + + if (dev_type == MMC_DEV) { + struct mmc *mmc = (struct mmc *)dev; + + if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) { + offset = CONTAINER_HDR_MMCSD_OFFSET; + } else { + u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config); + + if (part == 1 || part == 2) { + if (is_imx8qxp() && is_soc_rev(CHIP_REV_B)) + offset = CONTAINER_HDR_MMCSD_OFFSET; + else + offset = CONTAINER_HDR_EMMC_OFFSET; + } else { + offset = CONTAINER_HDR_MMCSD_OFFSET; + } + } + } else if (dev_type == QSPI_DEV) { + offset = CONTAINER_HDR_QSPI_OFFSET; + } else if (dev_type == NAND_DEV) { + offset = CONTAINER_HDR_NAND_OFFSET; + } else if (dev_type == QSPI_NOR_DEV) { + offset = CONTAINER_HDR_QSPI_OFFSET + 0x08000000; + } + + return offset; +} + +static int get_imageset_end(void *dev, int dev_type) +{ + unsigned long offset1 = 0, offset2 = 0; + int value_container[2]; + + offset1 = get_boot_device_offset(dev, dev_type); + offset2 = CONTAINER_HDR_ALIGNMENT + offset1; + + value_container[0] = get_container_size(dev, dev_type, offset1); + if (value_container[0] < 0) { + printf("Parse seco container failed %d\n", value_container[0]); + return value_container[0]; + } + + debug("seco container size 0x%x\n", value_container[0]); + + value_container[1] = get_container_size(dev, dev_type, offset2); + if (value_container[1] < 0) { + debug("Parse scu container failed %d, only seco container\n", + value_container[1]); + /* return seco container total size */ + return value_container[0] + offset1; + } + + debug("scu container size 0x%x\n", value_container[1]); + + return value_container[1] + offset2; +} + +#ifdef CONFIG_SPL_SPI_LOAD +unsigned long spl_spi_get_uboot_offs(struct spi_flash *flash) +{ + int end; + + end = get_imageset_end(flash, QSPI_DEV); + end = ROUND(end, SZ_1K); + + printf("Load image from QSPI 0x%x\n", end); + + return end; +} +#endif + +#ifdef CONFIG_SPL_MMC_SUPPORT +unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, + unsigned long raw_sect) +{ + int end; + + end = get_imageset_end(mmc, MMC_DEV); + end = ROUND(end, SZ_1K); + + printf("Load image from MMC/SD 0x%x\n", end); + + return end / mmc->read_bl_len; +} +#endif + +#ifdef CONFIG_SPL_NAND_SUPPORT +uint32_t spl_nand_get_uboot_raw_page(void) +{ + int end; + + end = get_imageset_end((void *)NULL, NAND_DEV); + end = ROUND(end, SZ_16K); + + printf("Load image from NAND 0x%x\n", end); + + return end; +} +#endif + +#ifdef CONFIG_SPL_NOR_SUPPORT +unsigned long spl_nor_get_uboot_base(void) +{ + int end; + + /* Calculate the image set end, + * if it is less than CONFIG_SYS_UBOOT_BASE(0x8281000), + * we use CONFIG_SYS_UBOOT_BASE + * Otherwise, use the calculated address + */ + end = get_imageset_end((void *)NULL, QSPI_NOR_DEV); + if (end <= CONFIG_SYS_UBOOT_BASE) + end = CONFIG_SYS_UBOOT_BASE; + else + end = ROUND(end, SZ_1K); + + printf("Load image from NOR 0x%x\n", end); + + return end; +} +#endif diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/iomux.c b/roms/u-boot/arch/arm/mach-imx/imx8/iomux.c new file mode 100644 index 000000000..9c3cfbf00 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/iomux.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include <common.h> +#include <log.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/sci/sci.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * configures a single pad in the iomuxer + */ +void imx8_iomux_setup_pad(iomux_cfg_t pad) +{ + sc_pad_t pin_id = pad & PIN_ID_MASK; + int ret; + + u32 val = (u32)((pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT); + + val |= PADRING_IFMUX_EN_MASK; + val |= PADRING_GP_EN_MASK; + + ret = sc_pad_set(-1, pin_id, val); + if (ret) + printf("sc_pad_set failed!, pin: %u, val: 0x%x\n", pin_id, val); + + debug("iomux: pin %d, val = 0x%x\n", pin_id, val); +} + +/* configures a list of pads within declared with IOMUX_PADS macro */ +void imx8_iomux_setup_multiple_pads(iomux_cfg_t const *pad_list, u32 count) +{ + iomux_cfg_t const *p = pad_list; + int i; + + for (i = 0; i < count; i++) { + imx8_iomux_setup_pad(*p); + p++; + } +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/lowlevel_init.S b/roms/u-boot/arch/arm/mach-imx/imx8/lowlevel_init.S new file mode 100644 index 000000000..a66243c5e --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/lowlevel_init.S @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 NXP + */ + +#include <config.h> + +.align 8 +.global boot_pointer +boot_pointer: + .space 32 + +/* + * Routine: save_boot_params (called after reset from start.S) + */ + +.global save_boot_params +save_boot_params: + /* The firmware provided ATAG/FDT address can be found in r2/x0 */ + adr x0, boot_pointer + stp x1, x2, [x0], #16 + stp x3, x4, [x0], #16 + + /* + * We use absolute address not PC relative address for return. + * When running SPL on iMX8, the A core starts at address 0, + * an alias to OCRAM 0x100000, our linker address for SPL is + * from 0x100000. So using absolute address can jump to the OCRAM + * address from the alias. The alias only map first 96KB of OCRAM, + * so this require the SPL size can't beyond 96KB. + * But when using SPL DM, the size increase significantly and + * always beyonds 96KB. That's why we have to jump to OCRAM. + * Normal u-boot also runs into this codes, but there is no impact. + */ + ldr x1, =save_boot_params_ret + br x1 diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/misc.c b/roms/u-boot/arch/arm/mach-imx/imx8/misc.c new file mode 100644 index 000000000..de19955e2 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/misc.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <common.h> +#include <log.h> +#include <asm/arch/sci/sci.h> +#include <asm/mach-imx/sys_proto.h> +#include <imx_sip.h> +#include <linux/arm-smccc.h> + +int sc_pm_setup_uart(sc_rsrc_t uart_rsrc, sc_pm_clock_rate_t clk_rate) +{ + sc_pm_clock_rate_t rate = clk_rate; + int ret; + + /* Power up UARTn */ + ret = sc_pm_set_resource_power_mode(-1, uart_rsrc, SC_PM_PW_MODE_ON); + if (ret) + return ret; + + /* Set UARTn clock root to 'rate' MHz */ + ret = sc_pm_set_clock_rate(-1, uart_rsrc, SC_PM_CLK_PER, &rate); + if (ret) + return ret; + + /* Enable UARTn clock root */ + ret = sc_pm_clock_enable(-1, uart_rsrc, SC_PM_CLK_PER, true, false); + if (ret) + return ret; + + return 0; +} + +void build_info(void) +{ + struct arm_smccc_res res; + u32 seco_build = 0, seco_commit = 0; + u32 sc_build = 0, sc_commit = 0; + ulong atf_commit = 0; + + /* Get SCFW build and commit id */ + sc_misc_build_info(-1, &sc_build, &sc_commit); + if (!sc_build) { + printf("SCFW does not support build info\n"); + sc_commit = 0; /* Display 0 if build info not supported */ + } + + /* Get SECO FW build and commit id */ + sc_seco_build_info(-1, &seco_build, &seco_commit); + if (!seco_build) { + debug("SECO FW does not support build info\n"); + /* Display 0 when the build info is not supported */ + seco_commit = 0; + } + + /* Get ARM Trusted Firmware commit id */ + arm_smccc_smc(IMX_SIP_BUILDINFO, IMX_SIP_BUILDINFO_GET_COMMITHASH, + 0, 0, 0, 0, 0, 0, &res); + atf_commit = res.a0; + if (atf_commit == 0xffffffff) { + debug("ATF does not support build info\n"); + atf_commit = 0x30; /* Display 0 */ + } + + printf("Build: SCFW %08x, SECO-FW %08x, ATF %s\n", + sc_commit, seco_commit, (char *)&atf_commit); +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/parse-container.c b/roms/u-boot/arch/arm/mach-imx/imx8/parse-container.c new file mode 100644 index 000000000..375098902 --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/parse-container.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018-2019 NXP + */ + +#include <common.h> +#include <errno.h> +#include <log.h> +#include <spl.h> +#include <asm/arch/image.h> +#include <asm/arch/sci/sci.h> + +#define SEC_SECURE_RAM_BASE 0x31800000UL +#define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) +#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE 0x60000000UL + +#define SECO_PT 2U + +#ifdef CONFIG_AHAB_BOOT +static int authenticate_image(struct boot_img_t *img, int image_index) +{ + sc_faddr_t start, end; + sc_rm_mr_t mr; + int err; + int ret = 0; + + debug("img %d, dst 0x%x, src 0x%x, size 0x%x\n", + image_index, (uint32_t)img->dst, img->offset, img->size); + + /* Find the memreg and set permission for seco pt */ + err = sc_rm_find_memreg(-1, &mr, + img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1), + ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1); + + if (err) { + printf("can't find memreg for image %d load address 0x%x, error %d\n", + image_index, img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1), err); + return -ENOMEM; + } + + err = sc_rm_get_memreg_info(-1, mr, &start, &end); + if (!err) + debug("memreg %u 0x%x -- 0x%x\n", mr, start, end); + + err = sc_rm_set_memreg_permissions(-1, mr, + SECO_PT, SC_RM_PERM_FULL); + if (err) { + printf("set permission failed for img %d, error %d\n", + image_index, err); + return -EPERM; + } + + err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE, + 1 << image_index); + if (err) { + printf("authenticate img %d failed, return %d\n", + image_index, err); + ret = -EIO; + } + + err = sc_rm_set_memreg_permissions(-1, mr, + SECO_PT, SC_RM_PERM_NONE); + if (err) { + printf("remove permission failed for img %d, error %d\n", + image_index, err); + ret = -EPERM; + } + + return ret; +} +#endif + +static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image, + struct spl_load_info *info, + struct container_hdr *container, + int image_index, + u32 container_sector) +{ + struct boot_img_t *images; + ulong sector; + u32 sectors; + + if (image_index > container->num_images) { + debug("Invalid image number\n"); + return NULL; + } + + images = (struct boot_img_t *)((u8 *)container + + sizeof(struct container_hdr)); + + if (images[image_index].offset % info->bl_len) { + printf("%s: image%d offset not aligned to %u\n", + __func__, image_index, info->bl_len); + return NULL; + } + + sectors = roundup(images[image_index].size, info->bl_len) / + info->bl_len; + sector = images[image_index].offset / info->bl_len + + container_sector; + + debug("%s: container: %p sector: %lu sectors: %u\n", __func__, + container, sector, sectors); + if (info->read(info, sector, sectors, + (void *)images[image_index].entry) != sectors) { + printf("%s wrong\n", __func__); + return NULL; + } + +#ifdef CONFIG_AHAB_BOOT + if (authenticate_image(&images[image_index], image_index)) { + printf("Failed to authenticate image %d\n", image_index); + return NULL; + } +#endif + + return &images[image_index]; +} + +static int read_auth_container(struct spl_image_info *spl_image, + struct spl_load_info *info, ulong sector) +{ + struct container_hdr *container = NULL; + u16 length; + u32 sectors; + int i, size, ret = 0; + + size = roundup(CONTAINER_HDR_ALIGNMENT, info->bl_len); + sectors = size / info->bl_len; + + /* + * It will not override the ATF code, so safe to use it here, + * no need malloc + */ + container = (struct container_hdr *)spl_get_load_buffer(-size, size); + + debug("%s: container: %p sector: %lu sectors: %u\n", __func__, + container, sector, sectors); + if (info->read(info, sector, sectors, container) != sectors) + return -EIO; + + if (container->tag != 0x87 && container->version != 0x0) { + printf("Wrong container header"); + return -ENOENT; + } + + if (!container->num_images) { + printf("Wrong container, no image found"); + return -ENOENT; + } + + length = container->length_lsb + (container->length_msb << 8); + debug("Container length %u\n", length); + + if (length > CONTAINER_HDR_ALIGNMENT) { + size = roundup(length, info->bl_len); + sectors = size / info->bl_len; + + container = (struct container_hdr *)spl_get_load_buffer(-size, size); + + debug("%s: container: %p sector: %lu sectors: %u\n", + __func__, container, sector, sectors); + if (info->read(info, sector, sectors, container) != + sectors) + return -EIO; + } + +#ifdef CONFIG_AHAB_BOOT + memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)container, + ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); + + ret = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER, + SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); + if (ret) { + printf("authenticate container hdr failed, return %d\n", ret); + return ret; + } +#endif + + for (i = 0; i < container->num_images; i++) { + struct boot_img_t *image = read_auth_image(spl_image, info, + container, i, + sector); + + if (!image) { + ret = -EINVAL; + goto end_auth; + } + + if (i == 0) { + spl_image->load_addr = image->dst; + spl_image->entry_point = image->entry; + } + } + +end_auth: +#ifdef CONFIG_AHAB_BOOT + if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0)) + printf("Error: release container failed!\n"); +#endif + return ret; +} + +int spl_load_imx_container(struct spl_image_info *spl_image, + struct spl_load_info *info, ulong sector) +{ + return read_auth_container(spl_image, info, sector); +} diff --git a/roms/u-boot/arch/arm/mach-imx/imx8/snvs_security_sc.c b/roms/u-boot/arch/arm/mach-imx/imx8/snvs_security_sc.c new file mode 100644 index 000000000..6f9b1c99f --- /dev/null +++ b/roms/u-boot/arch/arm/mach-imx/imx8/snvs_security_sc.c @@ -0,0 +1,925 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019-2020 NXP. + */ + +/* + * Configuration of the Tamper pins in different mode: + * - default (no tamper pins): _default_ + * - passive mode expecting VCC on the line: "_passive_vcc_" + * - passive mode expecting VCC on the line: "_passive_gnd_" + * - active mode: "_active_" + */ + +#include <command.h> +#include <log.h> +#include <stddef.h> +#include <common.h> +#include <asm/arch/sci/sci.h> +#include <asm/arch-imx8/imx8-pins.h> +#include <asm/arch-imx8/snvs_security_sc.h> +#include <asm/global_data.h> + +/* Access to gd */ +DECLARE_GLOBAL_DATA_PTR; + +#define SC_WRITE_CONF 1 + +#define PGD_HEX_VALUE 0x41736166 +#define SRTC_EN 0x1 +#define DP_EN BIT(5) + +struct snvs_security_sc_conf { + struct snvs_hp_conf { + u32 lock; /* HPLR - HP Lock */ + u32 __cmd; /* HPCOMR - HP Command */ + u32 __ctl; /* HPCR - HP Control */ + u32 secvio_intcfg; /* HPSICR - Security Violation Int + * Config + */ + u32 secvio_ctl; /* HPSVCR - Security Violation Control*/ + u32 status; /* HPSR - HP Status */ + u32 secvio_status; /* HPSVSR - Security Violation Status */ + u32 __ha_counteriv; /* High Assurance Counter IV */ + u32 __ha_counter; /* High Assurance Counter */ + u32 __rtc_msb; /* Real Time Clock/Counter MSB */ + u32 __rtc_lsb; /* Real Time Counter LSB */ + u32 __time_alarm_msb; /* Time Alarm MSB */ + u32 __time_alarm_lsb; /* Time Alarm LSB */ + } hp; + struct snvs_lp_conf { + u32 lock; + u32 __ctl; + u32 __mstr_key_ctl; /* Master Key Control */ + u32 secvio_ctl; /* Security Violation Control */ + u32 tamper_filt_cfg; /* Tamper Glitch Filters Configuration*/ + u32 tamper_det_cfg; /* Tamper Detectors Configuration */ + u32 status; + u32 __srtc_msb; /* Secure Real Time Clock/Counter MSB */ + u32 __srtc_lsb; /* Secure Real Time Clock/Counter LSB */ + u32 __time_alarm; /* Time Alarm */ + u32 __smc_msb; /* Secure Monotonic Counter MSB */ + u32 __smc_lsb; /* Secure Monotonic Counter LSB */ + u32 __pwr_glitch_det; /* Power Glitch Detector */ + u32 __gen_purpose; + u8 __zmk[32]; /* Zeroizable Master Key */ + u32 __rsvd0; + u32 __gen_purposes[4]; /* gp0_30 to gp0_33 */ + u32 tamper_det_cfg2; /* Tamper Detectors Configuration2 */ + u32 tamper_det_status; /* Tamper Detectors status */ + u32 tamper_filt1_cfg; /* Tamper Glitch Filter1 Configuration*/ + u32 tamper_filt2_cfg; /* Tamper Glitch Filter2 Configuration*/ + u32 __rsvd1[4]; + u32 act_tamper1_cfg; /* Active Tamper1 Configuration */ + u32 act_tamper2_cfg; /* Active Tamper2 Configuration */ + u32 act_tamper3_cfg; /* Active Tamper3 Configuration */ + u32 act_tamper4_cfg; /* Active Tamper4 Configuration */ + u32 act_tamper5_cfg; /* Active Tamper5 Configuration */ + u32 __rsvd2[3]; + u32 act_tamper_ctl; /* Active Tamper Control */ + u32 act_tamper_clk_ctl; /* Active Tamper Clock Control */ + u32 act_tamper_routing_ctl1;/* Active Tamper Routing Control1 */ + u32 act_tamper_routing_ctl2;/* Active Tamper Routing Control2 */ + } lp; +}; + +static struct snvs_security_sc_conf snvs_default_config = { + .hp = { + .lock = 0x1f0703ff, + .secvio_ctl = 0x3000007f, + }, + .lp = { + .lock = 0x1f0003ff, + .secvio_ctl = 0x36, + .tamper_filt_cfg = 0, + .tamper_det_cfg = 0x76, /* analogic tampers + * + rollover tampers + */ + .tamper_det_cfg2 = 0, + .tamper_filt1_cfg = 0, + .tamper_filt2_cfg = 0, + .act_tamper1_cfg = 0, + .act_tamper2_cfg = 0, + .act_tamper3_cfg = 0, + .act_tamper4_cfg = 0, + .act_tamper5_cfg = 0, + .act_tamper_ctl = 0, + .act_tamper_clk_ctl = 0, + .act_tamper_routing_ctl1 = 0, + .act_tamper_routing_ctl2 = 0, + } +}; + +static struct snvs_security_sc_conf snvs_passive_vcc_config = { + .hp = { + .lock = 0x1f0703ff, + .secvio_ctl = 0x3000007f, + }, + .lp = { + .lock = 0x1f0003ff, + .secvio_ctl = 0x36, + .tamper_filt_cfg = 0, + .tamper_det_cfg = 0x276, /* ET1 will trig on line at GND + * + analogic tampers + * + rollover tampers + */ + .tamper_det_cfg2 = 0, + .tamper_filt1_cfg = 0, + .tamper_filt2_cfg = 0, + .act_tamper1_cfg = 0, + .act_tamper2_cfg = 0, + .act_tamper3_cfg = 0, + .act_tamper4_cfg = 0, + .act_tamper5_cfg = 0, + .act_tamper_ctl = 0, + .act_tamper_clk_ctl = 0, + .act_tamper_routing_ctl1 = 0, + .act_tamper_routing_ctl2 = 0, + } +}; + +static struct snvs_security_sc_conf snvs_passive_gnd_config = { + .hp = { + .lock = 0x1f0703ff, + .secvio_ctl = 0x3000007f, + }, + .lp = { + .lock = 0x1f0003ff, + .secvio_ctl = 0x36, + .tamper_filt_cfg = 0, + .tamper_det_cfg = 0xa76, /* ET1 will trig on line at VCC + * + analogic tampers + * + rollover tampers + */ + .tamper_det_cfg2 = 0, + .tamper_filt1_cfg = 0, + .tamper_filt2_cfg = 0, + .act_tamper1_cfg = 0, + .act_tamper2_cfg = 0, + .act_tamper3_cfg = 0, + .act_tamper4_cfg = 0, + .act_tamper5_cfg = 0, + .act_tamper_ctl = 0, + .act_tamper_clk_ctl = 0, + .act_tamper_routing_ctl1 = 0, + .act_tamper_routing_ctl2 = 0, + } +}; + +static struct snvs_security_sc_conf snvs_active_config = { + .hp = { + .lock = 0x1f0703ff, + .secvio_ctl = 0x3000007f, + }, + .lp = { + .lock = 0x1f0003ff, + .secvio_ctl = 0x36, + .tamper_filt_cfg = 0x00800000, /* Enable filtering */ + .tamper_det_cfg = 0x276, /* ET1 enabled + analogic tampers + * + rollover tampers + */ + .tamper_det_cfg2 = 0, + .tamper_filt1_cfg = 0, + .tamper_filt2_cfg = 0, + .act_tamper1_cfg = 0x84001111, + .act_tamper2_cfg = 0, + .act_tamper3_cfg = 0, + .act_tamper4_cfg = 0, + .act_tamper5_cfg = 0, + .act_tamper_ctl = 0x00010001, + .act_tamper_clk_ctl = 0, + .act_tamper_routing_ctl1 = 0x1, + .act_tamper_routing_ctl2 = 0, + } +}; + +static struct snvs_security_sc_conf *get_snvs_config(void) +{ + return &snvs_default_config; +} + +struct snvs_dgo_conf { + u32 tamper_offset_ctl; + u32 tamper_pull_ctl; + u32 tamper_ana_test_ctl; + u32 tamper_sensor_trim_ctl; + u32 tamper_misc_ctl; + u32 tamper_core_volt_mon_ctl; +}; + +static struct snvs_dgo_conf snvs_dgo_default_config = { + .tamper_misc_ctl = 0x80000000, /* Lock the DGO */ +}; + +static struct snvs_dgo_conf snvs_dgo_passive_vcc_config = { + .tamper_misc_ctl = 0x80000000, /* Lock the DGO */ + .tamper_pull_ctl = 0x00000001, /* Pull down ET1 */ + .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */ +}; + +static struct snvs_dgo_conf snvs_dgo_passive_gnd_config = { + .tamper_misc_ctl = 0x80000000, /* Lock the DGO */ + .tamper_pull_ctl = 0x00000401, /* Pull up ET1 */ + .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */ +}; + +static struct snvs_dgo_conf snvs_dgo_active_config = { + .tamper_misc_ctl = 0x80000000, /* Lock the DGO */ + .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */ +}; + +static struct snvs_dgo_conf *get_snvs_dgo_config(void) +{ + return &snvs_dgo_default_config; +} + +struct tamper_pin_cfg { + u32 pad; + u32 mux_conf; +}; + +static struct tamper_pin_cfg tamper_pin_list_default_config[] = { + {SC_P_CSI_D00, 0}, /* Tamp_Out0 */ + {SC_P_CSI_D01, 0}, /* Tamp_Out1 */ + {SC_P_CSI_D02, 0}, /* Tamp_Out2 */ + {SC_P_CSI_D03, 0}, /* Tamp_Out3 */ + {SC_P_CSI_D04, 0}, /* Tamp_Out4 */ + {SC_P_CSI_D05, 0}, /* Tamp_In0 */ + {SC_P_CSI_D06, 0}, /* Tamp_In1 */ + {SC_P_CSI_D07, 0}, /* Tamp_In2 */ + {SC_P_CSI_HSYNC, 0}, /* Tamp_In3 */ + {SC_P_CSI_VSYNC, 0}, /* Tamp_In4 */ +}; + +static struct tamper_pin_cfg tamper_pin_list_passive_vcc_config[] = { + {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */ +}; + +static struct tamper_pin_cfg tamper_pin_list_passive_gnd_config[] = { + {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */ +}; + +static struct tamper_pin_cfg tamper_pin_list_active_config[] = { + {SC_P_CSI_D00, 0x1a000060}, /* Tamp_Out0 */ /* Sel tamper + OD */ + {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */ +}; + +#define TAMPER_PIN_LIST_CHOSEN tamper_pin_list_default_config + +static struct tamper_pin_cfg *get_tamper_pin_cfg_list(u32 *size) +{ + *size = sizeof(TAMPER_PIN_LIST_CHOSEN) / + sizeof(TAMPER_PIN_LIST_CHOSEN[0]); + + return TAMPER_PIN_LIST_CHOSEN; +} + +#define SC_CONF_OFFSET_OF(_field) \ + (offsetof(struct snvs_security_sc_conf, _field)) + +static u32 ptr_value(u32 *_p) +{ + return (_p) ? *_p : 0xdeadbeef; +} + +static int check_write_secvio_config(u32 id, u32 *_p1, u32 *_p2, + u32 *_p3, u32 *_p4, u32 *_p5, + u32 _cnt) +{ + int scierr = 0; + u32 d1 = ptr_value(_p1); + u32 d2 = ptr_value(_p2); + u32 d3 = ptr_value(_p3); + u32 d4 = ptr_value(_p4); + u32 d5 = ptr_value(_p5); + + scierr = sc_seco_secvio_config(-1, id, SC_WRITE_CONF, &d1, &d2, &d3, + &d4, &d4, _cnt); + if (scierr != SC_ERR_NONE) { + printf("Failed to set secvio configuration\n"); + debug("Failed to set conf id 0x%x with values ", id); + debug("0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x (cnt: %d)\n", + d1, d2, d3, d4, d5, _cnt); + goto exit; + } + + if (_p1) + *(u32 *)_p1 = d1; + if (_p2) + *(u32 *)_p2 = d2; + if (_p3) + *(u32 *)_p3 = d3; + if (_p4) + *(u32 *)_p4 = d4; + if (_p5) + *(u32 *)_p5 = d5; + +exit: + return scierr; +} + +#define SC_CHECK_WRITE1(id, _p1) \ + check_write_secvio_config(id, _p1, NULL, NULL, NULL, NULL, 1) + +static int apply_snvs_config(struct snvs_security_sc_conf *cnf) +{ + int scierr = 0; + + debug("%s\n", __func__); + + debug("Applying config:\n" + "\thp.lock = 0x%.8x\n" + "\thp.secvio_ctl = 0x%.8x\n" + "\tlp.lock = 0x%.8x\n" + "\tlp.secvio_ctl = 0x%.8x\n" + "\tlp.tamper_filt_cfg = 0x%.8x\n" + "\tlp.tamper_det_cfg = 0x%.8x\n" + "\tlp.tamper_det_cfg2 = 0x%.8x\n" + "\tlp.tamper_filt1_cfg = 0x%.8x\n" + "\tlp.tamper_filt2_cfg = 0x%.8x\n" + "\tlp.act_tamper1_cfg = 0x%.8x\n" + "\tlp.act_tamper2_cfg = 0x%.8x\n" + "\tlp.act_tamper3_cfg = 0x%.8x\n" + "\tlp.act_tamper4_cfg = 0x%.8x\n" + "\tlp.act_tamper5_cfg = 0x%.8x\n" + "\tlp.act_tamper_ctl = 0x%.8x\n" + "\tlp.act_tamper_clk_ctl = 0x%.8x\n" + "\tlp.act_tamper_routing_ctl1 = 0x%.8x\n" + "\tlp.act_tamper_routing_ctl2 = 0x%.8x\n", + cnf->hp.lock, + cnf->hp.secvio_ctl, + cnf->lp.lock, + cnf->lp.secvio_ctl, + cnf->lp.tamper_filt_cfg, + cnf->lp.tamper_det_cfg, + cnf->lp.tamper_det_cfg2, + cnf->lp.tamper_filt1_cfg, + cnf->lp.tamper_filt2_cfg, + cnf->lp.act_tamper1_cfg, + cnf->lp.act_tamper2_cfg, + cnf->lp.act_tamper3_cfg, + cnf->lp.act_tamper4_cfg, + cnf->lp.act_tamper5_cfg, + cnf->lp.act_tamper_ctl, + cnf->lp.act_tamper_clk_ctl, + cnf->lp.act_tamper_routing_ctl1, + cnf->lp.act_tamper_routing_ctl2); + + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_filt_cfg), + &cnf->lp.tamper_filt_cfg, + &cnf->lp.tamper_filt1_cfg, + &cnf->lp.tamper_filt2_cfg, NULL, + NULL, 3); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Configure AT */ + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper1_cfg), + &cnf->lp.act_tamper1_cfg, + &cnf->lp.act_tamper2_cfg, + &cnf->lp.act_tamper2_cfg, + &cnf->lp.act_tamper2_cfg, + &cnf->lp.act_tamper2_cfg, 5); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Configure AT routing */ + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper_routing_ctl1), + &cnf->lp.act_tamper_routing_ctl1, + &cnf->lp.act_tamper_routing_ctl2, + NULL, NULL, NULL, 2); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Configure AT frequency */ + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_clk_ctl), + &cnf->lp.act_tamper_clk_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Activate the ATs */ + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_ctl), + &cnf->lp.act_tamper_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Activate the detectors */ + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_cfg), + &cnf->lp.tamper_det_cfg, + &cnf->lp.tamper_det_cfg2, NULL, NULL, + NULL, 2); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Configure LP secvio */ + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.secvio_ctl), + &cnf->lp.secvio_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Configure HP secvio */ + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.secvio_ctl), + &cnf->hp.secvio_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Lock access */ + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.lock), &cnf->hp.lock); + if (scierr != SC_ERR_NONE) + goto exit; + + scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.lock), &cnf->lp.lock); + if (scierr != SC_ERR_NONE) + goto exit; + +exit: + return (scierr == SC_ERR_NONE) ? 0 : -EIO; +} + +static int dgo_write(u32 _id, u8 _access, u32 *_pdata) +{ + int scierr = sc_seco_secvio_dgo_config(-1, _id, _access, _pdata); + + if (scierr != SC_ERR_NONE) { + printf("Failed to set dgo configuration\n"); + debug("Failed to set conf id 0x%x : 0x%.8x", _id, *_pdata); + } + + return scierr; +} + +static int apply_snvs_dgo_config(struct snvs_dgo_conf *cnf) +{ + int scierr = 0; + + debug("%s\n", __func__); + + debug("Applying config:\n" + "\ttamper_offset_ctl = 0x%.8x\n" + "\ttamper_pull_ctl = 0x%.8x\n" + "\ttamper_ana_test_ctl = 0x%.8x\n" + "\ttamper_sensor_trim_ctl = 0x%.8x\n" + "\ttamper_misc_ctl = 0x%.8x\n" + "\ttamper_core_volt_mon_ctl = 0x%.8x\n", + cnf->tamper_offset_ctl, + cnf->tamper_pull_ctl, + cnf->tamper_ana_test_ctl, + cnf->tamper_sensor_trim_ctl, + cnf->tamper_misc_ctl, + cnf->tamper_core_volt_mon_ctl); + + dgo_write(0x04, 1, &cnf->tamper_offset_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + dgo_write(0x14, 1, &cnf->tamper_pull_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + dgo_write(0x24, 1, &cnf->tamper_ana_test_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + dgo_write(0x34, 1, &cnf->tamper_sensor_trim_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + dgo_write(0x54, 1, &cnf->tamper_core_volt_mon_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + + /* Last as it could lock the writes */ + dgo_write(0x44, 1, &cnf->tamper_misc_ctl); + if (scierr != SC_ERR_NONE) + goto exit; + +exit: + return (scierr == SC_ERR_NONE) ? 0 : -EIO; +} + +static int pad_write(u32 _pad, u32 _value) +{ + int scierr = sc_pad_set(-1, _pad, _value); + + if (scierr != SC_ERR_NONE) { + printf("Failed to set pad configuration\n"); + debug("Failed to set conf pad 0x%x : 0x%.8x", _pad, _value); + } + + return scierr; +} + +static int apply_tamper_pin_list_config(struct tamper_pin_cfg *confs, u32 size) +{ + int scierr = 0; + u32 idx; + + debug("%s\n", __func__); + + for (idx = 0; idx < size; idx++) { + debug("\t idx %d: pad %d: 0x%.8x\n", idx, confs[idx].pad, + confs[idx].mux_conf); + pad_write(confs[idx].pad, 3 << 30 | confs[idx].mux_conf); + if (scierr != SC_ERR_NONE) + goto exit; + } + +exit: + return (scierr == SC_ERR_NONE) ? 0 : -EIO; +} + +int examples(void) +{ + u32 size; + struct snvs_security_sc_conf *snvs_conf; + struct snvs_dgo_conf *snvs_dgo_conf; + struct tamper_pin_cfg *tamper_pin_conf; + + /* Caller */ + snvs_conf = get_snvs_config(); + snvs_dgo_conf = get_snvs_dgo_config(); + tamper_pin_conf = get_tamper_pin_cfg_list(&size); + + /* Default */ + snvs_conf = &snvs_default_config; + snvs_dgo_conf = &snvs_dgo_default_config; + tamper_pin_conf = tamper_pin_list_default_config; + + /* Passive tamper expecting VCC on the line */ + snvs_conf = &snvs_passive_vcc_config; + snvs_dgo_conf = &snvs_dgo_passive_vcc_config; + tamper_pin_conf = tamper_pin_list_passive_vcc_config; + + /* Passive tamper expecting GND on the line */ + snvs_conf = &snvs_passive_gnd_config; + snvs_dgo_conf = &snvs_dgo_passive_gnd_config; + tamper_pin_conf = tamper_pin_list_passive_gnd_config; + + /* Active tamper */ + snvs_conf = &snvs_active_config; + snvs_dgo_conf = &snvs_dgo_active_config; + tamper_pin_conf = tamper_pin_list_active_config; + + return !snvs_conf + !snvs_dgo_conf + !tamper_pin_conf; +} + +#ifdef CONFIG_IMX_SNVS_SEC_SC_AUTO +int snvs_security_sc_init(void) +{ + int err = 0; + + struct snvs_security_sc_conf *snvs_conf; + struct snvs_dgo_conf *snvs_dgo_conf; + struct tamper_pin_cfg *tamper_pin_conf; + u32 size; + + debug("%s\n", __func__); + + snvs_conf = get_snvs_config(); + snvs_dgo_conf = get_snvs_dgo_config(); + + tamper_pin_conf = get_tamper_pin_cfg_list(&size); + + err = apply_tamper_pin_list_config(tamper_pin_conf, size); + if (err) { + debug("Failed to set pins\n"); + goto exit; + } + + err = apply_snvs_dgo_config(snvs_dgo_conf); + if (err) { + debug("Failed to set dgo\n"); + goto exit; + } + + err = apply_snvs_config(snvs_conf); + if (err) { + debug("Failed to set snvs\n"); + goto exit; + } + +exit: + return err; +} +#endif /* CONFIG_IMX_SNVS_SEC_SC_AUTO */ + +static char snvs_cfg_help_text[] = + "snvs_cfg\n" + "\thp.lock\n" + "\thp.secvio_ctl\n" + "\tlp.lock\n" + "\tlp.secvio_ctl\n" + "\tlp.tamper_filt_cfg\n" + "\tlp.tamper_det_cfg\n" + "\tlp.tamper_det_cfg2\n" + "\tlp.tamper_filt1_cfg\n" + "\tlp.tamper_filt2_cfg\n" + "\tlp.act_tamper1_cfg\n" + "\tlp.act_tamper2_cfg\n" + "\tlp.act_tamper3_cfg\n" + "\tlp.act_tamper4_cfg\n" + "\tlp.act_tamper5_cfg\n" + "\tlp.act_tamper_ctl\n" + "\tlp.act_tamper_clk_ctl\n" + "\tlp.act_tamper_routing_ctl1\n" + "\tlp.act_tamper_routing_ctl2\n" + "\n" + "ALL values should be in hexadecimal format"; + +#define NB_REGISTERS 18 +static int do_snvs_cfg(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int err = 0; + u32 idx = 0; + + struct snvs_security_sc_conf conf = {0}; + + if (argc != (NB_REGISTERS + 1)) + return CMD_RET_USAGE; + + conf.hp.lock = simple_strtoul(argv[++idx], NULL, 16); + conf.hp.secvio_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.lock = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.secvio_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_filt_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_det_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_det_cfg2 = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_filt1_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_filt2_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper1_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper2_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper3_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper4_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper5_cfg = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper_clk_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper_routing_ctl1 = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.act_tamper_routing_ctl2 = simple_strtoul(argv[++idx], NULL, 16); + + err = apply_snvs_config(&conf); + + return err; +} + +U_BOOT_CMD(snvs_cfg, + NB_REGISTERS + 1, 1, do_snvs_cfg, + "Security violation configuration", + snvs_cfg_help_text +); + +static char snvs_dgo_cfg_help_text[] = + "snvs_dgo_cfg\n" + "\ttamper_offset_ctl\n" + "\ttamper_pull_ctl\n" + "\ttamper_ana_test_ctl\n" + "\ttamper_sensor_trim_ctl\n" + "\ttamper_misc_ctl\n" + "\ttamper_core_volt_mon_ctl\n" + "\n" + "ALL values should be in hexadecimal format"; + +static int do_snvs_dgo_cfg(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int err = 0; + u32 idx = 0; + + struct snvs_dgo_conf conf = {0}; + + if (argc != (6 + 1)) + return CMD_RET_USAGE; + + conf.tamper_offset_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.tamper_pull_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.tamper_ana_test_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.tamper_sensor_trim_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.tamper_misc_ctl = simple_strtoul(argv[++idx], NULL, 16); + conf.tamper_core_volt_mon_ctl = simple_strtoul(argv[++idx], NULL, 16); + + err = apply_snvs_dgo_config(&conf); + + return err; +} + +U_BOOT_CMD(snvs_dgo_cfg, + 7, 1, do_snvs_dgo_cfg, + "SNVS DGO configuration", + snvs_dgo_cfg_help_text +); + +static char tamper_pin_cfg_help_text[] = + "snvs_dgo_cfg\n" + "\tpad\n" + "\tvalue\n" + "\n" + "ALL values should be in hexadecimal format"; + +static int do_tamper_pin_cfg(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int err = 0; + u32 idx = 0; + + struct tamper_pin_cfg conf = {0}; + + if (argc != (2 + 1)) + return CMD_RET_USAGE; + + conf.pad = simple_strtoul(argv[++idx], NULL, 10); + conf.mux_conf = simple_strtoul(argv[++idx], NULL, 16); + + err = apply_tamper_pin_list_config(&conf, 1); + + return err; +} + +U_BOOT_CMD(tamper_pin_cfg, + 3, 1, do_tamper_pin_cfg, + "tamper pin configuration", + tamper_pin_cfg_help_text +); + +static char snvs_clear_status_help_text[] = + "snvs_clear_status\n" + "\tHPSR\n" + "\tHPSVSR\n" + "\tLPSR\n" + "\tLPTDSR\n" + "\n" + "Write the status registers with the value provided," + " clearing the status"; + +static int do_snvs_clear_status(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int scierr = 0; + u32 idx = 0; + + struct snvs_security_sc_conf conf = {0}; + + if (argc != (2 + 1)) + return CMD_RET_USAGE; + + conf.lp.status = simple_strtoul(argv[++idx], NULL, 16); + conf.lp.tamper_det_status = simple_strtoul(argv[++idx], NULL, 16); + + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.status), + &conf.lp.status, NULL, NULL, NULL, + NULL, 1); + if (scierr != SC_ERR_NONE) + goto exit; + + scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_status), + &conf.lp.tamper_det_status, NULL, + NULL, NULL, NULL, 1); + if (scierr != SC_ERR_NONE) + goto exit; + +exit: + return (scierr == SC_ERR_NONE) ? 0 : 1; +} + +U_BOOT_CMD(snvs_clear_status, + 3, 1, do_snvs_clear_status, + "snvs clear status", + snvs_clear_status_help_text +); + +static char snvs_sec_status_help_text[] = + "snvs_sec_status\n" + "Display information about the security related to tamper and secvio"; + +static int do_snvs_sec_status(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int scierr; + u32 idx; + + u32 data[5]; + + u32 pads[] = { + SC_P_CSI_D00, + SC_P_CSI_D01, + SC_P_CSI_D02, + SC_P_CSI_D03, + SC_P_CSI_D04, + SC_P_CSI_D05, + SC_P_CSI_D06, + SC_P_CSI_D07, + SC_P_CSI_HSYNC, + SC_P_CSI_VSYNC, + }; + + u32 fuses[] = { + 14, + 30, + 31, + 260, + 261, + 262, + 263, + 768, + }; + + struct snvs_reg { + u32 id; + u32 nb; + } snvs[] = { + /* Locks */ + {0x0, 1}, + {0x34, 1}, + /* Security violation */ + {0xc, 1}, + {0x10, 1}, + {0x18, 1}, + {0x40, 1}, + /* Temper detectors */ + {0x48, 2}, + {0x4c, 1}, + {0xa4, 1}, + /* */ + {0x44, 3}, + {0xe0, 1}, + {0xe4, 1}, + {0xe8, 2}, + /* Misc */ + {0x3c, 1}, + {0x5c, 2}, + {0x64, 1}, + {0xf8, 2}, + }; + + u32 dgo[] = { + 0x0, + 0x10, + 0x20, + 0x30, + 0x40, + 0x50, + }; + + /* Pins */ + printf("Pins:\n"); + for (idx = 0; idx < ARRAY_SIZE(pads); idx++) { + u8 pad_id = pads[idx]; + + scierr = sc_pad_get(-1, pad_id, &data[0]); + if (scierr == 0) + printf("\t- Pin %d: %.8x\n", pad_id, data[0]); + else + printf("Failed to read Pin %d\n", pad_id); + } + + /* Fuses */ + printf("Fuses:\n"); + for (idx = 0; idx < ARRAY_SIZE(fuses); idx++) { + u32 fuse_id = fuses[idx]; + + scierr = sc_misc_otp_fuse_read(-1, fuse_id, &data[0]); + if (scierr == 0) + printf("\t- Fuse %d: %.8x\n", fuse_id, data[0]); + else + printf("Failed to read Fuse %d\n", fuse_id); + } + + /* SNVS */ + printf("SNVS:\n"); + for (idx = 0; idx < ARRAY_SIZE(snvs); idx++) { + struct snvs_reg *reg = &snvs[idx]; + + scierr = sc_seco_secvio_config(-1, reg->id, 0, &data[0], + &data[1], &data[2], &data[3], + &data[4], reg->nb); + if (scierr == 0) { + int subidx; + + printf("\t- SNVS %.2x(%d):", reg->id, reg->nb); + for (subidx = 0; subidx < reg->nb; subidx++) + printf(" %.8x", data[subidx]); + printf("\n"); + } else { + printf("Failed to read SNVS %d\n", reg->id); + } + } + + /* DGO */ + printf("DGO:\n"); + for (idx = 0; idx < ARRAY_SIZE(dgo); idx++) { + u8 dgo_id = dgo[idx]; + + scierr = sc_seco_secvio_dgo_config(-1, dgo_id, 0, &data[0]); + if (scierr == 0) + printf("\t- DGO %.2x: %.8x\n", dgo_id, data[0]); + else + printf("Failed to read DGO %d\n", dgo_id); + } + + return 0; +} + +U_BOOT_CMD(snvs_sec_status, + 1, 1, do_snvs_sec_status, + "tamper pin configuration", + snvs_sec_status_help_text +); |