aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r--arch/arm/mach-imx/Kconfig44
-rw-r--r--arch/arm/mach-imx/Makefile3
-rw-r--r--arch/arm/mach-imx/cmd_dek.c262
-rw-r--r--arch/arm/mach-imx/cmd_mfgprot.c150
-rw-r--r--arch/arm/mach-imx/cpu.c8
-rw-r--r--arch/arm/mach-imx/hab.c417
-rw-r--r--arch/arm/mach-imx/imx8/Kconfig1
-rw-r--r--arch/arm/mach-imx/imx8m/Kconfig11
-rw-r--r--arch/arm/mach-imx/imx8m/clock_imx8mm.c8
-rw-r--r--arch/arm/mach-imx/imx8m/clock_imx8mq.c7
-rw-r--r--arch/arm/mach-imx/imx8m/soc.c190
-rw-r--r--arch/arm/mach-imx/imx_bootaux.c67
-rw-r--r--arch/arm/mach-imx/mx7ulp/Kconfig1
-rw-r--r--arch/arm/mach-imx/priblob.c33
14 files changed, 1111 insertions, 91 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 8f64e23195..26bfc5ccc4 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -43,9 +43,9 @@ config USE_IMXIMG_PLUGIN
config IMX_HAB
bool "Support i.MX HAB features"
- depends on ARCH_MX7 || ARCH_MX6 || ARCH_MX5
+ depends on ARCH_MX7 || ARCH_MX6 || ARCH_MX5 || ARCH_IMX8M
select FSL_CAAM if HAS_CAAM
- imply CMD_DEKBLOB
+ imply CMD_DEKBLOB if HAS_CAAM
help
This option enables the support for secure boot (HAB).
See doc/imx/habv4/* for more details.
@@ -75,12 +75,43 @@ config CMD_BMODE
config CMD_DEKBLOB
bool "Support the 'dek_blob' command"
+ select IMX_CAAM_DEK_ENCAP if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP
+ select IMX_OPTEE_DEK_ENCAP if ARCH_IMX8M
+ select IMX_SECO_DEK_ENCAP if ARCH_IMX8
help
This enables the 'dek_blob' command which is used with the
Freescale secure boot mechanism. This command encapsulates and
creates a blob of data. See also CMD_BLOB and doc/imx/habv4/* for
more information.
+config IMX_CAAM_DEK_ENCAP
+ bool "Support the DEK blob encapsulation with CAAM U-Boot driver"
+ help
+ This enables the DEK blob encapsulation with the U-Boot CAAM driver.
+ This option is only available on imx6, imx7 and imx7ulp.
+
+config IMX_OPTEE_DEK_ENCAP
+ select TEE
+ select OPTEE
+ bool "Support the DEK blob encapsulation with OP-TEE"
+ help
+ This enabled the DEK blob encapsulation with OP-TEE. The communication
+ with OP-TEE is done through a SMC call and OP-TEE shared memory. This
+ option is available on imx8mm.
+
+config IMX_SECO_DEK_ENCAP
+ bool "Support the DEK blob encapsulation with SECO"
+ help
+ This enabled the DEK blob encapsulation with the SECO API. This option
+ is only available on imx8.
+
+config CMD_PRIBLOB
+ bool "Support the set_priblob_bitfield command"
+ depends on HAS_CAAM && IMX_HAB
+ help
+ This option enables the priblob command which can be used
+ to set the priblob setting to 0x3.
+
config CMD_HDMIDETECT
bool "Support the 'hdmidet' command"
help
@@ -99,6 +130,15 @@ config CMD_NANDBCB
This is similar to kobs-ng, which is used in Linux as separate
rootfs package.
+config FSL_MFGPROT
+ bool "Support the 'mfgprot' command"
+ depends on IMX_HAB && ARCH_MX7
+ help
+ This option enables the manufacturing protection command
+ which can be used has a protection feature for Manufacturing
+ process. With this tool is possible to authenticate the
+ chip to the OEM's server.
+
config NXP_BOARD_REVISION
bool "Read NXP board revision from fuses"
depends on ARCH_MX6 || ARCH_MX7
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index e6b4654cd3..82aa39dee7 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -16,6 +16,7 @@ endif
obj-$(CONFIG_ENV_IS_IN_MMC) += mmc_env.o
obj-$(CONFIG_FEC_MXC) += mac.o
obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o
+obj-$(CONFIG_IMX_HAB) += hab.o
obj-y += cpu.o
endif
@@ -29,12 +30,14 @@ obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o
endif
ifeq ($(SOC),$(filter $(SOC),mx7 mx6 mxs imx8m imx8 imxrt))
obj-y += misc.o
+obj-$(CONFIG_CMD_PRIBLOB) += priblob.o
obj-$(CONFIG_SPL_BUILD) += spl.o
endif
ifeq ($(SOC),$(filter $(SOC),mx7))
obj-y += cpu.o
obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o
obj-$(CONFIG_ENV_IS_IN_MMC) += mmc_env.o
+obj-$(CONFIG_FSL_MFGPROT) += cmd_mfgprot.o
endif
ifeq ($(SOC),$(filter $(SOC),mx5 mx6 mx7))
obj-$(CONFIG_IMX_VIDEO_SKIP) += video.o
diff --git a/arch/arm/mach-imx/cmd_dek.c b/arch/arm/mach-imx/cmd_dek.c
index 49dd473af7..b10ead1942 100644
--- a/arch/arm/mach-imx/cmd_dek.c
+++ b/arch/arm/mach-imx/cmd_dek.c
@@ -14,6 +14,12 @@
#include <fsl_sec.h>
#include <asm/arch/clock.h>
#include <mapmem.h>
+#include <tee.h>
+#ifdef CONFIG_IMX_SECO_DEK_ENCAP
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/image.h>
+#endif
+#include <cpu_func.h>
/**
* blob_dek() - Encapsulate the DEK as a blob using CAM's Key
@@ -23,16 +29,20 @@
*
* Returns zero on success,and negative on error.
*/
-static int blob_encap_dek(const u8 *src, u8 *dst, u32 len)
+#ifdef CONFIG_IMX_CAAM_DEK_ENCAP
+static int blob_encap_dek(u32 src_addr, u32 dst_addr, u32 len)
{
- int ret = 0;
- u32 jr_size = 4;
+ u8 *src_ptr, *dst_ptr;
+
+ src_ptr = map_sysmem(src_addr, len / 8);
+ dst_ptr = map_sysmem(dst_addr, BLOB_SIZE(len / 8));
+
+ hab_caam_clock_enable(1);
- u32 out_jr_size = sec_in32(CONFIG_SYS_FSL_JR0_ADDR + 0x102c);
- if (out_jr_size != jr_size) {
- hab_caam_clock_enable(1);
+ u32 out_jr_size = sec_in32(CONFIG_SYS_FSL_JR0_ADDR +
+ FSL_CAAM_ORSR_JRa_OFFSET);
+ if (out_jr_size != FSL_CAAM_MAX_JR_SIZE)
sec_init();
- }
if (!((len == 128) | (len == 192) | (len == 256))) {
debug("Invalid DEK size. Valid sizes are 128, 192 and 256b\n");
@@ -40,10 +50,237 @@ static int blob_encap_dek(const u8 *src, u8 *dst, u32 len)
}
len /= 8;
- ret = blob_dek(src, dst, len);
+ return blob_dek(src_ptr, dst_ptr, len);
+}
+#endif /* CONFIG_IMX_CAAM_DEK_ENCAP */
+
+#ifdef CONFIG_IMX_OPTEE_DEK_ENCAP
+
+#define PTA_DEK_BLOB_PTA_UUID {0xef477737, 0x0db1, 0x4a9d, \
+ {0x84, 0x37, 0xf2, 0xf5, 0x35, 0xc0, 0xbd, 0x92} }
+
+#define OPTEE_BLOB_HDR_SIZE 8
+
+static int blob_encap_dek(u32 src_addr, u32 dst_addr, u32 len)
+{
+ struct udevice *dev = NULL;
+ struct tee_shm *shm_input, *shm_output;
+ struct tee_open_session_arg arg = {0};
+ struct tee_invoke_arg arg_func = {0};
+ const struct tee_optee_ta_uuid uuid = PTA_DEK_BLOB_PTA_UUID;
+ struct tee_param param[4] = {0};
+ int ret;
+
+ /* Get tee device */
+ dev = tee_find_device(NULL, NULL, NULL, NULL);
+ if (!dev) {
+ printf("Cannot get OP-TEE device\n");
+ return -1;
+ }
+
+ /* Set TA UUID */
+ tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
+
+ /* Open TA session */
+ ret = tee_open_session(dev, &arg, 0, NULL);
+ if (ret < 0) {
+ printf("Cannot open session with PTA Blob 0x%X\n", ret);
+ return -1;
+ }
+
+ /* Allocate shared input and output buffers for TA */
+ ret = tee_shm_register(dev, (void *)(ulong)src_addr, len / 8, 0x0, &shm_input);
+ if (ret < 0) {
+ printf("Cannot register input shared memory 0x%X\n", ret);
+ goto error;
+ }
+
+ ret = tee_shm_register(dev, (void *)(ulong)dst_addr,
+ BLOB_SIZE(len / 8) + OPTEE_BLOB_HDR_SIZE,
+ 0x0, &shm_output);
+ if (ret < 0) {
+ printf("Cannot register output shared memory 0x%X\n", ret);
+ goto error;
+ }
+
+ param[0].u.memref.shm = shm_input;
+ param[0].u.memref.size = shm_input->size;
+ param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[1].u.memref.shm = shm_output;
+ param[1].u.memref.size = shm_output->size;
+ param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[2].attr = TEE_PARAM_ATTR_TYPE_NONE;
+ param[3].attr = TEE_PARAM_ATTR_TYPE_NONE;
+
+ arg_func.func = 0;
+ arg_func.session = arg.session;
+
+ /* Generate DEK blob */
+ arg_func.session = arg.session;
+ ret = tee_invoke_func(dev, &arg_func, 4, param);
+ if (ret < 0)
+ printf("Cannot generate Blob with PTA DEK Blob 0x%X\n", ret);
+
+error:
+ /* Free shared memory */
+ tee_shm_free(shm_input);
+ tee_shm_free(shm_output);
+
+ /* Close session */
+ ret = tee_close_session(dev, arg.session);
+ if (ret < 0)
+ printf("Cannot close session with PTA DEK Blob 0x%X\n", ret);
+
+ return ret;
+}
+#endif /* CONFIG_IMX_OPTEE_DEK_ENCAP */
+#ifdef CONFIG_IMX_SECO_DEK_ENCAP
+
+#define DEK_BLOB_KEY_ID 0x0
+
+#define AHAB_PRIVATE_KEY 0x81
+#define AHAB_VERSION 0x00
+#define AHAB_MODE_CBC 0x67
+#define AHAB_ALG_AES 0x55
+#define AHAB_128_AES_KEY 0x10
+#define AHAB_192_AES_KEY 0x18
+#define AHAB_256_AES_KEY 0x20
+#define AHAB_FLAG_KEK 0x80
+#define AHAB_DEK_BLOB 0x01
+
+#define DEK_BLOB_HDR_SIZE 8
+#define SECO_PT 2U
+
+static int blob_encap_dek(u32 src_addr, u32 dst_addr, u32 len)
+{
+ sc_err_t err;
+ sc_rm_mr_t mr_input, mr_output;
+ struct generate_key_blob_hdr hdr;
+ u8 in_size, out_size;
+ u8 *src_ptr, *dst_ptr;
+ int ret = 0;
+ int i;
+
+ /* Set sizes */
+ in_size = sizeof(struct generate_key_blob_hdr) + len / 8;
+ out_size = BLOB_SIZE(len / 8) + DEK_BLOB_HDR_SIZE;
+
+ /* Get src and dst virtual addresses */
+ src_ptr = map_sysmem(src_addr, in_size);
+ dst_ptr = map_sysmem(dst_addr, out_size);
+
+ /* Check addr input */
+ if (!(src_ptr && dst_ptr)) {
+ debug("src_addr or dst_addr invalid\n");
+ return -1;
+ }
+
+ /* Build key header */
+ hdr.version = AHAB_VERSION;
+ hdr.length_lsb = sizeof(struct generate_key_blob_hdr) + len / 8;
+ hdr.length_msb = 0x00;
+ hdr.tag = AHAB_PRIVATE_KEY;
+ hdr.flags = AHAB_DEK_BLOB;
+ hdr.algorithm = AHAB_ALG_AES;
+ hdr.mode = AHAB_MODE_CBC;
+
+ switch (len) {
+ case 128:
+ hdr.size = AHAB_128_AES_KEY;
+ break;
+ case 192:
+ hdr.size = AHAB_192_AES_KEY;
+ break;
+ case 256:
+ hdr.size = AHAB_256_AES_KEY;
+ break;
+ default:
+ /* Not supported */
+ debug("Invalid DEK size. Valid sizes are 128, 192 and 256b\n");
+ return -1;
+ }
+
+ /* Build input message */
+ memmove((void *)(src_ptr + sizeof(struct generate_key_blob_hdr)),
+ (void *)src_ptr, len / 8);
+ memcpy((void *)src_ptr, (void *)&hdr,
+ sizeof(struct generate_key_blob_hdr));
+
+ /* Flush the cache before triggering the CAAM DMA */
+ flush_dcache_range(src_addr, src_addr + in_size);
+
+ /* Find input memory region */
+ err = sc_rm_find_memreg((-1), &mr_input, src_addr & ~(CONFIG_SYS_CACHELINE_SIZE - 1),
+ ALIGN(src_addr + in_size, CONFIG_SYS_CACHELINE_SIZE));
+ if (err) {
+ printf("Error: find memory region 0x%X\n", src_addr);
+ return -ENOMEM;
+ }
+
+ /* Find output memory region */
+ err = sc_rm_find_memreg((-1), &mr_output, dst_addr & ~(CONFIG_SYS_CACHELINE_SIZE - 1),
+ ALIGN(dst_addr + out_size, CONFIG_SYS_CACHELINE_SIZE));
+ if (err) {
+ printf("Error: find memory region 0x%X\n", dst_addr);
+ return -ENOMEM;
+ }
+
+ /* Set memory region permissions for SECO */
+ err = sc_rm_set_memreg_permissions(-1, mr_input, SECO_PT,
+ SC_RM_PERM_FULL);
+ if (err) {
+ printf("Set permission failed for input memory region\n");
+ ret = -EPERM;
+ goto error;
+ }
+
+ err = sc_rm_set_memreg_permissions(-1, mr_output, SECO_PT,
+ SC_RM_PERM_FULL);
+ if (err) {
+ printf("Set permission failed for output memory region\n");
+ ret = -EPERM;
+ goto error;
+ }
+
+ /* Flush output data before SECO operation */
+ flush_dcache_range((ulong)dst_ptr, (ulong)(dst_ptr +
+ roundup(out_size, ARCH_DMA_MINALIGN)));
+
+ /* Generate DEK blob */
+ err = sc_seco_gen_key_blob((-1), 0x0, src_addr, dst_addr, out_size);
+ if (err) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ /* Invalidate output buffer */
+ invalidate_dcache_range((ulong)dst_ptr, (ulong)(dst_ptr +
+ roundup(out_size, ARCH_DMA_MINALIGN)));
+
+ printf("DEK Blob\n");
+ for (i = 0; i < DEK_BLOB_HDR_SIZE + BLOB_SIZE(len / 8); i++)
+ printf("%02X", dst_ptr[i]);
+ printf("\n");
+
+error:
+ /* Remove memory region permission to SECO */
+ err = sc_rm_set_memreg_permissions(-1, mr_input, SECO_PT,
+ SC_RM_PERM_NONE);
+ if (err) {
+ printf("Error: remove permission failed for input\n");
+ ret = -EPERM;
+ }
+
+ err = sc_rm_set_memreg_permissions(-1, mr_output, SECO_PT,
+ SC_RM_PERM_NONE);
+ if (err) {
+ printf("Error: remove permission failed for output\n");
+ ret = -EPERM;
+ }
return ret;
}
+#endif /* CONFIG_IMX_SECO_DEK_ENCAP */
/**
* do_dek_blob() - Handle the "dek_blob" command-line command
@@ -59,8 +296,6 @@ static int do_dek_blob(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
uint32_t src_addr, dst_addr, len;
- uint8_t *src_ptr, *dst_ptr;
- int ret = 0;
if (argc != 4)
return CMD_RET_USAGE;
@@ -69,12 +304,7 @@ static int do_dek_blob(struct cmd_tbl *cmdtp, int flag, int argc,
dst_addr = simple_strtoul(argv[2], NULL, 16);
len = simple_strtoul(argv[3], NULL, 10);
- src_ptr = map_sysmem(src_addr, len/8);
- dst_ptr = map_sysmem(dst_addr, BLOB_SIZE(len/8));
-
- ret = blob_encap_dek(src_ptr, dst_ptr, len);
-
- return ret;
+ return blob_encap_dek(src_addr, dst_addr, len);
}
/***************************************************/
diff --git a/arch/arm/mach-imx/cmd_mfgprot.c b/arch/arm/mach-imx/cmd_mfgprot.c
new file mode 100644
index 0000000000..1430f61909
--- /dev/null
+++ b/arch/arm/mach-imx/cmd_mfgprot.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * These commands enable the use of the CAAM MPPubK-generation and MPSign
+ * functions in supported i.MX devices.
+ */
+
+#include <asm/byteorder.h>
+#include <asm/arch/clock.h>
+#include <linux/compiler.h>
+#include <command.h>
+#include <common.h>
+#include <environment.h>
+#include <fsl_sec.h>
+#include <mapmem.h>
+#include <memalign.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * do_mfgprot() - Handle the "mfgprot" command-line command
+ * @cmdtp: Command data struct pointer
+ * @flag: Command flag
+ * @argc: Command-line argument count
+ * @argv: Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
+static int do_mfgprot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ u8 *m_ptr, *dgst_ptr, *c_ptr, *d_ptr, *dst_ptr;
+ char *pubk, *sign, *sel;
+ int m_size, i, ret;
+ u32 m_addr;
+
+ pubk = "pubk";
+ sign = "sign";
+ sel = argv[1];
+
+ /* Enable HAB clock */
+ hab_caam_clock_enable(1);
+
+ u32 out_jr_size = sec_in32(CONFIG_SYS_FSL_JR0_ADDR +
+ FSL_CAAM_ORSR_JRa_OFFSET);
+
+ if (out_jr_size != FSL_CAAM_MAX_JR_SIZE)
+ sec_init();
+
+ if (strcmp(sel, pubk) == 0) {
+ dst_ptr = malloc_cache_aligned(FSL_CAAM_MP_PUBK_BYTES);
+ if (!dst_ptr)
+ return -ENOMEM;
+
+ ret = gen_mppubk(dst_ptr);
+ if (ret) {
+ free(dst_ptr);
+ return ret;
+ }
+
+ /* Output results */
+ puts("Public key:\n");
+ for (i = 0; i < FSL_CAAM_MP_PUBK_BYTES; i++)
+ printf("%02X", (dst_ptr)[i]);
+ puts("\n");
+ free(dst_ptr);
+
+ } else if (strcmp(sel, sign) == 0) {
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ m_addr = simple_strtoul(argv[2], NULL, 16);
+ m_size = simple_strtoul(argv[3], NULL, 10);
+ m_ptr = map_physmem(m_addr, m_size, MAP_NOCACHE);
+ if (!m_ptr)
+ return -ENOMEM;
+
+ dgst_ptr = malloc_cache_aligned(FSL_CAAM_MP_MES_DGST_BYTES);
+ if (!dgst_ptr) {
+ ret = -ENOMEM;
+ goto free_m;
+ }
+
+ c_ptr = malloc_cache_aligned(FSL_CAAM_MP_PRVK_BYTES);
+ if (!c_ptr) {
+ ret = -ENOMEM;
+ goto free_dgst;
+ }
+
+ d_ptr = malloc_cache_aligned(FSL_CAAM_MP_PRVK_BYTES);
+ if (!d_ptr) {
+ ret = -ENOMEM;
+ goto free_c;
+ }
+
+ ret = sign_mppubk(m_ptr, m_size, dgst_ptr, c_ptr, d_ptr);
+ if (ret)
+ goto free_d;
+
+ /* Output results */
+ puts("Message: ");
+ for (i = 0; i < m_size; i++)
+ printf("%02X ", (m_ptr)[i]);
+ puts("\n");
+
+ puts("Message Representative Digest(SHA-256):\n");
+ for (i = 0; i < FSL_CAAM_MP_MES_DGST_BYTES; i++)
+ printf("%02X", (dgst_ptr)[i]);
+ puts("\n");
+
+ puts("Signature:\n");
+ puts("C:\n");
+ for (i = 0; i < FSL_CAAM_MP_PRVK_BYTES; i++)
+ printf("%02X", (c_ptr)[i]);
+ puts("\n");
+
+ puts("d:\n");
+ for (i = 0; i < FSL_CAAM_MP_PRVK_BYTES; i++)
+ printf("%02X", (d_ptr)[i]);
+ puts("\n");
+free_d:
+ free(d_ptr);
+free_c:
+ free(c_ptr);
+free_dgst:
+ free(dgst_ptr);
+free_m:
+ unmap_sysmem(m_ptr);
+
+ } else {
+ return CMD_RET_USAGE;
+ }
+ return ret;
+}
+
+/***************************************************/
+static char mfgprot_help_text[] =
+ "Usage:\n"
+ "Print the public key for Manufacturing Protection\n"
+ "\tmfgprot pubk\n"
+ "Generates a Manufacturing Protection signature\n"
+ "\tmfgprot sign <data_addr> <size>";
+
+U_BOOT_CMD(
+ mfgprot, 4, 1, do_mfgprot,
+ "Manufacturing Protection\n",
+ mfgprot_help_text
+);
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index 38b87ed5c3..423b715352 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -117,7 +117,13 @@ const char *get_imx_type(u32 imxtype)
case MXC_CPU_IMX8MNDL:
return "8MNano DualLite"; /* Dual-core Lite version */
case MXC_CPU_IMX8MNSL:
- return "8MNano SoloLite"; /* Single-core Lite version */
+ return "8MNano SoloLite";/* Single-core Lite version of the imx8mn */
+ case MXC_CPU_IMX8MNUQ:
+ return "8MNano UltraLite Quad";/* Quad-core UltraLite version of the imx8mn */
+ case MXC_CPU_IMX8MNUD:
+ return "8MNano UltraLite Dual";/* Dual-core UltraLite version of the imx8mn */
+ case MXC_CPU_IMX8MNUS:
+ return "8MNano UltraLite Solo";/* Single-core UltraLite version of the imx8mn */
case MXC_CPU_IMX8MM:
return "8MMQ"; /* Quad-core version of the imx8mm */
case MXC_CPU_IMX8MML:
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c
index d0757d8b66..00bd157d0e 100644
--- a/arch/arm/mach-imx/hab.c
+++ b/arch/arm/mach-imx/hab.c
@@ -10,10 +10,14 @@
#include <mapmem.h>
#include <image.h>
#include <asm/io.h>
+#include <asm/global_data.h>
#include <asm/system.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
#include <asm/mach-imx/hab.h>
+#include <linux/arm-smccc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
#define ALIGN_SIZE 0x1000
#define MX6DQ_PU_IROM_MMU_EN_VAR 0x009024a8
@@ -21,7 +25,13 @@
#define MX6SL_PU_IROM_MMU_EN_VAR 0x00901c60
#define IS_HAB_ENABLED_BIT \
(is_soc_type(MXC_SOC_MX7ULP) ? 0x80000000 : \
- (is_soc_type(MXC_SOC_MX7) ? 0x2000000 : 0x2))
+ ((is_soc_type(MXC_SOC_MX7) || is_soc_type(MXC_SOC_IMX8M)) ? 0x2000000 : 0x2))
+
+#ifdef CONFIG_MX7ULP
+#define HAB_M4_PERSISTENT_START ((soc_rev() >= CHIP_REV_2_0) ? 0x20008040 : \
+ 0x20008180)
+#define HAB_M4_PERSISTENT_BYTES 0xB80
+#endif
static int ivt_header_error(const char *err_str, struct ivt_header *ivt_hdr)
{
@@ -41,13 +51,200 @@ static int verify_ivt_header(struct ivt_header *ivt_hdr)
if (be16_to_cpu(ivt_hdr->length) != IVT_TOTAL_LENGTH)
result = ivt_header_error("bad length", ivt_hdr);
- if (ivt_hdr->version != IVT_HEADER_V1 &&
- ivt_hdr->version != IVT_HEADER_V2)
+ if ((ivt_hdr->version & HAB_MAJ_MASK) != HAB_MAJ_VER)
result = ivt_header_error("bad version", ivt_hdr);
return result;
}
+#ifdef CONFIG_ARM64
+#define FSL_SIP_HAB 0xC2000007
+#define FSL_SIP_HAB_AUTHENTICATE 0x00
+#define FSL_SIP_HAB_ENTRY 0x01
+#define FSL_SIP_HAB_EXIT 0x02
+#define FSL_SIP_HAB_REPORT_EVENT 0x03
+#define FSL_SIP_HAB_REPORT_STATUS 0x04
+#define FSL_SIP_HAB_FAILSAFE 0x05
+#define FSL_SIP_HAB_CHECK_TARGET 0x06
+static volatile gd_t *gd_save;
+#endif
+
+static inline void save_gd(void)
+{
+#ifdef CONFIG_ARM64
+ gd_save = gd;
+#endif
+}
+
+static inline void restore_gd(void)
+{
+#ifdef CONFIG_ARM64
+ /*
+ * Make will already error that reserving x18 is not supported at the
+ * time of writing, clang: error: unknown argument: '-ffixed-x18'
+ */
+ __asm__ volatile("mov x18, %0\n" : : "r" (gd_save));
+#endif
+}
+
+enum hab_status hab_rvt_report_event(enum hab_status status, u32 index,
+ u8 *event, size_t *bytes)
+{
+ enum hab_status ret;
+ hab_rvt_report_event_t *hab_rvt_report_event_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_report_event_func = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_EVENT, (unsigned long)index,
+ (unsigned long)event, (unsigned long)bytes, 0, 0, 0, &res);
+ return (enum hab_status)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_report_event_func(status, index, event, bytes);
+ restore_gd();
+
+ return ret;
+
+}
+
+enum hab_status hab_rvt_report_status(enum hab_config *config, enum hab_state *state)
+{
+ enum hab_status ret;
+ hab_rvt_report_status_t *hab_rvt_report_status_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_report_status_func = (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_STATUS, (unsigned long)config,
+ (unsigned long)state, 0, 0, 0, 0, &res);
+ return (enum hab_status)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_report_status_func(config, state);
+ restore_gd();
+
+ return ret;
+}
+
+enum hab_status hab_rvt_entry(void)
+{
+ enum hab_status ret;
+ hab_rvt_entry_t *hab_rvt_entry_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_entry_func = (hab_rvt_entry_t *)HAB_RVT_ENTRY;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_ENTRY, 0, 0, 0, 0, 0, 0, &res);
+ return (enum hab_status)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_entry_func();
+ restore_gd();
+
+ return ret;
+}
+
+enum hab_status hab_rvt_exit(void)
+{
+ enum hab_status ret;
+ hab_rvt_exit_t *hab_rvt_exit_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_exit_func = (hab_rvt_exit_t *)HAB_RVT_EXIT;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_EXIT, 0, 0, 0, 0, 0, 0, &res);
+ return (enum hab_status)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_exit_func();
+ restore_gd();
+
+ return ret;
+}
+
+void hab_rvt_failsafe(void)
+{
+ hab_rvt_failsafe_t *hab_rvt_failsafe_func;
+
+ hab_rvt_failsafe_func = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_FAILSAFE, 0, 0, 0, 0, 0, 0, NULL);
+ return;
+ }
+#endif
+
+ save_gd();
+ hab_rvt_failsafe_func();
+ restore_gd();
+}
+
+enum hab_status hab_rvt_check_target(enum hab_target type, const void *start,
+ size_t bytes)
+{
+ enum hab_status ret;
+ hab_rvt_check_target_t *hab_rvt_check_target_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_check_target_func = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_CHECK_TARGET, (unsigned long)type,
+ (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res);
+ return (enum hab_status)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_check_target_func(type, start, bytes);
+ restore_gd();
+
+ return ret;
+}
+
+void *hab_rvt_authenticate_image(uint8_t cid, ptrdiff_t ivt_offset,
+ void **start, size_t *bytes, hab_loader_callback_f_t loader)
+{
+ void *ret;
+ hab_rvt_authenticate_image_t *hab_rvt_authenticate_image_func;
+ struct arm_smccc_res res __maybe_unused;
+
+ hab_rvt_authenticate_image_func = (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE;
+#if defined(CONFIG_ARM64)
+ if (current_el() != 3) {
+ /* call sip */
+ arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_AUTHENTICATE, (unsigned long)ivt_offset,
+ (unsigned long)start, (unsigned long)bytes, 0, 0, 0, &res);
+ return (void *)res.a0;
+ }
+#endif
+
+ save_gd();
+ ret = hab_rvt_authenticate_image_func(cid, ivt_offset, start, bytes, loader);
+ restore_gd();
+
+ return ret;
+}
+
#if !defined(CONFIG_SPL_BUILD)
#define MAX_RECORD_BYTES (8*1024) /* 4 kbytes */
@@ -253,12 +450,6 @@ static int get_hab_status(void)
size_t bytes = sizeof(event_data); /* Event size in bytes */
enum hab_config config = 0;
enum hab_state state = 0;
- hab_rvt_report_event_t *hab_rvt_report_event;
- hab_rvt_report_status_t *hab_rvt_report_status;
-
- hab_rvt_report_event = (hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT;
- hab_rvt_report_status =
- (hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS;
if (imx_hab_is_enabled())
puts("\nSecure boot enabled\n");
@@ -270,8 +461,8 @@ static int get_hab_status(void)
printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
config, state);
- /* Display HAB Error events */
- while (hab_rvt_report_event(HAB_FAILURE, index, event_data,
+ /* Display HAB events */
+ while (hab_rvt_report_event(HAB_STS_ANY, index, event_data,
&bytes) == HAB_SUCCESS) {
puts("\n");
printf("--------- HAB Event %d -----------------\n",
@@ -292,15 +483,99 @@ static int get_hab_status(void)
return 0;
}
+#ifdef CONFIG_MX7ULP
+
+static int get_record_len(struct record *rec)
+{
+ return (size_t)((rec->len[0] << 8) + (rec->len[1]));
+}
+
+static int get_hab_status_m4(void)
+{
+ unsigned int index = 0;
+ uint8_t event_data[128];
+ size_t record_len, offset = 0;
+ enum hab_config config = 0;
+ enum hab_state state = 0;
+
+ if (imx_hab_is_enabled())
+ puts("\nSecure boot enabled\n");
+ else
+ puts("\nSecure boot disabled\n");
+
+ /*
+ * HAB in both A7 and M4 gather the security state
+ * and configuration of the chip from
+ * shared SNVS module
+ */
+ hab_rvt_report_status(&config, &state);
+ printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
+ config, state);
+
+ struct record *rec = (struct record *)(HAB_M4_PERSISTENT_START);
+
+ record_len = get_record_len(rec);
+
+ /* Check if HAB persistent memory is valid */
+ if (rec->tag != HAB_TAG_EVT_DEF ||
+ record_len != sizeof(struct evt_def) ||
+ (rec->par & HAB_MAJ_MASK) != HAB_MAJ_VER) {
+ puts("\nERROR: Invalid HAB persistent memory\n");
+ return 1;
+ }
+
+ /* Parse events in HAB M4 persistent memory region */
+ while (offset < HAB_M4_PERSISTENT_BYTES) {
+ rec = (struct record *)(HAB_M4_PERSISTENT_START + offset);
+
+ record_len = get_record_len(rec);
+
+ if (rec->tag == HAB_TAG_EVT) {
+ memcpy(&event_data, rec, record_len);
+ puts("\n");
+ printf("--------- HAB Event %d -----------------\n",
+ index + 1);
+ puts("event data:\n");
+ display_event(event_data, record_len);
+ puts("\n");
+ index++;
+ }
+
+ offset += record_len;
+
+ /* Ensure all records start on a word boundary */
+ if ((offset % 4) != 0)
+ offset = offset + (4 - (offset % 4));
+ }
+
+ if (!index)
+ puts("No HAB Events Found!\n\n");
+
+ return 0;
+}
+#endif
+
static int do_hab_status(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
+#ifdef CONFIG_MX7ULP
+ if ((argc > 2)) {
+ cmd_usage(cmdtp);
+ return 1;
+ }
+
+ if (strcmp("m4", argv[1]) == 0)
+ get_hab_status_m4();
+ else
+ get_hab_status();
+#else
if ((argc != 1)) {
cmd_usage(cmdtp);
return 1;
}
get_hab_status();
+#endif
return 0;
}
@@ -353,14 +628,11 @@ static int do_authenticate_image(struct cmd_tbl *cmdtp, int flag, int argc,
static int do_hab_failsafe(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
- hab_rvt_failsafe_t *hab_rvt_failsafe;
-
if (argc != 1) {
cmd_usage(cmdtp);
return 1;
}
- hab_rvt_failsafe = (hab_rvt_failsafe_t *)HAB_RVT_FAILSAFE;
hab_rvt_failsafe();
return 0;
@@ -406,11 +678,20 @@ error:
return ret;
}
+#ifdef CONFIG_MX7ULP
+U_BOOT_CMD(
+ hab_status, CONFIG_SYS_MAXARGS, 2, do_hab_status,
+ "display HAB status and events",
+ "hab_status - A7 HAB event and status\n"
+ "hab_status m4 - M4 HAB event and status"
+ );
+#else
U_BOOT_CMD(
hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status,
"display HAB status",
""
);
+#endif
U_BOOT_CMD(
hab_auth_img, 4, 0, do_authenticate_image,
@@ -493,7 +774,7 @@ static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes)
return false;
}
- csf_hdr = (u8 *)ivt->csf;
+ csf_hdr = (u8 *)(ulong)ivt->csf;
/* Verify if CSF Header exist */
if (*csf_hdr != HAB_CMD_HDR) {
@@ -542,6 +823,48 @@ static bool csf_is_valid(struct ivt *ivt, ulong start_addr, size_t bytes)
return true;
}
+/*
+ * Validate IVT structure of the image being authenticated
+ */
+static int validate_ivt(struct ivt *ivt_initial)
+{
+ struct ivt_header *ivt_hdr = &ivt_initial->hdr;
+
+ if ((ulong)ivt_initial & 0x3) {
+ puts("Error: Image's start address is not 4 byte aligned\n");
+ return 0;
+ }
+
+ /* Check IVT fields before allowing authentication */
+ if ((!verify_ivt_header(ivt_hdr)) && \
+ (ivt_initial->entry != 0x0) && \
+ (ivt_initial->reserved1 == 0x0) && \
+ (ivt_initial->self == \
+ (uint32_t)((ulong)ivt_initial & 0xffffffff)) && \
+ (ivt_initial->csf != 0x0) && \
+ (ivt_initial->reserved2 == 0x0)) {
+ /* Report boot failure if DCD pointer is found in IVT */
+ if (ivt_initial->dcd != 0x0)
+ puts("Error: DCD pointer must be 0\n");
+ else
+ return 1;
+ }
+
+ puts("Error: Invalid IVT structure\n");
+ debug("\nAllowed IVT structure:\n");
+ debug("IVT HDR = 0x4X2000D1\n");
+ debug("IVT ENTRY = 0xXXXXXXXX\n");
+ debug("IVT RSV1 = 0x0\n");
+ debug("IVT DCD = 0x0\n"); /* Recommended */
+ debug("IVT BOOT_DATA = 0xXXXXXXXX\n"); /* Commonly 0x0 */
+ debug("IVT SELF = 0xXXXXXXXX\n"); /* = ddr_start + ivt_offset */
+ debug("IVT CSF = 0xXXXXXXXX\n");
+ debug("IVT RSV2 = 0x0\n");
+
+ /* Invalid IVT structure */
+ return 0;
+}
+
bool imx_hab_is_enabled(void)
{
struct imx_sec_config_fuse_t *fuse =
@@ -561,29 +884,16 @@ bool imx_hab_is_enabled(void)
int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
uint32_t ivt_offset)
{
- uint32_t load_addr = 0;
+ ulong load_addr = 0;
size_t bytes;
- uint32_t ivt_addr = 0;
+ ulong ivt_addr = 0;
int result = 1;
ulong start;
- hab_rvt_authenticate_image_t *hab_rvt_authenticate_image;
- hab_rvt_entry_t *hab_rvt_entry;
- hab_rvt_exit_t *hab_rvt_exit;
- hab_rvt_check_target_t *hab_rvt_check_target;
struct ivt *ivt;
- struct ivt_header *ivt_hdr;
enum hab_status status;
- hab_rvt_authenticate_image =
- (hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE;
- hab_rvt_entry = (hab_rvt_entry_t *)HAB_RVT_ENTRY;
- hab_rvt_exit = (hab_rvt_exit_t *)HAB_RVT_EXIT;
- hab_rvt_check_target = (hab_rvt_check_target_t *)HAB_RVT_CHECK_TARGET;
-
- if (!imx_hab_is_enabled()) {
+ if (!imx_hab_is_enabled())
puts("hab fuse not enabled\n");
- return 0;
- }
printf("\nAuthenticate image from DDR location 0x%x...\n",
ddr_start);
@@ -591,27 +901,13 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
hab_caam_clock_enable(1);
/* Calculate IVT address header */
- ivt_addr = ddr_start + ivt_offset;
+ ivt_addr = (ulong) (ddr_start + ivt_offset);
ivt = (struct ivt *)ivt_addr;
- ivt_hdr = &ivt->hdr;
/* Verify IVT header bugging out on error */
- if (verify_ivt_header(ivt_hdr))
+ if (!validate_ivt(ivt))
goto hab_authentication_exit;
- /* Verify IVT body */
- if (ivt->self != ivt_addr) {
- printf("ivt->self 0x%08x pointer is 0x%08x\n",
- ivt->self, ivt_addr);
- goto hab_authentication_exit;
- }
-
- /* Verify if IVT DCD pointer is NULL */
- if (ivt->dcd) {
- puts("Error: DCD pointer must be NULL\n");
- goto hab_authentication_exit;
- }
-
start = ddr_start;
bytes = image_size;
@@ -624,14 +920,14 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
goto hab_exit_failure_print_status;
}
- status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)ddr_start, bytes);
+ status = hab_rvt_check_target(HAB_TGT_MEMORY, (void *)(ulong)ddr_start, bytes);
if (status != HAB_SUCCESS) {
- printf("HAB check target 0x%08x-0x%08x fail\n",
- ddr_start, ddr_start + bytes);
+ printf("HAB check target 0x%08x-0x%08lx fail\n",
+ ddr_start, ddr_start + (ulong)bytes);
goto hab_exit_failure_print_status;
}
#ifdef DEBUG
- printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n", ivt_offset, ivt_addr);
+ printf("\nivt_offset = 0x%x, ivt addr = 0x%lx\n", ivt_offset, ivt_addr);
printf("ivt entry = 0x%08x, dcd = 0x%08x, csf = 0x%08x\n", ivt->entry,
ivt->dcd, ivt->csf);
puts("Dumping IVT\n");
@@ -649,6 +945,8 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
printf("\tstart = 0x%08lx\n", start);
printf("\tbytes = 0x%x\n", bytes);
#endif
+
+#ifndef CONFIG_ARM64
/*
* If the MMU is enabled, we have to notify the ROM
* code, or it won't flush the caches when needed.
@@ -676,8 +974,9 @@ int imx_hab_authenticate_image(uint32_t ddr_start, uint32_t image_size,
writel(1, MX6SL_PU_IROM_MMU_EN_VAR);
}
}
+#endif
- load_addr = (uint32_t)hab_rvt_authenticate_image(
+ load_addr = (ulong)hab_rvt_authenticate_image(
HAB_CID_UBOOT,
ivt_offset, (void **)&start,
(size_t *)&bytes, NULL);
@@ -693,8 +992,20 @@ hab_exit_failure_print_status:
hab_authentication_exit:
- if (load_addr != 0)
+ if (load_addr != 0 || !imx_hab_is_enabled())
result = 0;
return result;
}
+
+int authenticate_image(u32 ddr_start, u32 raw_image_size)
+{
+ u32 ivt_offset;
+ size_t bytes;
+
+ ivt_offset = (raw_image_size + ALIGN_SIZE - 1) &
+ ~(ALIGN_SIZE - 1);
+ bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE;
+
+ return imx_hab_authenticate_image(ddr_start, bytes, ivt_offset);
+}
diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig
index 04b9729109..4e76612d05 100644
--- a/arch/arm/mach-imx/imx8/Kconfig
+++ b/arch/arm/mach-imx/imx8/Kconfig
@@ -2,6 +2,7 @@ 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.
diff --git a/arch/arm/mach-imx/imx8m/Kconfig b/arch/arm/mach-imx/imx8m/Kconfig
index 12b8d0d831..c27fb248d1 100644
--- a/arch/arm/mach-imx/imx8m/Kconfig
+++ b/arch/arm/mach-imx/imx8m/Kconfig
@@ -2,6 +2,7 @@ if ARCH_IMX8M
config IMX8M
bool
+ select HAS_CAAM
select ROM_UNIFIED_SECTIONS
config IMX8MQ
@@ -39,6 +40,7 @@ config TARGET_IMX8MQ_PHANBELL
config TARGET_IMX8MM_EVK
bool "imx8mm LPDDR4 EVK board"
+ select BINMAN
select IMX8MM
select SUPPORT_SPL
select IMX8M_LPDDR4
@@ -49,14 +51,23 @@ config TARGET_IMX8MM_VENICE
select SUPPORT_SPL
select IMX8M_LPDDR4
+config TARGET_IMX8MN_EVK
+ bool "imx8mn LPDDR4 EVK board"
+ select BINMAN
+ select IMX8MN
+ select SUPPORT_SPL
+ select IMX8M_LPDDR4
+
config TARGET_IMX8MN_DDR4_EVK
bool "imx8mn DDR4 EVK board"
+ select BINMAN
select IMX8MN
select SUPPORT_SPL
select IMX8M_DDR4
config TARGET_IMX8MP_EVK
bool "imx8mp LPDDR4 EVK board"
+ select BINMAN
select IMX8MP
select SUPPORT_SPL
select IMX8M_LPDDR4
diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
index 4024dafca1..029d06f27f 100644
--- a/arch/arm/mach-imx/imx8m/clock_imx8mm.c
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
@@ -21,6 +21,14 @@ DECLARE_GLOBAL_DATA_PTR;
static struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
static u32 get_root_clk(enum clk_root_index clock_id);
+
+#ifdef CONFIG_IMX_HAB
+void hab_caam_clock_enable(unsigned char enable)
+{
+ /* The CAAM clock is always on for iMX8M */
+}
+#endif
+
void enable_ocotp_clk(unsigned char enable)
{
clock_enable(CCGR_OCOTP, !!enable);
diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mq.c b/arch/arm/mach-imx/imx8m/clock_imx8mq.c
index 759ec6d114..8fecc60ecb 100644
--- a/arch/arm/mach-imx/imx8m/clock_imx8mq.c
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mq.c
@@ -310,6 +310,13 @@ static u32 get_root_clk(enum clk_root_index clock_id)
return root_src_clk / (post_podf + 1) / (pre_podf + 1);
}
+#ifdef CONFIG_IMX_HAB
+void hab_caam_clock_enable(unsigned char enable)
+{
+ /* The CAAM clock is always on for iMX8M */
+}
+#endif
+
#ifdef CONFIG_MXC_OCOTP
void enable_ocotp_clk(unsigned char enable)
{
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index e6bc977fc8..36abb2e57f 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -105,6 +105,13 @@ static struct mm_region imx8m_mem_map[] = {
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
+ /* OCRAM_S */
+ .virt = 0x180000UL,
+ .phys = 0x180000UL,
+ .size = 0x8000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_OUTER_SHARE
+ }, {
/* TCM */
.virt = 0x7C0000UL,
.phys = 0x7C0000UL,
@@ -324,18 +331,30 @@ static u32 get_cpu_variant_type(u32 type)
} else if (type == MXC_CPU_IMX8MN) {
switch (value & 0x3) {
case 2:
- if (value & 0x1000000)
- return MXC_CPU_IMX8MNDL;
- else
+ if (value & 0x1000000) {
+ if (value & 0x10000000) /* MIPI DSI */
+ return MXC_CPU_IMX8MNUD;
+ else
+ return MXC_CPU_IMX8MNDL;
+ } else {
return MXC_CPU_IMX8MND;
+ }
case 3:
- if (value & 0x1000000)
- return MXC_CPU_IMX8MNSL;
- else
+ if (value & 0x1000000) {
+ if (value & 0x10000000) /* MIPI DSI */
+ return MXC_CPU_IMX8MNUS;
+ else
+ return MXC_CPU_IMX8MNSL;
+ } else {
return MXC_CPU_IMX8MNS;
+ }
default:
- if (value & 0x1000000)
- return MXC_CPU_IMX8MNL;
+ if (value & 0x1000000) {
+ if (value & 0x10000000) /* MIPI DSI */
+ return MXC_CPU_IMX8MNUQ;
+ else
+ return MXC_CPU_IMX8MNL;
+ }
break;
}
} else if (type == MXC_CPU_IMX8MP) {
@@ -398,7 +417,16 @@ u32 get_cpu_rev(void)
* 0xff0055aa is magic number for B1.
*/
if (readl((void __iomem *)(OCOTP_BASE_ADDR + 0x40)) == 0xff0055aa) {
- reg = CHIP_REV_2_1;
+ /*
+ * B2 uses same DIGPROG and OCOTP_READ_FUSE_DATA value with B1,
+ * so have to check ROM to distinguish them
+ */
+ rom_version = readl((void __iomem *)ROM_VERSION_B0);
+ rom_version &= 0xff;
+ if (rom_version == CHIP_REV_2_2)
+ reg = CHIP_REV_2_2;
+ else
+ reg = CHIP_REV_2_1;
} else {
rom_version =
readl((void __iomem *)ROM_VERSION_A0);
@@ -468,7 +496,7 @@ int arch_cpu_init(void)
if (is_imx8md() || is_imx8mmd() || is_imx8mmdl() || is_imx8mms() ||
is_imx8mmsl() || is_imx8mnd() || is_imx8mndl() || is_imx8mns() ||
- is_imx8mnsl() || is_imx8mpd()) {
+ is_imx8mnsl() || is_imx8mpd() || is_imx8mnud() || is_imx8mnus()) {
/* Power down cpu core 1, 2 and 3 for iMX8M Dual core or Single core */
struct pgc_reg *pgc_core1 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x840);
struct pgc_reg *pgc_core2 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x880);
@@ -477,7 +505,7 @@ int arch_cpu_init(void)
writel(0x1, &pgc_core2->pgcr);
writel(0x1, &pgc_core3->pgcr);
- if (is_imx8mms() || is_imx8mmsl() || is_imx8mns() || is_imx8mnsl()) {
+ if (is_imx8mms() || is_imx8mmsl() || is_imx8mns() || is_imx8mnsl() || is_imx8mnus()) {
writel(0x1, &pgc_core1->pgcr);
writel(0xE, &gpc->cpu_pgc_dn_trg);
} else {
@@ -616,7 +644,8 @@ static int disable_mipi_dsi_nodes(void *blob)
"/mipi_dsi_bridge@30A00000",
"/dsi_phy@30A00300",
"/soc@0/bus@30800000/mipi_dsi@30a00000",
- "/soc@0/bus@30800000/dphy@30a00300"
+ "/soc@0/bus@30800000/dphy@30a00300",
+ "/soc@0/bus@30800000/mipi-dsi@30a00000",
};
return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path));
@@ -644,7 +673,8 @@ static int check_mipi_dsi_nodes(void *blob)
{
static const char * const lcdif_path[] = {
"/lcdif@30320000",
- "/soc@0/bus@30000000/lcdif@30320000"
+ "/soc@0/bus@30000000/lcdif@30320000",
+ "/soc@0/bus@30000000/lcd-controller@30320000"
};
static const char * const mipi_dsi_path[] = {
"/mipi_dsi@30A00000",
@@ -652,11 +682,13 @@ static int check_mipi_dsi_nodes(void *blob)
};
static const char * const lcdif_ep_path[] = {
"/lcdif@30320000/port@0/mipi-dsi-endpoint",
- "/soc@0/bus@30000000/lcdif@30320000/port@0/endpoint"
+ "/soc@0/bus@30000000/lcdif@30320000/port@0/endpoint",
+ "/soc@0/bus@30000000/lcd-controller@30320000/port@0/endpoint"
};
static const char * const mipi_dsi_ep_path[] = {
"/mipi_dsi@30A00000/port@1/endpoint",
- "/soc@0/bus@30800000/mipi_dsi@30a00000/ports/port@0/endpoint"
+ "/soc@0/bus@30800000/mipi_dsi@30a00000/ports/port@0/endpoint",
+ "/soc@0/bus@30800000/mipi-dsi@30a00000/ports/port@0/endpoint@0"
};
int lookup_node;
@@ -726,10 +758,46 @@ int disable_vpu_nodes(void *blob)
return -EPERM;
}
+#ifdef CONFIG_IMX8MN_LOW_DRIVE_MODE
+static int low_drive_gpu_freq(void *blob)
+{
+ static const char *nodes_path_8mn[] = {
+ "/gpu@38000000",
+ "/soc@0/gpu@38000000"
+ };
+
+ int nodeoff, cnt, i;
+ u32 assignedclks[7];
+
+ nodeoff = fdt_path_offset(blob, nodes_path_8mn[0]);
+ if (nodeoff < 0)
+ return nodeoff;
+
+ cnt = fdtdec_get_int_array_count(blob, nodeoff, "assigned-clock-rates", assignedclks, 7);
+ if (cnt < 0)
+ return cnt;
+
+ if (cnt != 7)
+ printf("Warning: %s, assigned-clock-rates count %d\n", nodes_path_8mn[0], cnt);
+
+ assignedclks[cnt - 1] = 200000000;
+ assignedclks[cnt - 2] = 200000000;
+
+ for (i = 0; i < cnt; i++) {
+ debug("<%u>, ", assignedclks[i]);
+ assignedclks[i] = cpu_to_fdt32(assignedclks[i]);
+ }
+ debug("\n");
+
+ return fdt_setprop(blob, nodeoff, "assigned-clock-rates", &assignedclks, sizeof(assignedclks));
+}
+#endif
+
int disable_gpu_nodes(void *blob)
{
static const char * const nodes_path_8mn[] = {
- "/gpu@38000000"
+ "/gpu@38000000",
+ "/soc@/gpu@38000000"
};
return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn));
@@ -763,6 +831,79 @@ int disable_dsp_nodes(void *blob)
return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
}
+static void disable_thermal_cpu_nodes(void *blob, u32 disabled_cores)
+{
+ static const char * const thermal_path[] = {
+ "/thermal-zones/cpu-thermal/cooling-maps/map0"
+ };
+
+ int nodeoff, cnt, i, ret, j;
+ u32 cooling_dev[12];
+
+ for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
+ nodeoff = fdt_path_offset(blob, thermal_path[i]);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ cnt = fdtdec_get_int_array_count(blob, nodeoff, "cooling-device", cooling_dev, 12);
+ if (cnt < 0)
+ continue;
+
+ if (cnt != 12)
+ printf("Warning: %s, cooling-device count %d\n", thermal_path[i], cnt);
+
+ for (j = 0; j < cnt; j++)
+ cooling_dev[j] = cpu_to_fdt32(cooling_dev[j]);
+
+ ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
+ sizeof(u32) * (12 - disabled_cores * 3));
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device setprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+
+ printf("Update node %s, cooling-device prop\n", thermal_path[i]);
+ }
+}
+
+static void disable_pmu_cpu_nodes(void *blob, u32 disabled_cores)
+{
+ static const char * const pmu_path[] = {
+ "/pmu"
+ };
+
+ int nodeoff, cnt, i, ret, j;
+ u32 irq_affinity[4];
+
+ for (i = 0; i < ARRAY_SIZE(pmu_path); i++) {
+ nodeoff = fdt_path_offset(blob, pmu_path[i]);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ cnt = fdtdec_get_int_array_count(blob, nodeoff, "interrupt-affinity",
+ irq_affinity, 4);
+ if (cnt < 0)
+ continue;
+
+ if (cnt != 4)
+ printf("Warning: %s, interrupt-affinity count %d\n", pmu_path[i], cnt);
+
+ for (j = 0; j < cnt; j++)
+ irq_affinity[j] = cpu_to_fdt32(irq_affinity[j]);
+
+ ret = fdt_setprop(blob, nodeoff, "interrupt-affinity", &irq_affinity,
+ sizeof(u32) * (4 - disabled_cores));
+ if (ret < 0) {
+ printf("Warning: %s, interrupt-affinity setprop failed %d\n",
+ pmu_path[i], ret);
+ continue;
+ }
+
+ printf("Update node %s, interrupt-affinity prop\n", pmu_path[i]);
+ }
+}
+
static int disable_cpu_nodes(void *blob, u32 disabled_cores)
{
static const char * const nodes_path[] = {
@@ -795,6 +936,9 @@ static int disable_cpu_nodes(void *blob, u32 disabled_cores)
}
}
+ disable_thermal_cpu_nodes(blob, disabled_cores);
+ disable_pmu_cpu_nodes(blob, disabled_cores);
+
return 0;
}
@@ -895,10 +1039,20 @@ usb_modify_speed:
#elif defined(CONFIG_IMX8MN)
if (is_imx8mnl() || is_imx8mndl() || is_imx8mnsl())
disable_gpu_nodes(blob);
+#ifdef CONFIG_IMX8MN_LOW_DRIVE_MODE
+ else {
+ int ldm_gpu = low_drive_gpu_freq(blob);
+
+ if (ldm_gpu < 0)
+ printf("Update GPU node assigned-clock-rates failed\n");
+ else
+ printf("Update GPU node assigned-clock-rates ok\n");
+ }
+#endif
- if (is_imx8mnd() || is_imx8mndl())
+ if (is_imx8mnd() || is_imx8mndl() || is_imx8mnud())
disable_cpu_nodes(blob, 2);
- else if (is_imx8mns() || is_imx8mnsl())
+ else if (is_imx8mns() || is_imx8mnsl() || is_imx8mnus())
disable_cpu_nodes(blob, 3);
#elif defined(CONFIG_IMX8MP)
diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c
index e1fc4b3e19..30fb45d48c 100644
--- a/arch/arm/mach-imx/imx_bootaux.c
+++ b/arch/arm/mach-imx/imx_bootaux.c
@@ -14,6 +14,71 @@
#include <linux/compiler.h>
#include <cpu_func.h>
+#ifndef CONFIG_IMX8M
+const __weak struct rproc_att hostmap[] = { };
+
+static const struct rproc_att *get_host_mapping(unsigned long auxcore)
+{
+ const struct rproc_att *mmap = hostmap;
+
+ while (mmap && mmap->size) {
+ if (mmap->da <= auxcore &&
+ mmap->da + mmap->size > auxcore)
+ return mmap;
+ mmap++;
+ }
+
+ return NULL;
+}
+
+/*
+ * A very simple elf loader for the auxilary core, assumes the image
+ * is valid, returns the entry point address.
+ * Translates load addresses in the elf file to the U-Boot address space.
+ */
+static unsigned long load_elf_image_m_core_phdr(unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* ELF header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ int i;
+
+ ehdr = (Elf32_Ehdr *)addr;
+ phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
+ const struct rproc_att *mmap = get_host_mapping(phdr->p_paddr);
+ void *dst, *src;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (!mmap) {
+ printf("Invalid aux core address: %08x",
+ phdr->p_paddr);
+ return 0;
+ }
+
+ dst = (void *)(phdr->p_paddr - mmap->da) + mmap->sa;
+ src = (void *)addr + phdr->p_offset;
+
+ debug("Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ if (phdr->p_filesz != phdr->p_memsz)
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ flush_cache((unsigned long)dst &
+ ~(CONFIG_SYS_CACHELINE_SIZE - 1),
+ ALIGN(phdr->p_filesz, CONFIG_SYS_CACHELINE_SIZE));
+ }
+
+ return ehdr->e_entry;
+}
+#endif
+
int arch_auxiliary_core_up(u32 core_id, ulong addr)
{
ulong stack, pc;
@@ -31,7 +96,7 @@ int arch_auxiliary_core_up(u32 core_id, ulong addr)
*/
if (valid_elf_image(addr)) {
stack = 0x0;
- pc = load_elf_image_phdr(addr);
+ pc = load_elf_image_m_core_phdr(addr);
if (!pc)
return CMD_RET_FAILURE;
diff --git a/arch/arm/mach-imx/mx7ulp/Kconfig b/arch/arm/mach-imx/mx7ulp/Kconfig
index 6680f856c5..2ffac9cf7c 100644
--- a/arch/arm/mach-imx/mx7ulp/Kconfig
+++ b/arch/arm/mach-imx/mx7ulp/Kconfig
@@ -9,6 +9,7 @@ config LDO_ENABLED_MODE
Select this option to enable the PMC1 LDO.
config MX7ULP
+ select HAS_CAAM
bool
choice
diff --git a/arch/arm/mach-imx/priblob.c b/arch/arm/mach-imx/priblob.c
new file mode 100644
index 0000000000..e253eddfdc
--- /dev/null
+++ b/arch/arm/mach-imx/priblob.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * Boot command to get and set the PRIBLOB bitfield form the SCFGR register
+ * of the CAAM IP. It is recommended to set this bitfield to 3 once your
+ * encrypted boot image is ready, to prevent the generation of blobs usable
+ * to decrypt an encrypted boot image.
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include "../drivers/crypto/fsl_caam_internal.h"
+
+int do_priblob_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ writel((readl(CAAM_SCFGR) & 0xFFFFFFFC) | 3, CAAM_SCFGR);
+ printf("New priblob setting = 0x%x\n", readl(CAAM_SCFGR) & 0x3);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ set_priblob_bitfield, 1, 0, do_priblob_write,
+ "Set the PRIBLOB bitfield to 3",
+ "<value>\n"
+ " - Write 3 in PRIBLOB bitfield of SCFGR regiter of CAAM IP.\n"
+ " Prevent the generation of blobs usable to decrypt an\n"
+ " encrypted boot image."
+);