summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/arch-imx8ulp/mu_hal.h12
-rw-r--r--arch/arm/mach-imx/imx8ulp/lowlevel_init.S10
-rw-r--r--arch/arm/mach-imx/imx8ulp/soc.c84
-rw-r--r--drivers/misc/imx8ulp/imx8ulp_mu.c36
4 files changed, 118 insertions, 24 deletions
diff --git a/arch/arm/include/asm/arch-imx8ulp/mu_hal.h b/arch/arm/include/asm/arch-imx8ulp/mu_hal.h
new file mode 100644
index 0000000000..10d966d5d4
--- /dev/null
+++ b/arch/arm/include/asm/arch-imx8ulp/mu_hal.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef __IMX8ULP_MU_HAL_H__
+#define __IMX8ULP_MU_HAL_H__
+
+void mu_hal_init(ulong base);
+int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg);
+int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg);
+#endif
diff --git a/arch/arm/mach-imx/imx8ulp/lowlevel_init.S b/arch/arm/mach-imx/imx8ulp/lowlevel_init.S
index 7d81a75639..791c26407c 100644
--- a/arch/arm/mach-imx/imx8ulp/lowlevel_init.S
+++ b/arch/arm/mach-imx/imx8ulp/lowlevel_init.S
@@ -16,17 +16,11 @@ rom_pointer:
.global save_boot_params
save_boot_params:
+#ifndef CONFIG_SPL_BUILD
/* The firmware provided ATAG/FDT address can be found in r2/x0 */
adr x0, rom_pointer
stp x1, x2, [x0], #16
stp x3, x4, [x0], #16
-
+#endif
/* Returns */
b save_boot_params_ret
-
-.global restore_boot_params
-restore_boot_params:
- adr x0, rom_pointer
- ldp x1, x2, [x0], #16
- ldp x3, x4, [x0], #16
- ret
diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c
index 5e7bf57a62..62c02a6223 100644
--- a/arch/arm/mach-imx/imx8ulp/soc.c
+++ b/arch/arm/mach-imx/imx8ulp/soc.c
@@ -11,6 +11,10 @@
#include <asm/mach-imx/boot_mode.h>
#include <efi_loader.h>
#include <spl.h>
+#include <asm/arch/s400_api.h>
+#include <asm/arch/mu_hal.h>
+#include <cpu_func.h>
+#include <asm/setup.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -340,9 +344,89 @@ static void set_core0_reset_vector(u32 entry)
setbits_le32(SIM1_BASE_ADDR + 0x8, (0x1 << 26));
}
+static int release_xrdc(void)
+{
+ ulong s_mu_base = 0x27020000UL;
+ struct imx8ulp_s400_msg msg;
+ int ret;
+
+ msg.version = AHAB_VERSION;
+ msg.tag = AHAB_CMD_TAG;
+ msg.size = 2;
+ msg.command = AHAB_RELEASE_RDC_REQ_CID;
+ msg.data[0] = (0x78 << 8) | 0x2; /* A35 XRDC */
+
+ mu_hal_init(s_mu_base);
+ mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
+ mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
+
+ ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
+ if (!ret) {
+ ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
+ if (!ret)
+ return ret;
+
+ if ((msg.data[0] & 0xff) == 0)
+ return 0;
+ else
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static void xrdc_mrc_region_set_access(int mrc_index, u32 addr, u32 access)
+{
+ ulong xrdc_base = 0x292f0000, off;
+ u32 mrgd[5];
+ u8 mrcfg, j, region_num;
+ u8 dsel;
+
+ mrcfg = readb(xrdc_base + 0x140 + mrc_index);
+ region_num = mrcfg & 0x1f;
+
+ for (j = 0; j < region_num; j++) {
+ off = 0x2000 + mrc_index * 0x200 + j * 0x20;
+
+ mrgd[0] = readl(xrdc_base + off);
+ mrgd[1] = readl(xrdc_base + off + 4);
+ mrgd[2] = readl(xrdc_base + off + 8);
+ mrgd[3] = readl(xrdc_base + off + 0xc);
+ mrgd[4] = readl(xrdc_base + off + 0x10);
+
+ debug("MRC [%u][%u]\n", mrc_index, j);
+ debug("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ mrgd[0], mrgd[1], mrgd[2], mrgd[3], mrgd[4]);
+
+ /* hit */
+ if (addr >= mrgd[0] && addr <= mrgd[1]) {
+ /* find domain 7 DSEL */
+ dsel = (mrgd[2] >> 21) & 0x7;
+ if (dsel == 1) {
+ mrgd[4] &= ~0xFFF;
+ mrgd[4] |= (access & 0xFFF);
+ } else if (dsel == 2) {
+ mrgd[4] &= ~0xFFF0000;
+ mrgd[4] |= ((access & 0xFFF) << 16);
+ }
+
+ /* not handle other cases, since S400 only set ACCESS1 and 2 */
+ writel(mrgd[4], xrdc_base + off + 0x10);
+ return;
+ }
+ }
+}
+
int arch_cpu_init(void)
{
if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+ /* Disable wdog */
+ init_wdog();
+
+ /* release xrdc, then allow A35 to write SRAM2 */
+ release_xrdc();
+ xrdc_mrc_region_set_access(2, CONFIG_SPL_TEXT_BASE, 0xE00);
+
clock_init();
} else {
/* reconfigure core0 reset vector to ROM */
diff --git a/drivers/misc/imx8ulp/imx8ulp_mu.c b/drivers/misc/imx8ulp/imx8ulp_mu.c
index f3ca5473e3..913ebe7ad3 100644
--- a/drivers/misc/imx8ulp/imx8ulp_mu.c
+++ b/drivers/misc/imx8ulp/imx8ulp_mu.c
@@ -42,24 +42,27 @@ struct imx8ulp_mu {
#define MU_TR_COUNT 4
#define MU_RR_COUNT 4
-static inline void mu_hal_init(struct mu_type *base)
+void mu_hal_init(ulong base)
{
- writel(0, &base->tcr);
- writel(0, &base->rcr);
+ struct mu_type *mu_base = (struct mu_type *)base;
+
+ writel(0, &mu_base->tcr);
+ writel(0, &mu_base->rcr);
}
-static int mu_hal_sendmsg(struct mu_type *base, u32 reg_index, u32 msg)
+int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg)
{
+ struct mu_type *mu_base = (struct mu_type *)base;
u32 mask = MU_SR_TE0_MASK << reg_index;
u32 val;
int ret;
assert(reg_index < MU_TR_COUNT);
- debug("sendmsg sr 0x%x\n", readl(&base->sr));
+ debug("sendmsg sr 0x%x\n", readl(&mu_base->sr));
/* Wait TX register to be empty. */
- ret = readl_poll_timeout(&base->tsr, val, val & mask, 10000);
+ ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
if (ret < 0) {
debug("%s timeout\n", __func__);
return -ETIMEDOUT;
@@ -67,29 +70,30 @@ static int mu_hal_sendmsg(struct mu_type *base, u32 reg_index, u32 msg)
debug("tr[%d] 0x%x\n", reg_index, msg);
- writel(msg, &base->tr[reg_index]);
+ writel(msg, &mu_base->tr[reg_index]);
return 0;
}
-static int mu_hal_receivemsg(struct mu_type *base, u32 reg_index, u32 *msg)
+int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg)
{
+ struct mu_type *mu_base = (struct mu_type *)base;
u32 mask = MU_SR_RF0_MASK << reg_index;
u32 val;
int ret;
assert(reg_index < MU_TR_COUNT);
- debug("receivemsg sr 0x%x\n", readl(&base->sr));
+ debug("receivemsg sr 0x%x\n", readl(&mu_base->sr));
/* Wait RX register to be full. */
- ret = readl_poll_timeout(&base->rsr, val, val & mask, 10000);
+ ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 10000);
if (ret < 0) {
debug("%s timeout\n", __func__);
return -ETIMEDOUT;
}
- *msg = readl(&base->rr[reg_index]);
+ *msg = readl(&mu_base->rr[reg_index]);
debug("rr[%d] 0x%x\n", reg_index, *msg);
@@ -106,7 +110,7 @@ static int imx8ulp_mu_read(struct mu_type *base, void *data)
return -EINVAL;
/* Read first word */
- ret = mu_hal_receivemsg(base, 0, (u32 *)msg);
+ ret = mu_hal_receivemsg((ulong)base, 0, (u32 *)msg);
if (ret)
return ret;
count++;
@@ -119,7 +123,7 @@ static int imx8ulp_mu_read(struct mu_type *base, void *data)
/* Read remaining words */
while (count < msg->size) {
- ret = mu_hal_receivemsg(base, count % MU_RR_COUNT,
+ ret = mu_hal_receivemsg((ulong)base, count % MU_RR_COUNT,
&msg->data[count - 1]);
if (ret)
return ret;
@@ -143,14 +147,14 @@ static int imx8ulp_mu_write(struct mu_type *base, void *data)
return -EINVAL;
/* Write first word */
- ret = mu_hal_sendmsg(base, 0, *((u32 *)msg));
+ ret = mu_hal_sendmsg((ulong)base, 0, *((u32 *)msg));
if (ret)
return ret;
count++;
/* Write remaining words */
while (count < msg->size) {
- ret = mu_hal_sendmsg(base, count % MU_TR_COUNT,
+ ret = mu_hal_sendmsg((ulong)base, count % MU_TR_COUNT,
msg->data[count - 1]);
if (ret)
return ret;
@@ -207,7 +211,7 @@ static int imx8ulp_mu_probe(struct udevice *dev)
debug("mu base 0x%lx\n", (ulong)priv->base);
/* U-Boot not enable interrupts, so need to enable RX interrupts */
- mu_hal_init(priv->base);
+ mu_hal_init((ulong)priv->base);
gd->arch.s400_dev = dev;