summaryrefslogtreecommitdiff
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/Kconfig9
-rw-r--r--arch/arm/mach-imx/Makefile25
-rw-r--r--arch/arm/mach-imx/cmd_nandbcb.c2
-rw-r--r--arch/arm/mach-imx/cpu.c14
-rw-r--r--arch/arm/mach-imx/imx8/Kconfig13
-rw-r--r--arch/arm/mach-imx/imx8/Makefile7
-rw-r--r--arch/arm/mach-imx/imx8/cpu.c189
-rw-r--r--arch/arm/mach-imx/imx8/fdt.c292
-rw-r--r--arch/arm/mach-imx/imx8/image.c246
-rw-r--r--arch/arm/mach-imx/imx8/lowlevel_init.S36
-rw-r--r--arch/arm/mach-imx/imx8/parse-container.c120
-rw-r--r--arch/arm/mach-imx/imx8m/Kconfig17
-rw-r--r--arch/arm/mach-imx/imx8m/Makefile4
-rw-r--r--arch/arm/mach-imx/imx8m/clock_imx8mm.c306
-rw-r--r--arch/arm/mach-imx/imx8m/clock_imx8mq.c (renamed from arch/arm/mach-imx/imx8m/clock.c)5
-rw-r--r--arch/arm/mach-imx/imx8m/clock_slice.c63
-rw-r--r--arch/arm/mach-imx/imx8m/imximage-8mm-lpddr4.cfg16
-rw-r--r--arch/arm/mach-imx/imx8m/soc.c131
-rwxr-xr-xarch/arm/mach-imx/mkimage_fit_atf.sh10
-rw-r--r--arch/arm/mach-imx/mx6/Kconfig26
-rw-r--r--arch/arm/mach-imx/mx6/clock.c34
-rw-r--r--arch/arm/mach-imx/mx6/soc.c6
-rw-r--r--arch/arm/mach-imx/mx7/clock.c2
-rw-r--r--arch/arm/mach-imx/mx7/soc.c2
-rw-r--r--arch/arm/mach-imx/mx7ulp/Kconfig6
-rw-r--r--arch/arm/mach-imx/mx7ulp/clock.c10
-rw-r--r--arch/arm/mach-imx/mx7ulp/scg.c63
-rw-r--r--arch/arm/mach-imx/mx7ulp/soc.c40
-rw-r--r--arch/arm/mach-imx/spl.c36
-rw-r--r--arch/arm/mach-imx/spl_qspi.cfg17
-rw-r--r--arch/arm/mach-imx/spl_sd.cfg2
31 files changed, 1498 insertions, 251 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index aeb5493488..b0b9d2c070 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -34,7 +34,7 @@ config USE_IMXIMG_PLUGIN
i.MX6/7 supports DCD and Plugin. Enable this configuration
to use Plugin, otherwise DCD will be used.
-config SECURE_BOOT
+config IMX_HAB
bool "Support i.MX HAB features"
depends on ARCH_MX7 || ARCH_MX6 || ARCH_MX5
select FSL_CAAM if HAS_CAAM
@@ -43,6 +43,13 @@ config SECURE_BOOT
This option enables the support for secure boot (HAB).
See doc/README.mxc_hab for more details.
+config CSF_SIZE
+ hex "Maximum size for Command Sequence File (CSF) binary"
+ default 0x2060
+ help
+ Define the maximum size for Command Sequence File (CSF) binary
+ this information is used to define the image boot data.
+
config CMD_BMODE
bool "Support the 'bmode' command"
default y
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 08ee52edbf..fbd99a3499 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -44,12 +44,12 @@ ifneq ($(CONFIG_SPL_BUILD),y)
obj-$(CONFIG_IMX_BOOTAUX) += imx_bootaux.o
endif
obj-$(CONFIG_SATA) += sata.o
-obj-$(CONFIG_SECURE_BOOT) += hab.o
+obj-$(CONFIG_IMX_HAB) += hab.o
obj-$(CONFIG_SYSCOUNTER_TIMER) += syscounter.o
endif
ifeq ($(SOC),$(filter $(SOC),mx7ulp))
obj-y += cache.o
-obj-$(CONFIG_SECURE_BOOT) += hab.o
+obj-$(CONFIG_IMX_HAB) += hab.o
endif
ifeq ($(SOC),$(filter $(SOC),vf610))
obj-y += ddrmc-vf610.o
@@ -90,6 +90,11 @@ IMX_CONFIG = $(CONFIG_IMX_CONFIG:"%"=%)
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cpp_cfg)
+IMX_CONTAINER_CFG = $(CONFIG_IMX_CONTAINER_CFG:"%"=%)
+container.cfg: $(IMX_CONTAINER_CFG) FORCE
+ $(Q)mkdir -p $(dir $@)
+ $(call if_changed_dep,cpp_cfg)
+
ifeq ($(CONFIG_ARCH_IMX8), y)
CNTR_DEPFILES := $(srctree)/tools/imx_cntr_image.sh
IMAGE_TYPE := imx8image
@@ -158,8 +163,20 @@ SPL:
MKIMAGEFLAGS_flash.bin = -n spl/u-boot-spl.cfgout -T $(IMAGE_TYPE) -e 0x100000
flash.bin: MKIMAGEOUTPUT = flash.log
-flash.bin: spl/u-boot-spl.bin u-boot.itb FORCE
-ifeq ($(SPL_DEPFILE_EXISTS),0)
+MKIMAGEFLAGS_u-boot.cnt = -n container.cfg -T $(IMAGE_TYPE) -e 0x100000
+u-boot.cnt: MKIMAGEOUTPUT = u-boot.cnt.log
+
+ifeq ($(CONFIG_SPL_LOAD_IMX_CONTAINER), y)
+u-boot.cnt: u-boot.bin container.cfg FORCE
+ $(call if_changed,mkimage)
+flash.bin: spl/u-boot-spl.bin FORCE
+ $(call if_changed,mkimage)
+ @flashbin_size=`wc -c flash.bin | awk '{print $$1}'`; \
+ pad_cnt=$$(((flashbin_size + 0x400 - 1) / 0x400)); \
+ echo "append u-boot.cnt at $$pad_cnt KB"; \
+ dd if=u-boot.cnt of=flash.bin bs=1K seek=$$pad_cnt;
+else
+flash.bin: spl/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
endif
endif
diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c
index 065b814b2e..7811c61d22 100644
--- a/arch/arm/mach-imx/cmd_nandbcb.c
+++ b/arch/arm/mach-imx/cmd_nandbcb.c
@@ -359,9 +359,11 @@ usage:
return CMD_RET_USAGE;
}
+#ifdef CONFIG_SYS_LONGHELP
static char nandbcb_help_text[] =
"update addr off|partition len - update 'len' bytes starting at\n"
" 'off|part' to memory address 'addr', skipping bad blocks";
+#endif
U_BOOT_CMD(nandbcb, 5, 1, do_nandbcb,
"i.MX6 Nand BCB",
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index 6e9a175210..efd8fc614a 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -145,6 +145,18 @@ unsigned imx_ddr_size(void)
const char *get_imx_type(u32 imxtype)
{
switch (imxtype) {
+ case MXC_CPU_IMX8MM:
+ return "8MMQ"; /* Quad-core version of the imx8mm */
+ case MXC_CPU_IMX8MML:
+ return "8MMQL"; /* Quad-core Lite version of the imx8mm */
+ case MXC_CPU_IMX8MMD:
+ return "8MMD"; /* Dual-core version of the imx8mm */
+ case MXC_CPU_IMX8MMDL:
+ return "8MMDL"; /* Dual-core Lite version of the imx8mm */
+ case MXC_CPU_IMX8MMS:
+ return "8MMS"; /* Single-core version of the imx8mm */
+ case MXC_CPU_IMX8MMSL:
+ return "8MMSL"; /* Single-core Lite version of the imx8mm */
case MXC_CPU_IMX8MQ:
return "8MQ"; /* Quad-core version of the imx8m */
case MXC_CPU_MX7S:
@@ -173,6 +185,8 @@ const char *get_imx_type(u32 imxtype)
return "6UL"; /* Ultra-Lite version of the mx6 */
case MXC_CPU_MX6ULL:
return "6ULL"; /* ULL version of the mx6 */
+ case MXC_CPU_MX6ULZ:
+ return "6ULZ"; /* ULZ version of the mx6 */
case MXC_CPU_MX51:
return "51";
case MXC_CPU_MX53:
diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig
index bbe323d5ca..d17760e333 100644
--- a/arch/arm/mach-imx/imx8/Kconfig
+++ b/arch/arm/mach-imx/imx8/Kconfig
@@ -23,6 +23,19 @@ config IMX8QXP
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.
+
choice
prompt "i.MX8 board select"
optional
diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile
index 92b5c56acb..39e384d5c7 100644
--- a/arch/arm/mach-imx/imx8/Makefile
+++ b/arch/arm/mach-imx/imx8/Makefile
@@ -4,4 +4,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y += cpu.o iomux.o misc.o
+obj-y += cpu.o iomux.o misc.o lowlevel_init.o
+obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image.o parse-container.o
+endif
diff --git a/arch/arm/mach-imx/imx8/cpu.c b/arch/arm/mach-imx/imx8/cpu.c
index f2fa262ac8..d393a01178 100644
--- a/arch/arm/mach-imx/imx8/cpu.c
+++ b/arch/arm/mach-imx/imx8/cpu.c
@@ -60,18 +60,18 @@ int arch_cpu_init_dm(void)
int node, ret;
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx8-mu");
- ret = device_bind_driver_to_node(gd->dm_root, "imx8_scu", "imx8_scu",
- offset_to_ofnode(node), &devp);
+ ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
if (ret) {
- printf("could not find scu %d\n", ret);
+ printf("could not get scu %d\n", ret);
return ret;
}
- ret = device_probe(devp);
- if (ret) {
- printf("scu probe failed %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;
@@ -475,10 +475,17 @@ u64 get_page_table_size(void)
}
#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)
{
@@ -528,171 +535,3 @@ u32 get_cpu_rev(void)
return (id << 12) | rev;
}
-#if CONFIG_IS_ENABLED(CPU)
-struct cpu_imx_platdata {
- const char *name;
- const char *rev;
- const char *type;
- u32 cpurev;
- u32 freq_mhz;
-};
-
-const char *get_imx8_type(u32 imxtype)
-{
- switch (imxtype) {
- case MXC_CPU_IMX8QXP:
- case MXC_CPU_IMX8QXP_A0:
- return "QXP";
- case MXC_CPU_IMX8QM:
- return "QM";
- default:
- return "??";
- }
-}
-
-const char *get_imx8_rev(u32 rev)
-{
- switch (rev) {
- case CHIP_REV_A:
- return "A";
- case CHIP_REV_B:
- return "B";
- default:
- return "?";
- }
-}
-
-const char *get_core_name(void)
-{
- if (is_cortex_a35())
- return "A35";
- else if (is_cortex_a53())
- return "A53";
- else if (is_cortex_a72())
- return "A72";
- else
- return "?";
-}
-
-#if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
-static int cpu_imx_get_temp(void)
-{
- struct udevice *thermal_dev;
- int cpu_tmp, ret;
-
- ret = uclass_get_device_by_name(UCLASS_THERMAL, "cpu-thermal0",
- &thermal_dev);
-
- if (!ret) {
- ret = thermal_get_temp(thermal_dev, &cpu_tmp);
- if (ret)
- return 0xdeadbeef;
- } else {
- return 0xdeadbeef;
- }
-
- return cpu_tmp;
-}
-#else
-static int cpu_imx_get_temp(void)
-{
- return 0;
-}
-#endif
-
-int cpu_imx_get_desc(struct udevice *dev, char *buf, int size)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- if (size < 100)
- return -ENOSPC;
-
- ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
- plat->type, plat->rev, plat->name, plat->freq_mhz);
-
- if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
- buf = buf + ret;
- size = size - ret;
- ret = snprintf(buf, size, " at %dC", cpu_imx_get_temp());
- }
-
- snprintf(buf + ret, size - ret, "\n");
-
- return 0;
-}
-
-static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
-
- info->cpu_freq = plat->freq_mhz * 1000;
- info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
- return 0;
-}
-
-static int cpu_imx_get_count(struct udevice *dev)
-{
- return 4;
-}
-
-static int cpu_imx_get_vendor(struct udevice *dev, char *buf, int size)
-{
- snprintf(buf, size, "NXP");
- return 0;
-}
-
-static const struct cpu_ops cpu_imx8_ops = {
- .get_desc = cpu_imx_get_desc,
- .get_info = cpu_imx_get_info,
- .get_count = cpu_imx_get_count,
- .get_vendor = cpu_imx_get_vendor,
-};
-
-static const struct udevice_id cpu_imx8_ids[] = {
- { .compatible = "arm,cortex-a35" },
- { .compatible = "arm,cortex-a53" },
- { }
-};
-
-static ulong imx8_get_cpu_rate(void)
-{
- ulong rate;
- int ret;
- int type = is_cortex_a35() ? SC_R_A35 : is_cortex_a53() ?
- SC_R_A53 : SC_R_A72;
-
- ret = sc_pm_get_clock_rate(-1, type, SC_PM_CLK_CPU,
- (sc_pm_clock_rate_t *)&rate);
- if (ret) {
- printf("Could not read CPU frequency: %d\n", ret);
- return 0;
- }
-
- return rate;
-}
-
-static int imx8_cpu_probe(struct udevice *dev)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
- u32 cpurev;
-
- cpurev = get_cpu_rev();
- plat->cpurev = cpurev;
- plat->name = get_core_name();
- plat->rev = get_imx8_rev(cpurev & 0xFFF);
- plat->type = get_imx8_type((cpurev & 0xFF000) >> 12);
- plat->freq_mhz = imx8_get_cpu_rate() / 1000000;
- return 0;
-}
-
-U_BOOT_DRIVER(cpu_imx8_drv) = {
- .name = "imx8x_cpu",
- .id = UCLASS_CPU,
- .of_match = cpu_imx8_ids,
- .ops = &cpu_imx8_ops,
- .probe = imx8_cpu_probe,
- .platdata_auto_alloc_size = sizeof(struct cpu_imx_platdata),
- .flags = DM_FLAG_PRE_RELOC,
-};
-#endif
diff --git a/arch/arm/mach-imx/imx8/fdt.c b/arch/arm/mach-imx/imx8/fdt.c
new file mode 100644
index 0000000000..65c8ac1a7e
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/fdt.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+#include <dm/ofnode.h>
+#include <fdt_support.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;
+
+ if (!check_owned_resource(rsrc)) {
+ printf("%s rsrc[%d] not owned\n", __func__, rsrc);
+ return -1;
+ }
+ 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) {
+ 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, bd_t *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, bd_t *bd)
+{
+ int ret;
+
+ 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/arch/arm/mach-imx/imx8/image.c b/arch/arm/mach-imx/imx8/image.c
new file mode 100644
index 0000000000..58a29e8a03
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/image.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <errno.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)
+{
+ 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/arch/arm/mach-imx/imx8/lowlevel_init.S b/arch/arm/mach-imx/imx8/lowlevel_init.S
new file mode 100644
index 0000000000..a66243c5e4
--- /dev/null
+++ b/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/arch/arm/mach-imx/imx8/parse-container.c b/arch/arm/mach-imx/imx8/parse-container.c
new file mode 100644
index 0000000000..32f78bdddf
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/parse-container.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <spl.h>
+#include <asm/arch/image.h>
+
+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;
+ }
+
+ 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;
+
+ 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;
+ }
+
+ for (i = 0; i < container->num_images; i++) {
+ struct boot_img_t *image = read_auth_image(spl_image, info,
+ container, i,
+ sector);
+
+ if (!image)
+ return -EINVAL;
+
+ if (i == 0) {
+ spl_image->load_addr = image->dst;
+ spl_image->entry_point = image->entry;
+ }
+ }
+
+ return 0;
+}
+
+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/arch/arm/mach-imx/imx8m/Kconfig b/arch/arm/mach-imx/imx8m/Kconfig
index 317dee9bc1..f520075875 100644
--- a/arch/arm/mach-imx/imx8m/Kconfig
+++ b/arch/arm/mach-imx/imx8m/Kconfig
@@ -4,6 +4,14 @@ config IMX8M
bool
select ROM_UNIFIED_SECTIONS
+config IMX8MQ
+ bool
+ select IMX8M
+
+config IMX8MM
+ bool
+ select IMX8M
+
config SYS_SOC
default "imx8m"
@@ -13,11 +21,18 @@ choice
config TARGET_IMX8MQ_EVK
bool "imx8mq_evk"
- select IMX8M
+ select IMX8MQ
+ select IMX8M_LPDDR4
+
+config TARGET_IMX8MM_EVK
+ bool "imx8mm LPDDR4 EVK board"
+ select IMX8MM
+ select SUPPORT_SPL
select IMX8M_LPDDR4
endchoice
source "board/freescale/imx8mq_evk/Kconfig"
+source "board/freescale/imx8mm_evk/Kconfig"
endif
diff --git a/arch/arm/mach-imx/imx8m/Makefile b/arch/arm/mach-imx/imx8m/Makefile
index feff4941c1..92184f3135 100644
--- a/arch/arm/mach-imx/imx8m/Makefile
+++ b/arch/arm/mach-imx/imx8m/Makefile
@@ -3,4 +3,6 @@
# Copyright 2017 NXP
obj-y += lowlevel_init.o
-obj-y += clock.o clock_slice.o soc.o
+obj-y += clock_slice.o soc.o
+obj-$(CONFIG_IMX8MQ) += clock_imx8mq.o
+obj-$(CONFIG_IMX8MM) += clock_imx8mm.o
diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
new file mode 100644
index 0000000000..ee44ba75fe
--- /dev/null
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2019 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dt-bindings/clock/imx8mm-clock.h>
+#include <div64.h>
+#include <errno.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
+
+void enable_ocotp_clk(unsigned char enable)
+{
+ struct clk *clkp;
+ int ret;
+
+ ret = clk_get_by_id(IMX8MM_CLK_OCOTP_ROOT, &clkp);
+ if (ret) {
+ printf("%s: err: %d\n", __func__, ret);
+ return;
+ }
+
+ enable ? clk_enable(clkp) : clk_disable(clkp);
+}
+
+int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
+{
+ struct clk *clkp;
+ int ret;
+
+ ret = clk_get_by_id(IMX8MM_CLK_I2C1_ROOT + i2c_num, &clkp);
+ if (ret) {
+ printf("%s: err: %d\n", __func__, ret);
+ return ret;
+ }
+
+ return enable ? clk_enable(clkp) : clk_disable(clkp);
+}
+
+#ifdef CONFIG_SPL_BUILD
+static struct imx_int_pll_rate_table imx8mm_fracpll_tbl[] = {
+ PLL_1443X_RATE(800000000U, 300, 9, 0, 0),
+ PLL_1443X_RATE(750000000U, 250, 8, 0, 0),
+ PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+ PLL_1443X_RATE(600000000U, 300, 3, 2, 0),
+ PLL_1443X_RATE(594000000U, 99, 1, 2, 0),
+ PLL_1443X_RATE(400000000U, 300, 9, 1, 0),
+ PLL_1443X_RATE(266666667U, 400, 9, 2, 0),
+ PLL_1443X_RATE(167000000U, 334, 3, 4, 0),
+ PLL_1443X_RATE(100000000U, 300, 9, 3, 0),
+};
+
+int fracpll_configure(enum pll_clocks pll, u32 freq)
+{
+ int i;
+ u32 tmp, div_val;
+ void *pll_base;
+ struct imx_int_pll_rate_table *rate;
+
+ for (i = 0; i < ARRAY_SIZE(imx8mm_fracpll_tbl); i++) {
+ if (freq == imx8mm_fracpll_tbl[i].rate)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(imx8mm_fracpll_tbl)) {
+ printf("No matched freq table %u\n", freq);
+ return -EINVAL;
+ }
+
+ rate = &imx8mm_fracpll_tbl[i];
+
+ switch (pll) {
+ case ANATOP_DRAM_PLL:
+ setbits_le32(GPC_BASE_ADDR + 0xEC, 1 << 7);
+ setbits_le32(GPC_BASE_ADDR + 0xF8, 1 << 5);
+ writel(SRC_DDR1_ENABLE_MASK, SRC_BASE_ADDR + 0x1004);
+
+ pll_base = &ana_pll->dram_pll_gnrl_ctl;
+ break;
+ case ANATOP_VIDEO_PLL:
+ pll_base = &ana_pll->video_pll1_gnrl_ctl;
+ break;
+ default:
+ return 0;
+ }
+ /* Bypass clock and set lock to pll output lock */
+ tmp = readl(pll_base);
+ tmp |= BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ /* Enable RST */
+ tmp &= ~RST_MASK;
+ writel(tmp, pll_base);
+
+ div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+ (rate->sdiv << SDIV_SHIFT);
+ writel(div_val, pll_base + 4);
+ writel(rate->kdiv << KDIV_SHIFT, pll_base + 8);
+
+ __udelay(100);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel(tmp, pll_base);
+
+ /* Wait Lock*/
+ while (!(readl(pll_base) & LOCK_STATUS))
+ ;
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel(tmp, pll_base);
+
+ return 0;
+}
+
+void dram_pll_init(ulong pll_val)
+{
+ fracpll_configure(ANATOP_DRAM_PLL, pll_val);
+}
+
+static struct dram_bypass_clk_setting imx8mm_dram_bypass_tbl[] = {
+ DRAM_BYPASS_ROOT_CONFIG(MHZ(100), 2, CLK_ROOT_PRE_DIV1, 2,
+ CLK_ROOT_PRE_DIV2),
+ DRAM_BYPASS_ROOT_CONFIG(MHZ(250), 3, CLK_ROOT_PRE_DIV2, 2,
+ CLK_ROOT_PRE_DIV2),
+ DRAM_BYPASS_ROOT_CONFIG(MHZ(400), 1, CLK_ROOT_PRE_DIV2, 3,
+ CLK_ROOT_PRE_DIV2),
+};
+
+void dram_enable_bypass(ulong clk_val)
+{
+ int i;
+ struct dram_bypass_clk_setting *config;
+
+ for (i = 0; i < ARRAY_SIZE(imx8mm_dram_bypass_tbl); i++) {
+ if (clk_val == imx8mm_dram_bypass_tbl[i].clk)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(imx8mm_dram_bypass_tbl)) {
+ printf("No matched freq table %lu\n", clk_val);
+ return;
+ }
+
+ config = &imx8mm_dram_bypass_tbl[i];
+
+ clock_set_target_val(DRAM_ALT_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(config->alt_root_sel) |
+ CLK_ROOT_PRE_DIV(config->alt_pre_div));
+ clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(config->apb_root_sel) |
+ CLK_ROOT_PRE_DIV(config->apb_pre_div));
+ clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(1));
+}
+
+void dram_disable_bypass(void)
+{
+ clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(4) |
+ CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV5));
+}
+#endif
+
+void init_uart_clk(u32 index)
+{
+ /*
+ * set uart clock root
+ * 24M OSC
+ */
+ switch (index) {
+ case 0:
+ clock_enable(CCGR_UART1, 0);
+ clock_set_target_val(UART1_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_enable(CCGR_UART1, 1);
+ return;
+ case 1:
+ clock_enable(CCGR_UART2, 0);
+ clock_set_target_val(UART2_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_enable(CCGR_UART2, 1);
+ return;
+ case 2:
+ clock_enable(CCGR_UART3, 0);
+ clock_set_target_val(UART3_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_enable(CCGR_UART3, 1);
+ return;
+ case 3:
+ clock_enable(CCGR_UART4, 0);
+ clock_set_target_val(UART4_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_enable(CCGR_UART4, 1);
+ return;
+ default:
+ printf("Invalid uart index\n");
+ return;
+ }
+}
+
+void init_wdog_clk(void)
+{
+ clock_enable(CCGR_WDOG1, 0);
+ clock_enable(CCGR_WDOG2, 0);
+ clock_enable(CCGR_WDOG3, 0);
+ clock_set_target_val(WDOG_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(0));
+ clock_enable(CCGR_WDOG1, 1);
+ clock_enable(CCGR_WDOG2, 1);
+ clock_enable(CCGR_WDOG3, 1);
+}
+
+int clock_init(void)
+{
+ u32 val_cfg0;
+
+ /*
+ * The gate is not exported to clk tree, so configure them here.
+ * According to ANAMIX SPEC
+ * sys pll1 fixed at 800MHz
+ * sys pll2 fixed at 1GHz
+ * Here we only enable the outputs.
+ */
+ val_cfg0 = readl(&ana_pll->sys_pll1_gnrl_ctl);
+ val_cfg0 |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
+ INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
+ INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
+ INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
+ INTPLL_DIV20_CLKE_MASK;
+ writel(val_cfg0, &ana_pll->sys_pll1_gnrl_ctl);
+
+ val_cfg0 = readl(&ana_pll->sys_pll2_gnrl_ctl);
+ val_cfg0 |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
+ INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
+ INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
+ INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
+ INTPLL_DIV20_CLKE_MASK;
+ writel(val_cfg0, &ana_pll->sys_pll2_gnrl_ctl);
+
+ /* config GIC to sys_pll2_100m */
+ clock_enable(CCGR_GIC, 0);
+ clock_set_target_val(GIC_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(3));
+ clock_enable(CCGR_GIC, 1);
+
+ clock_set_target_val(NAND_USDHC_BUS_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(1));
+
+ clock_enable(CCGR_DDR1, 0);
+ clock_set_target_val(DRAM_ALT_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(1));
+ clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
+ CLK_ROOT_SOURCE_SEL(1));
+ clock_enable(CCGR_DDR1, 1);
+
+ init_wdog_clk();
+
+ clock_enable(CCGR_TEMP_SENSOR, 1);
+
+ clock_enable(CCGR_SEC_DEBUG, 1);
+
+ return 0;
+};
+
+u32 imx_get_uartclk(void)
+{
+ return 24000000U;
+}
+
+u32 mxc_get_clock(enum mxc_clock clk)
+{
+ struct clk *clkp;
+ int ret;
+
+ switch (clk) {
+ case MXC_IPG_CLK:
+ ret = clk_get_by_id(IMX8MM_CLK_IPG_ROOT, &clkp);
+ if (ret)
+ return 0;
+ return clk_get_rate(clkp);
+ case MXC_ARM_CLK:
+ ret = clk_get_by_id(IMX8MM_CLK_A53_DIV, &clkp);
+ if (ret)
+ return 0;
+ return clk_get_rate(clkp);
+ default:
+ printf("%s: %d not supported\n", __func__, clk);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-imx/imx8m/clock.c b/arch/arm/mach-imx/imx8m/clock_imx8mq.c
index 289b9417aa..feecdb50f6 100644
--- a/arch/arm/mach-imx/imx8m/clock.c
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mq.c
@@ -322,13 +322,10 @@ int enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
return 0;
}
-unsigned int mxc_get_clock(enum clk_root_index clk)
+unsigned int mxc_get_clock(enum mxc_clock clk)
{
u32 val;
- if (clk >= CLK_ROOT_MAX)
- return 0;
-
if (clk == MXC_ARM_CLK)
return get_root_clk(ARM_A53_CLK_ROOT);
diff --git a/arch/arm/mach-imx/imx8m/clock_slice.c b/arch/arm/mach-imx/imx8m/clock_slice.c
index 1a67c626f1..780f64314d 100644
--- a/arch/arm/mach-imx/imx8m/clock_slice.c
+++ b/arch/arm/mach-imx/imx8m/clock_slice.c
@@ -13,6 +13,7 @@
static struct ccm_reg *ccm_reg = (struct ccm_reg *)CCM_BASE_ADDR;
+#ifdef CONFIG_IMX8MQ
static struct clk_root_map root_array[] = {
{ARM_A53_CLK_ROOT, CORE_CLOCK_SLICE, 0,
{OSC_25M_CLK, ARM_PLL_CLK, SYSTEM_PLL2_500M_CLK,
@@ -474,6 +475,68 @@ static struct clk_root_map root_array[] = {
{DRAM_PLL1_CLK}
},
};
+#elif defined(CONFIG_IMX8MM)
+static struct clk_root_map root_array[] = {
+ {NAND_USDHC_BUS_CLK_ROOT, BUS_CLOCK_SLICE, 2,
+ {OSC_24M_CLK, SYSTEM_PLL1_266M_CLK, SYSTEM_PLL1_800M_CLK,
+ SYSTEM_PLL2_200M_CLK, SYSTEM_PLL1_133M_CLK,
+ SYSTEM_PLL3_CLK, SYSTEM_PLL2_250M_CLK, AUDIO_PLL1_CLK}
+ },
+ {NOC_CLK_ROOT, BUS_CLOCK_SLICE, 10,
+ {OSC_24M_CLK, SYSTEM_PLL1_800M_CLK, SYSTEM_PLL3_CLK,
+ SYSTEM_PLL2_1000M_CLK, SYSTEM_PLL2_500M_CLK,
+ AUDIO_PLL1_CLK, VIDEO_PLL_CLK, AUDIO_PLL2_CLK}
+ },
+ {NOC_APB_CLK_ROOT, BUS_CLOCK_SLICE, 11,
+ {OSC_24M_CLK, SYSTEM_PLL1_400M_CLK, SYSTEM_PLL3_CLK,
+ SYSTEM_PLL2_333M_CLK, SYSTEM_PLL2_200M_CLK,
+ SYSTEM_PLL1_800M_CLK, AUDIO_PLL1_CLK, VIDEO_PLL_CLK}
+ },
+ {DRAM_ALT_CLK_ROOT, IP_CLOCK_SLICE, 0,
+ {OSC_24M_CLK, SYSTEM_PLL1_800M_CLK, SYSTEM_PLL1_100M_CLK,
+ SYSTEM_PLL2_500M_CLK, SYSTEM_PLL2_1000M_CLK,
+ SYSTEM_PLL3_CLK, AUDIO_PLL1_CLK, SYSTEM_PLL1_266M_CLK}
+ },
+ {DRAM_APB_CLK_ROOT, IP_CLOCK_SLICE, 1,
+ {OSC_24M_CLK, SYSTEM_PLL2_200M_CLK, SYSTEM_PLL1_40M_CLK,
+ SYSTEM_PLL1_160M_CLK, SYSTEM_PLL1_800M_CLK,
+ SYSTEM_PLL3_CLK, SYSTEM_PLL2_250M_CLK, AUDIO_PLL2_CLK}
+ },
+ {UART1_CLK_ROOT, IP_CLOCK_SLICE, 30,
+ {OSC_24M_CLK, SYSTEM_PLL1_80M_CLK, SYSTEM_PLL2_200M_CLK,
+ SYSTEM_PLL2_100M_CLK, SYSTEM_PLL3_CLK,
+ EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK}
+ },
+ {UART2_CLK_ROOT, IP_CLOCK_SLICE, 31,
+ {OSC_24M_CLK, SYSTEM_PLL1_80M_CLK, SYSTEM_PLL2_200M_CLK,
+ SYSTEM_PLL2_100M_CLK, SYSTEM_PLL3_CLK,
+ EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK}
+ },
+ {UART3_CLK_ROOT, IP_CLOCK_SLICE, 32,
+ {OSC_24M_CLK, SYSTEM_PLL1_80M_CLK, SYSTEM_PLL2_200M_CLK,
+ SYSTEM_PLL2_100M_CLK, SYSTEM_PLL3_CLK,
+ EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK}
+ },
+ {UART4_CLK_ROOT, IP_CLOCK_SLICE, 33,
+ {OSC_24M_CLK, SYSTEM_PLL1_80M_CLK, SYSTEM_PLL2_200M_CLK,
+ SYSTEM_PLL2_100M_CLK, SYSTEM_PLL3_CLK,
+ EXT_CLK_2, EXT_CLK_3, AUDIO_PLL2_CLK}
+ },
+ {GIC_CLK_ROOT, IP_CLOCK_SLICE, 36,
+ {OSC_24M_CLK, SYSTEM_PLL2_200M_CLK, SYSTEM_PLL1_40M_CLK,
+ SYSTEM_PLL2_100M_CLK, SYSTEM_PLL1_800M_CLK,
+ EXT_CLK_2, EXT_CLK_4, AUDIO_PLL2_CLK}
+ },
+ {WDOG_CLK_ROOT, IP_CLOCK_SLICE, 50,
+ {OSC_24M_CLK, SYSTEM_PLL1_133M_CLK, SYSTEM_PLL1_160M_CLK,
+ VPU_PLL_CLK, SYSTEM_PLL2_125M_CLK,
+ SYSTEM_PLL3_CLK, SYSTEM_PLL1_80M_CLK, SYSTEM_PLL2_166M_CLK}
+ },
+ {DRAM_SEL_CFG, DRAM_SEL_CLOCK_SLICE, 0,
+ {DRAM_PLL1_CLK}
+ },
+};
+#endif
static int select(enum clk_root_index clock_id)
{
diff --git a/arch/arm/mach-imx/imx8m/imximage-8mm-lpddr4.cfg b/arch/arm/mach-imx/imx8m/imximage-8mm-lpddr4.cfg
new file mode 100644
index 0000000000..1a2e43e671
--- /dev/null
+++ b/arch/arm/mach-imx/imx8m/imximage-8mm-lpddr4.cfg
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#define __ASSEMBLY__
+
+FIT
+BOOT_FROM sd
+LOADER spl/u-boot-spl-ddr.bin 0x7E1000
+SECOND_LOADER u-boot.itb 0x40200000 0x60000
+
+DDR_FW lpddr4_pmu_train_1d_imem.bin
+DDR_FW lpddr4_pmu_train_1d_dmem.bin
+DDR_FW lpddr4_pmu_train_2d_imem.bin
+DDR_FW lpddr4_pmu_train_2d_dmem.bin
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index 7ec39b3e47..aeca82cdbf 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -14,6 +14,7 @@
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/syscounter.h>
#include <asm/armv8/mmu.h>
+#include <dm/uclass.h>
#include <errno.h>
#include <fdt_support.h>
#include <fsl_wdog.h>
@@ -21,7 +22,7 @@
DECLARE_GLOBAL_DATA_PTR;
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
.bank = 1,
.word = 3,
@@ -55,6 +56,14 @@ void enable_tzc380(void)
/* Enable TZASC and lock setting */
setbits_le32(&gpr->gpr[10], GPR_TZASC_EN);
setbits_le32(&gpr->gpr[10], GPR_TZASC_EN_LOCK);
+ if (IS_ENABLED(CONFIG_IMX8MM))
+ setbits_le32(&gpr->gpr[10], BIT(1));
+ /*
+ * set Region 0 attribute to allow secure and non-secure
+ * read/write permission. Found some masters like usb dwc3
+ * controllers can't work with secure memory.
+ */
+ writel(0xf0000000, TZASC_BASE_ADDR + 0x108);
}
void set_wdog_reset(struct wdog_regs *wdog)
@@ -112,16 +121,18 @@ static struct mm_region imx8m_mem_map[] = {
/* DRAM1 */
.virt = 0x40000000UL,
.phys = 0x40000000UL,
- .size = 0xC0000000UL,
+ .size = PHYS_SDRAM_SIZE,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_OUTER_SHARE
+#ifdef PHYS_SDRAM_2_SIZE
}, {
/* DRAM2 */
.virt = 0x100000000UL,
.phys = 0x100000000UL,
- .size = 0x040000000UL,
+ .size = PHYS_SDRAM_2_SIZE,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_OUTER_SHARE
+#endif
}, {
/* List terminator */
0,
@@ -130,25 +141,76 @@ static struct mm_region imx8m_mem_map[] = {
struct mm_region *mem_map = imx8m_mem_map;
+void enable_caches(void)
+{
+ /*
+ * If OPTEE runs, remove OPTEE memory from MMU table to
+ * avoid speculative prefetch. OPTEE runs at the top of
+ * the first memory bank
+ */
+ if (rom_pointer[1])
+ imx8m_mem_map[5].size -= rom_pointer[1];
+
+ icache_enable();
+ dcache_enable();
+}
+
+static u32 get_cpu_variant_type(u32 type)
+{
+ struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+ struct fuse_bank *bank = &ocotp->bank[1];
+ struct fuse_bank1_regs *fuse =
+ (struct fuse_bank1_regs *)bank->fuse_regs;
+
+ u32 value = readl(&fuse->tester4);
+
+ if (type == MXC_CPU_IMX8MM) {
+ switch (value & 0x3) {
+ case 2:
+ if (value & 0x1c0000)
+ return MXC_CPU_IMX8MMDL;
+ else
+ return MXC_CPU_IMX8MMD;
+ case 3:
+ if (value & 0x1c0000)
+ return MXC_CPU_IMX8MMSL;
+ else
+ return MXC_CPU_IMX8MMS;
+ default:
+ if (value & 0x1c0000)
+ return MXC_CPU_IMX8MML;
+ break;
+ }
+ }
+
+ return type;
+}
+
u32 get_cpu_rev(void)
{
struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
u32 reg = readl(&ana_pll->digprog);
u32 type = (reg >> 16) & 0xff;
+ u32 major_low = (reg >> 8) & 0xff;
u32 rom_version;
reg &= 0xff;
- if (reg == CHIP_REV_1_0) {
- /*
- * For B0 chip, the DIGPROG is not updated, still TO1.0.
- * we have to check ROM version further
- */
- rom_version = readl((void __iomem *)ROM_VERSION_A0);
- if (rom_version != CHIP_REV_1_0) {
- rom_version = readl((void __iomem *)ROM_VERSION_B0);
- if (rom_version >= CHIP_REV_2_0)
- reg = CHIP_REV_2_0;
+ /* i.MX8MM */
+ if (major_low == 0x41) {
+ type = get_cpu_variant_type(MXC_CPU_IMX8MM);
+ } else {
+ if (reg == CHIP_REV_1_0) {
+ /*
+ * For B0 chip, the DIGPROG is not updated, still TO1.0.
+ * we have to check ROM version further
+ */
+ rom_version = readl((void __iomem *)ROM_VERSION_A0);
+ if (rom_version != CHIP_REV_1_0) {
+ rom_version = readl((void __iomem *)ROM_VERSION_B0);
+ if (rom_version >= CHIP_REV_2_0)
+ reg = CHIP_REV_2_0;
+ }
}
}
@@ -167,10 +229,32 @@ static void imx_set_wdog_powerdown(bool enable)
writew(enable, &wdog3->wmcr);
}
+int arch_cpu_init_dm(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK,
+ "clock-controller@30380000",
+ &dev);
+ if (ret < 0) {
+ printf("Failed to find clock node. Check device tree\n");
+ return ret;
+ }
+
+ return 0;
+}
+
int arch_cpu_init(void)
{
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
/*
+ * ROM might disable clock for SCTR,
+ * enable the clock before timer_init.
+ */
+ if (IS_ENABLED(CONFIG_SPL_BUILD))
+ clock_enable(CCGR_SCTR, 1);
+ /*
* Init timer at very early state, because sscg pll setting
* will use it
*/
@@ -234,16 +318,21 @@ int ft_system_setup(void *blob, bd_t *bd)
}
#endif
+#if defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SYSRESET)
void reset_cpu(ulong addr)
{
- struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
+ struct watchdog_regs *wdog = (struct watchdog_regs *)addr;
- /* Clear WDA to trigger WDOG_B immediately */
- writew((WCR_WDE | WCR_SRS), &wdog->wcr);
+ if (!addr)
+ wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
- while (1) {
- /*
- * spin for .5 seconds before reset
- */
- }
+ /* Clear WDA to trigger WDOG_B immediately */
+ writew((WCR_WDE | WCR_SRS), &wdog->wcr);
+
+ while (1) {
+ /*
+ * spin for .5 seconds before reset
+ */
+ }
}
+#endif
diff --git a/arch/arm/mach-imx/mkimage_fit_atf.sh b/arch/arm/mach-imx/mkimage_fit_atf.sh
index 38c9858e84..ad81d5ecab 100755
--- a/arch/arm/mach-imx/mkimage_fit_atf.sh
+++ b/arch/arm/mach-imx/mkimage_fit_atf.sh
@@ -55,6 +55,7 @@ cat << __HEADER_EOF
images {
uboot@1 {
description = "U-Boot (64-bit)";
+ os = "u-boot";
data = /incbin/("$BL33");
type = "standalone";
arch = "arm64";
@@ -63,6 +64,7 @@ cat << __HEADER_EOF
};
atf@1 {
description = "ARM Trusted Firmware";
+ os = "arm-trusted-firmware";
data = /incbin/("$BL31");
type = "firmware";
arch = "arm64";
@@ -114,8 +116,8 @@ if [ -f $BL32 ]; then
cat << __CONF_SECTION_EOF
config@$cnt {
description = "$(basename $dtname .dtb)";
- firmware = "uboot@1";
- loadables = "atf@1", "tee@1";
+ firmware = "atf@1";
+ loadables = "uboot@1", "tee@1";
fdt = "fdt@$cnt";
};
__CONF_SECTION_EOF
@@ -123,8 +125,8 @@ else
cat << __CONF_SECTION1_EOF
config@$cnt {
description = "$(basename $dtname .dtb)";
- firmware = "uboot@1";
- loadables = "atf@1";
+ firmware = "atf@1";
+ loadables = "uboot@1";
fdt = "fdt@$cnt";
};
__CONF_SECTION1_EOF
diff --git a/arch/arm/mach-imx/mx6/Kconfig b/arch/arm/mach-imx/mx6/Kconfig
index fe5991e7c6..7e5a667e81 100644
--- a/arch/arm/mach-imx/mx6/Kconfig
+++ b/arch/arm/mach-imx/mx6/Kconfig
@@ -87,6 +87,15 @@ config MX6ULL
select SYSCOUNTER_TIMER
select SYS_L2CACHE_OFF
+config MX6_OCRAM_256KB
+ bool "Support 256KB OCRAM"
+ depends on MX6D || MX6Q
+ help
+ Allows using the full 256KB size of the OCRAM on the MX6Q/MX6D series
+ of chips, such as for SPL. The OCRAM of the Lite series of chips is
+ only 128KB, so using this option will prevent the resulting code from
+ working on those chips.
+
config MX6_DDRCAL
bool "Include dynamic DDR calibration routines"
depends on SPL
@@ -108,6 +117,7 @@ config TARGET_ADVANTECH_DMS_BA16
config TARGET_APALIS_IMX6
bool "Toradex Apalis iMX6 board"
select BOARD_LATE_INIT
+ select MX6Q
select DM
select DM_SERIAL
select DM_THERMAL
@@ -187,6 +197,11 @@ config TARGET_DHCOMIMX6
config TARGET_DISPLAY5
bool "LWN DISPLAY5 board"
select DM
+ select DM_ETH
+ select DM_I2C
+ select DM_MMC
+ select DM_SPI
+ select DM_GPIO
select DM_SERIAL
select SUPPORT_SPL
imply CMD_DM
@@ -412,6 +427,16 @@ config TARGET_OT1200
select SUPPORT_SPL
imply CMD_SATA
+config TARGET_PICO_IMX6
+ bool "PICO-IMX6"
+ select BOARD_EARLY_INIT_F
+ select BOARD_LATE_INIT
+ select DM
+ select DM_THERMAL
+ select MX6QDL
+ select SUPPORT_SPL
+ imply CMD_DM
+
config TARGET_PICO_IMX6UL
bool "PICO-IMX6UL-EMMC"
select MX6UL
@@ -599,6 +624,7 @@ source "board/logicpd/imx6/Kconfig"
source "board/seco/Kconfig"
source "board/sks-kinkel/sksimx6/Kconfig"
source "board/solidrun/mx6cuboxi/Kconfig"
+source "board/technexion/pico-imx6/Kconfig"
source "board/technexion/pico-imx6ul/Kconfig"
source "board/tbs/tbs2910/Kconfig"
source "board/tqc/tqma6/Kconfig"
diff --git a/arch/arm/mach-imx/mx6/clock.c b/arch/arm/mach-imx/mx6/clock.c
index 366a4e3c6b..7763c79e1c 100644
--- a/arch/arm/mach-imx/mx6/clock.c
+++ b/arch/arm/mach-imx/mx6/clock.c
@@ -1152,7 +1152,7 @@ int enable_pcie_clock(void)
}
#endif
-#ifdef CONFIG_SECURE_BOOT
+#ifdef CONFIG_IMX_HAB
void hab_caam_clock_enable(unsigned char enable)
{
u32 reg;
@@ -1275,6 +1275,22 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
return 0;
}
+#ifndef CONFIG_MX6SX
+void enable_ipu_clock(void)
+{
+ struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+ int reg;
+ reg = readl(&mxc_ccm->CCGR3);
+ reg |= MXC_CCM_CCGR3_IPU1_IPU_MASK;
+ writel(reg, &mxc_ccm->CCGR3);
+
+ if (is_mx6dqp()) {
+ setbits_le32(&mxc_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
+ setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
+ }
+}
+#endif
+
#ifndef CONFIG_SPL_BUILD
/*
* Dump some core clockes.
@@ -1311,22 +1327,6 @@ int do_mx6_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return 0;
}
-#ifndef CONFIG_MX6SX
-void enable_ipu_clock(void)
-{
- struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- int reg;
- reg = readl(&mxc_ccm->CCGR3);
- reg |= MXC_CCM_CCGR3_IPU1_IPU_MASK;
- writel(reg, &mxc_ccm->CCGR3);
-
- if (is_mx6dqp()) {
- setbits_le32(&mxc_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
- setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
- }
-}
-#endif
-
#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6D) || defined(CONFIG_MX6DL) || \
defined(CONFIG_MX6S)
static void disable_ldb_di_clock_sources(void)
diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c
index 075d2467ce..6dccee484c 100644
--- a/arch/arm/mach-imx/mx6/soc.c
+++ b/arch/arm/mach-imx/mx6/soc.c
@@ -50,7 +50,7 @@ U_BOOT_DEVICE(imx6_thermal) = {
};
#endif
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
.bank = 0,
.word = 6,
@@ -85,6 +85,10 @@ u32 get_cpu_rev(void)
type = MXC_CPU_MX6D;
}
+ if (type == MXC_CPU_MX6ULL) {
+ if (readl(SRC_BASE_ADDR + 0x1c) & (1 << 6))
+ type = MXC_CPU_MX6ULZ;
+ }
}
major = ((reg >> 8) & 0xff);
if ((major >= 1) &&
diff --git a/arch/arm/mach-imx/mx7/clock.c b/arch/arm/mach-imx/mx7/clock.c
index 4f9724cadb..0e08cabb7a 100644
--- a/arch/arm/mach-imx/mx7/clock.c
+++ b/arch/arm/mach-imx/mx7/clock.c
@@ -1074,7 +1074,7 @@ void clock_init(void)
}
}
-#ifdef CONFIG_SECURE_BOOT
+#ifdef CONFIG_IMX_HAB
void hab_caam_clock_enable(unsigned char enable)
{
if (enable)
diff --git a/arch/arm/mach-imx/mx7/soc.c b/arch/arm/mach-imx/mx7/soc.c
index 3b8e1ba9c3..35160f4b37 100644
--- a/arch/arm/mach-imx/mx7/soc.c
+++ b/arch/arm/mach-imx/mx7/soc.c
@@ -122,7 +122,7 @@ static void isolate_resource(void)
}
#endif
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
.bank = 1,
.word = 3,
diff --git a/arch/arm/mach-imx/mx7ulp/Kconfig b/arch/arm/mach-imx/mx7ulp/Kconfig
index d4b0299dbd..ed5f0aeb2d 100644
--- a/arch/arm/mach-imx/mx7ulp/Kconfig
+++ b/arch/arm/mach-imx/mx7ulp/Kconfig
@@ -3,12 +3,16 @@ if ARCH_MX7ULP
config SYS_SOC
default "mx7ulp"
+config MX7ULP
+ bool
+
choice
prompt "MX7ULP board select"
optional
config TARGET_MX7ULP_EVK
- bool "Support mx7ulp EVK board"
+ bool "Support mx7ulp EVK board"
+ select MX7ULP
select SYS_ARCH_TIMER
endchoice
diff --git a/arch/arm/mach-imx/mx7ulp/clock.c b/arch/arm/mach-imx/mx7ulp/clock.c
index dc317fe810..d3365dd411 100644
--- a/arch/arm/mach-imx/mx7ulp/clock.c
+++ b/arch/arm/mach-imx/mx7ulp/clock.c
@@ -72,7 +72,7 @@ u32 get_lpuart_clk(void)
return pcc_clock_get_rate(lpuart_pcc_clks[index - 4]);
}
-#ifdef CONFIG_SYS_LPI2C_IMX
+#ifdef CONFIG_SYS_I2C_IMX_LPI2C
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
{
/* Set parent to FIRC DIV2 clock */
@@ -300,9 +300,11 @@ void clock_init(void)
scg_a7_soscdiv_init();
- /* APLL PFD1 = 270Mhz, PFD2=480Mhz, PFD3=800Mhz */
+ scg_a7_init_core_clk();
+
+ /* APLL PFD1 = 270Mhz, PFD2=345.6Mhz, PFD3=800Mhz */
scg_enable_pll_pfd(SCG_APLL_PFD1_CLK, 35);
- scg_enable_pll_pfd(SCG_APLL_PFD2_CLK, 20);
+ scg_enable_pll_pfd(SCG_APLL_PFD2_CLK, 28);
scg_enable_pll_pfd(SCG_APLL_PFD3_CLK, 12);
init_clk_lpuart();
@@ -312,7 +314,7 @@ void clock_init(void)
enable_usboh3_clk(1);
}
-#ifdef CONFIG_SECURE_BOOT
+#ifdef CONFIG_IMX_HAB
void hab_caam_clock_enable(unsigned char enable)
{
if (enable)
diff --git a/arch/arm/mach-imx/mx7ulp/scg.c b/arch/arm/mach-imx/mx7ulp/scg.c
index b4f2ea875a..819c90af6c 100644
--- a/arch/arm/mach-imx/mx7ulp/scg.c
+++ b/arch/arm/mach-imx/mx7ulp/scg.c
@@ -352,7 +352,7 @@ static u32 scg_ddr_get_rate(void)
static u32 scg_nic_get_rate(enum scg_clk clk)
{
- u32 reg, val, rate;
+ u32 reg, val, rate, nic0_rate;
u32 shift, mask;
reg = readl(&scg1_regs->niccsr);
@@ -370,6 +370,7 @@ static u32 scg_nic_get_rate(enum scg_clk clk)
val = (reg & SCG_NICCSR_NIC0DIV_MASK) >> SCG_NICCSR_NIC0DIV_SHIFT;
rate = rate / (val + 1);
+ nic0_rate = rate;
clk_debug("scg_nic_get_rate NIC0 rate %u\n", rate);
@@ -411,6 +412,13 @@ static u32 scg_nic_get_rate(enum scg_clk clk)
return 0;
}
+ /*
+ * On RevB, the nic_bus and nic_ext dividers are parallel
+ * not chained with nic div
+ */
+ if (soc_rev() >= CHIP_REV_2_0)
+ rate = nic0_rate;
+
val = (reg & mask) >> shift;
rate = rate / (val + 1);
@@ -440,7 +448,7 @@ static u32 scg_sys_get_rate(enum scg_clk clk)
case SCG_SCS_SLOW_IRC:
case SCG_SCS_FAST_IRC:
case SCG_SCS_RTC_OSC:
- rate = scg_src_get_rate(scg_scs_array[val]);
+ rate = scg_src_get_rate(scg_scs_array[val - 1]);
break;
case 5:
rate = scg_apll_get_rate();
@@ -503,7 +511,10 @@ u32 decode_pll(enum pll_clocks pll)
infreq = infreq / pre_div;
- return infreq * mult + infreq * num / denom;
+ if (denom)
+ return infreq * mult + infreq * num / denom;
+ else
+ return infreq * mult;
case PLL_A7_APLL:
reg = readl(&scg1_regs->apllcsr);
@@ -532,7 +543,10 @@ u32 decode_pll(enum pll_clocks pll)
infreq = infreq / pre_div;
- return infreq * mult + infreq * num / denom;
+ if (denom)
+ return infreq * mult + infreq * num / denom;
+ else
+ return infreq * mult;
case PLL_USB:
reg = readl(&scg1_regs->upllcsr);
@@ -1085,3 +1099,44 @@ void scg_a7_info(void)
debug("SCG RCCR Value: 0x%x\n", readl(&scg1_regs->rccr));
debug("SCG Clock Status: 0x%x\n", readl(&scg1_regs->csr));
}
+
+void scg_a7_init_core_clk(void)
+{
+ u32 val = 0;
+
+ /*
+ * The normal target frequency for ULP B0 is 500Mhz,
+ * but ROM set it to 413Mhz, need to change SPLL PFD0 FRAC
+ */
+ if (soc_rev() >= CHIP_REV_2_0) {
+ /* Switch RCCR SCG to SOSC, firstly check the SOSC is valid */
+ if ((readl(&scg1_regs->sosccsr) & SCG_SOSC_CSR_SOSCVLD_MASK)) {
+ val = readl(&scg1_regs->rccr);
+ val &= (~SCG_CCR_SCS_MASK);
+ val |= ((SCG_SCS_SYS_OSC) << SCG_CCR_SCS_SHIFT);
+ writel(val, &scg1_regs->rccr);
+
+ /* Switch the PLLS to SPLL clk */
+ val = readl(&scg1_regs->spllcfg);
+ val &= ~SCG_PLL_CFG_PLLSEL_MASK;
+ writel(val, &scg1_regs->spllcfg);
+
+ /*
+ * Re-configure PFD0 to 19,
+ * A7 SPLL(528MHz) * 18 / 19 = 500MHz
+ */
+ scg_enable_pll_pfd(SCG_SPLL_PFD0_CLK, 19);
+
+ /* Switch the PLLS to SPLL PFD0 */
+ val = readl(&scg1_regs->spllcfg);
+ val |= SCG_PLL_CFG_PLLSEL_MASK;
+ writel(val, &scg1_regs->spllcfg);
+
+ /* Set RCCR SCG to SPLL clk out */
+ val = readl(&scg1_regs->rccr);
+ val &= (~SCG_CCR_SCS_MASK);
+ val |= ((SCG_SCS_SYS_PLL) << SCG_CCR_SCS_SHIFT);
+ writel(val, &scg1_regs->rccr);
+ }
+ }
+}
diff --git a/arch/arm/mach-imx/mx7ulp/soc.c b/arch/arm/mach-imx/mx7ulp/soc.c
index c72f0ed3fc..127fcfeea1 100644
--- a/arch/arm/mach-imx/mx7ulp/soc.c
+++ b/arch/arm/mach-imx/mx7ulp/soc.c
@@ -6,21 +6,25 @@
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
+#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/hab.h>
static char *get_reset_cause(char *);
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
.bank = 29,
.word = 6,
};
#endif
+#define ROM_VERSION_ADDR 0x80
u32 get_cpu_rev(void)
{
- /* Temporally hard code the CPU rev to 0x73, rev 1.0. Fix it later */
- return (MXC_CPU_MX7ULP << 12) | (1 << 4);
+ /* Check the ROM version for cpu revision */
+ u32 rom_version = readl((void __iomem *)ROM_VERSION_ADDR);
+
+ return (MXC_CPU_MX7ULP << 12) | (rom_version & 0xFF);
}
#ifdef CONFIG_REVISION_TAG
@@ -105,6 +109,10 @@ void s_init(void)
/* clock configuration. */
clock_init();
+ if (soc_rev() < CHIP_REV_2_0) {
+ /* enable dumb pmic */
+ writel((readl(SNVS_LP_LPCR) | SNVS_LPCR_DPEN), SNVS_LP_LPCR);
+ }
return;
}
@@ -244,3 +252,29 @@ int mmc_get_env_dev(void)
return board_mmc_get_env_dev(devno);
}
#endif
+
+enum boot_device get_boot_device(void)
+{
+ struct bootrom_sw_info **p =
+ (struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
+
+ enum boot_device boot_dev = SD1_BOOT;
+ u8 boot_type = (*p)->boot_dev_type;
+ u8 boot_instance = (*p)->boot_dev_instance;
+
+ switch (boot_type) {
+ case BOOT_TYPE_SD:
+ boot_dev = boot_instance + SD1_BOOT;
+ break;
+ case BOOT_TYPE_MMC:
+ boot_dev = boot_instance + MMC1_BOOT;
+ break;
+ case BOOT_TYPE_USB:
+ boot_dev = USB_BOOT;
+ break;
+ default:
+ break;
+ }
+
+ return boot_dev;
+}
diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c
index 1f230aca33..f025c4b301 100644
--- a/arch/arm/mach-imx/spl.c
+++ b/arch/arm/mach-imx/spl.c
@@ -18,13 +18,17 @@
DECLARE_GLOBAL_DATA_PTR;
+__weak int spl_board_boot_device(enum boot_device boot_dev_spl)
+{
+ return 0;
+}
+
#if defined(CONFIG_MX6)
/* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 register */
u32 spl_boot_device(void)
{
unsigned int bmode = readl(&src_base->sbmr2);
u32 reg = imx6_src_get_boot_mode();
- u32 mmc_index = ((reg >> 11) & 0x03);
/*
* Check for BMODE if serial downloader is enabled
@@ -85,15 +89,19 @@ u32 spl_boot_device(void)
/* SD/eSD: 8.5.3, Table 8-15 */
case IMX6_BMODE_SD:
case IMX6_BMODE_ESD:
+ return BOOT_DEVICE_MMC1;
+ /* MMC/eMMC: 8.5.3 */
case IMX6_BMODE_MMC:
case IMX6_BMODE_EMMC:
- if (mmc_index == 1)
- return BOOT_DEVICE_MMC2;
- else
- return BOOT_DEVICE_MMC1;
+ return BOOT_DEVICE_MMC1;
/* NAND Flash: 8.5.2, Table 8-10 */
case IMX6_BMODE_NAND_MIN ... IMX6_BMODE_NAND_MAX:
return BOOT_DEVICE_NAND;
+#if defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL)
+ /* QSPI boot */
+ case IMX6_BMODE_QSPI:
+ return BOOT_DEVICE_SPI;
+#endif
}
return BOOT_DEVICE_NONE;
}
@@ -127,6 +135,9 @@ u32 spl_boot_device(void)
enum boot_device boot_device_spl = get_boot_device();
+ if (IS_ENABLED(CONFIG_IMX8MM))
+ return spl_board_boot_device(boot_device_spl);
+
switch (boot_device_spl) {
#if defined(CONFIG_MX7)
case SD1_BOOT:
@@ -178,7 +189,18 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
/* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */
u32 spl_boot_mode(const u32 boot_device)
{
+/*
+ * When CONFIG_SPL_FORCE_MMC_BOOT is defined the 'boot_device' is used
+ * unconditionally to decide about device to use for booting.
+ * This is crucial for falcon boot mode, when board boots up (i.e. ROM
+ * loads SPL) from slow SPI-NOR memory and afterwards the SPL's 'falcon' boot
+ * mode is used to load Linux OS from eMMC partition.
+ */
+#ifdef CONFIG_SPL_FORCE_MMC_BOOT
+ switch (boot_device) {
+#else
switch (spl_boot_device()) {
+#endif
/* for MMC return either RAW or FAT mode */
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
@@ -198,7 +220,7 @@ u32 spl_boot_mode(const u32 boot_device)
}
#endif
-#if defined(CONFIG_SECURE_BOOT)
+#if defined(CONFIG_IMX_HAB)
/*
* +------------+ 0x0 (DDR_UIMAGE_START) -
@@ -261,6 +283,7 @@ __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
}
}
+#if !defined(CONFIG_SPL_FIT_SIGNATURE)
ulong board_spl_fit_size_align(ulong size)
{
/*
@@ -285,6 +308,7 @@ void board_spl_fit_post_load(ulong load_addr, size_t length)
hang();
}
}
+#endif
#endif
diff --git a/arch/arm/mach-imx/spl_qspi.cfg b/arch/arm/mach-imx/spl_qspi.cfg
new file mode 100644
index 0000000000..88956e626f
--- /dev/null
+++ b/arch/arm/mach-imx/spl_qspi.cfg
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2014, Compulab Ltd - http://compulab.co.il/
+ */
+
+#define __ASSEMBLY__
+#include <config.h>
+
+IMAGE_VERSION 2
+BOOT_FROM qspi
+
+/*
+ * Secure boot support
+ */
+#ifdef CONFIG_SECURE_BOOT
+CSF CONFIG_CSF_SIZE
+#endif
diff --git a/arch/arm/mach-imx/spl_sd.cfg b/arch/arm/mach-imx/spl_sd.cfg
index e791debf10..dbaee81535 100644
--- a/arch/arm/mach-imx/spl_sd.cfg
+++ b/arch/arm/mach-imx/spl_sd.cfg
@@ -12,6 +12,6 @@ BOOT_FROM sd
/*
* Secure boot support
*/
-#ifdef CONFIG_SECURE_BOOT
+#ifdef CONFIG_IMX_HAB
CSF CONFIG_CSF_SIZE
#endif