plat: imx: Add i.MX8MQ basic support
authorBai Ping <ping.bai@nxp.com>
Sat, 27 Oct 2018 16:12:34 +0000 (00:12 +0800)
committerBai Ping <ping.bai@nxp.com>
Wed, 5 Dec 2018 00:58:51 +0000 (08:58 +0800)
i.MX8MQ is new SOC of NXP's i.MX8M family based on
A53. It can provide industry-leading audio, voice
and video processing for applications that scale
from consumer home audio to industrial building
automation and mobile computers

this patchset add the basic supoort to boot up
the 4 X A53. more feature will be added later.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
docs/plat/imx8m.rst [new file with mode: 0644]
plat/imx/common/imx_uart_console.S [new file with mode: 0644]
plat/imx/common/include/imx_uart.h [new file with mode: 0644]
plat/imx/imx8m/imx8mq/gpc.c [new file with mode: 0644]
plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c [new file with mode: 0644]
plat/imx/imx8m/imx8mq/imx8mq_psci.c [new file with mode: 0644]
plat/imx/imx8m/imx8mq/include/platform_def.h [new file with mode: 0644]
plat/imx/imx8m/imx8mq/platform.mk [new file with mode: 0644]
plat/imx/imx8m/include/gpc.h [new file with mode: 0644]

diff --git a/docs/plat/imx8m.rst b/docs/plat/imx8m.rst
new file mode 100644 (file)
index 0000000..ab33a8a
--- /dev/null
@@ -0,0 +1,42 @@
+Description
+===========
+
+The i.MX 8M family of applications processors based on Arm Corte-A53 and Cortex-M4
+cores provide high-performance computing, power efficiency, enhanced system
+reliability and embedded security needed to drive the growth of fast-growing
+edge node computing, streaming multimedia, and machine learning applications.
+
+Boot Sequence
+=============
+
+Bootrom --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel
+
+How to build
+============
+
+Build Procedure
+---------------
+
+-  Prepare AARCH64 toolchain.
+
+-  Build spl and u-boot firstly, and get binary images: u-boot-spl.bin,
+   u-boot-nodtb.bin and dtb for the target board.
+
+-  Build TF-A
+
+   Build bl31:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
+
+   Target_SoC should be "imx8mq" for i.MX8MQ SoC.
+
+Deploy TF-A Images
+-----------------
+
+TF-A binary(bl31.bin), u-boot-spl.bin u-boot-nodtb.bin and dtb are combined
+together to generate a binary file called flash.bin, the imx-mkimage tool is
+used to generate flash.bin, and flash.bin needs to be flashed into SD card
+with certain offset for BOOT ROM. the u-boot and imx-mkimage will be upstreamed
+soon, this doc will be updated once they are ready, and the link will be posted.
diff --git a/plat/imx/common/imx_uart_console.S b/plat/imx/common/imx_uart_console.S
new file mode 100644 (file)
index 0000000..7dbde79
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#define USE_FINISH_CONSOLE_REG_2
+#include <console_macros.S>
+#include <assert_macros.S>
+#include "imx_uart.h"
+
+#define URXD  0x0  /* Receiver Register */
+#define UTXD  0x40 /* Transmitter Register */
+#define UTS   0xb4 /* UART Test Register (mx31) */
+#define  URXD_RX_DATA    (0xFF)
+
+       .globl  console_uart_register
+       .globl  console_uart_init
+       .globl  console_uart_putc
+       .globl  console_uart_getc
+
+func console_imx_uart_register
+       mov     x7, x30
+       mov     x6, x3
+       cbz     x6, register_fail
+       str     x0, [x6, #CONSOLE_T_DRVDATA]
+
+       bl      console_imx_uart_init
+       cbz     x0, register_fail
+
+       mov     x0, x6
+       mov     x30, x7
+       finish_console_register imx_uart putc=1, getc=1
+
+register_fail:
+       ret     x7
+endfunc console_imx_uart_register
+
+func console_imx_uart_init
+       mov     w0, #1
+       ret
+endfunc console_imx_uart_init
+
+func console_imx_uart_putc
+       ldr     x1, [x1, #CONSOLE_T_DRVDATA]
+       cbz     x1, putc_error
+
+       /* Prepare '\r' to '\n' */
+       cmp     w0, #0xA
+       b.ne    2f
+1:
+       /* Check if the transmit FIFO is full */
+       ldr     w2, [x1, #UTS]
+       tbz     w2, #6, 1b
+       mov     w2, #0xD
+       str     w2, [x1, #UTXD]
+2:
+       /* Check if the transmit FIFO is full */
+       ldr     w2, [x1, #UTS]
+       tbz     w2, #6, 2b
+       str     w0, [x1, #UTXD]
+       ret
+putc_error:
+       mov     w0, #-1
+       ret
+endfunc console_imx_uart_putc
+
+func console_imx_uart_getc
+       ldr     x0, [x0, #CONSOLE_T_DRVDATA]
+       cbz     x0, getc_error
+1:
+       ldr     w1, [x0, #UTS]
+       tbnz    w1, #5, 1b
+
+       ldr     w1, [x0, #URXD]
+       and     w0, w1, #URXD_RX_DATA
+
+       ret
+getc_error:
+       mov     w0, #-1
+       ret
+endfunc console_imx_uart_getc
diff --git a/plat/imx/common/include/imx_uart.h b/plat/imx/common/include/imx_uart.h
new file mode 100644 (file)
index 0000000..d2c3968
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_UART_H
+#define IMX_UART_H
+
+#include <console.h>
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+       console_t console;
+       uintptr_t base;
+} console_uart_t;
+
+int console_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+                          console_uart_t *console);
+#endif /*__ASSEMBLY__*/
+
+#endif  /* IMX_UART_H */
diff --git a/plat/imx/imx8m/imx8mq/gpc.c b/plat/imx/imx8m/imx8mq/gpc.c
new file mode 100644 (file)
index 0000000..187a4ad
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <gpc.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <std_svc.h>
+
+void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint)
+{
+       uint64_t temp_base;
+
+       temp_base = (uint64_t) sec_entrypoint;
+       temp_base >>= 2;
+
+       mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3),
+               ((uint32_t)(temp_base >> 22) & 0xffff));
+       mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4,
+               ((uint32_t)temp_base & 0x003fffff));
+}
+
+/* use wfi power down the core */
+void imx_set_cpu_pwr_off(unsigned int core_id)
+{
+       /* enable the wfi power down of the core */
+       mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+                       (1 << (core_id + 20)));
+       /* assert the pcg pcr bit of the core */
+       mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+};
+
+/* use the sw method to power up the core */
+void imx_set_cpu_pwr_on(unsigned int core_id)
+{
+       /* clear the wfi power down bit of the core */
+       mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
+       /* assert the ncpuporeset */
+       mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
+       /* assert the pcg pcr bit of the core */
+       mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+       /* sw power up the core */
+       mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id));
+
+       /* wait for the power up finished */
+       while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0)
+               ;
+
+       /* deassert the pcg pcr bit of the core */
+       mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+       /* deassert the ncpuporeset */
+       mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
+}
+
+/* if out of lpm, we need to do reverse steps */
+void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
+{
+       if (pdn) {
+               /* enable the core WFI PDN & IRQ PUP */
+               mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+                               (1 << (core_id + 20)) | COREx_IRQ_WUP(core_id));
+               /* assert the pcg pcr bit of the core */
+               mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+       } else {
+               /* disable CORE WFI PDN & IRQ PUP */
+               mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+                               COREx_IRQ_WUP(core_id));
+               /* deassert the pcg pcr bit of the core */
+               mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+       }
+}
+
+void imx_set_sys_wakeup(unsigned int last_core, bool pdn)
+{
+       /* TODO */
+}
+
+void imx_pup_pdn_slot_config(int last_core, bool pdn)
+{
+       if (pdn) {
+               /* SLOT0 for A53 PLAT power down */
+               mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN);
+               /* SLOT1 for A53 PLAT power up */
+               mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP);
+               /* SLOT2 for A53 primary core power up */
+               mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core));
+               /* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */
+               mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
+                       A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK);
+       } else {
+               mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF);
+               mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF);
+               mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF);
+               mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
+                       A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK);
+       }
+}
+
+void imx_set_cluster_standby(bool retention)
+{
+       /*
+        * Enable BIT 6 of A53 AD register to make sure system
+        * don't enter LPM mode.
+        */
+       if (retention)
+               mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
+       else
+               mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
+}
+
+void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
+{
+       uint32_t val;
+
+       if (is_local_state_off(power_state)) {
+               val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+               val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */
+               val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */
+               mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+               /* enable C2-3's STOP mode */
+               mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP);
+
+               /* enable PLAT/SCU power down */
+               val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+               val &= ~EN_L2_WFI_PDN;
+               val |= L2PGE | EN_PLAT_PDN;
+               val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */
+               val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */
+               mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+               imx_pup_pdn_slot_config(last_core, true);
+
+               /* enable PLAT PGC */
+               mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
+       } else {
+               /* clear PLAT PGC */
+               mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
+
+               /* clear the slot and ack for cluster power down */
+               imx_pup_pdn_slot_config(last_core, false);
+
+               val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+               val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */
+               val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */
+               mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+               /* set A53 LPM to RUN mode */
+               mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK);
+
+               /* clear PLAT/SCU power down */
+               val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+               val |= EN_L2_WFI_PDN;
+               val &= ~(L2PGE | EN_PLAT_PDN);
+               val &= ~COREx_LPM_PUP(last_core);  /* disable C0's LPM PUP */
+               mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+       }
+}
+
+/* config the system level power mode */
+void imx_set_sys_lpm(bool retention)
+{
+       uint32_t val;
+
+       /* set system DSM mode SLPCR(0x14) */
+       val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+       val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+                SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
+
+       if (retention)
+               val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+                        SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN |
+                        SLPCR_A53_FASTWUP_STOP_MODE);
+
+       mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+}
+
+void imx_set_rbc_count(void)
+{
+       mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
+}
+
+void imx_clear_rbc_count(void)
+{
+       mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
+}
+
+void imx_gpc_init(void)
+{
+       uint32_t val;
+       int i;
+       /* mask all the interrupt by default */
+       /* Due to the hardware design requirement, need to make
+        * sure GPR interrupt(#32) is unmasked during RUN mode to
+        * avoid entering DSM mode by mistake.
+        */
+       for (i = 0; i < 4; i++) {
+               mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE);
+               mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE);
+               mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE);
+               mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE);
+               mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
+       }
+
+       /* use external IRQs to wakeup C0~C3 from LPM */
+       val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+       val |= IRQ_SRC_A53_WUP;
+       /* clear the MASTER0 LPM handshake */
+       val &= ~MASTER0_LPM_HSK;
+       mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+       /* mask M4 DSM trigger if M4 is NOT enabled */
+       mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK);
+
+       /* set all mix/PU in A53 domain */
+       mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd);
+
+       /* set SCU timming */
+       mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
+                     (0x59 << 10) | 0x5B | (0x2 << 20));
+
+       /* set DUMMY PDN/PUP ACK by default for A53 domain */
+       mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
+               A53_DUMMY_PDN_ACK);
+
+       /* disable DSM mode by default */
+       mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK);
+
+       /*
+        * USB PHY power up needs to make sure RESET bit in SRC is clear,
+        * otherwise, the PU power up bit in GPC will NOT self-cleared.
+        * only need to do it once.
+        */
+       mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
+       mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
+}
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
new file mode 100644 (file)
index 0000000..45d2a40
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <gpc.h>
+#include <imx_uart.h>
+#include <stdbool.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <plat_imx8.h>
+#include <xlat_tables.h>
+#include <tzc380.h>
+
+IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START);
+IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END);
+IMPORT_SYM(uintptr_t, __RO_START__, BL31_RO_START);
+IMPORT_SYM(uintptr_t, __RO_END__, BL31_RO_END);
+IMPORT_SYM(uintptr_t, __RW_START__, BL31_RW_START);
+IMPORT_SYM(uintptr_t, __RW_END__, BL31_RW_END);
+
+static const mmap_region_t imx_mmap[] = {
+       MAP_REGION_FLAT(GPV_BASE, GPV_SIZE, MT_DEVICE | MT_RW), /* GPV map */
+       MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */
+       MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */
+       {0},
+};
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* get SPSR for BL33 entry */
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+       unsigned long el_status;
+       unsigned long mode;
+       uint32_t spsr;
+
+       /* figure out what mode we enter the non-secure world */
+       el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+       el_status &= ID_AA64PFR0_ELX_MASK;
+
+       mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+       spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+       return spsr;
+}
+
+static void bl31_tz380_setup(void)
+{
+       unsigned int val;
+
+       val = mmio_read_32(IMX_IOMUX_GPR_BASE + IOMUXC_GPR10);
+       if ((val & GPR_TZASC_EN) != GPR_TZASC_EN)
+               return;
+
+       tzc380_init(IMX_TZASC_BASE);
+       /*
+        * Need to substact offset 0x40000000 from CPU address when
+        * programming tzasc region for i.mx8mq. Enable 1G-5G S/NS RW
+        */
+       tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) |
+                               TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+                       u_register_t arg2, u_register_t arg3)
+{
+       int i;
+       /* enable CSU NS access permission */
+       for (i = 0; i < 64; i++) {
+               mmio_write_32(IMX_CSU_BASE + i * 4, 0xffffffff);
+       }
+
+#if DEBUG_CONSOLE
+       static console_uart_t console;
+
+       console_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+               IMX_CONSOLE_BAUDRATE, &console);
+#endif
+       /*
+        * tell BL3-1 where the non-secure software image is located
+        * and the entry state information.
+        */
+       bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+       bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+       SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+       bl31_tz380_setup();
+}
+
+void bl31_plat_arch_setup(void)
+{
+       mmap_add_region(BL31_RO_START, BL31_RO_START, (BL31_RO_END - BL31_RO_START),
+               MT_MEMORY | MT_RO | MT_SECURE);
+       mmap_add_region(BL31_RW_START, BL31_RW_START, (BL31_RW_END - BL31_RW_START),
+               MT_MEMORY | MT_RW | MT_SECURE);
+
+       mmap_add(imx_mmap);
+
+#if USE_COHERENT_MEM
+       mmap_add_region(BL31_COHERENT_RAM_START, BL31_COHERENT_RAM_START,
+               BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START,
+               MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+       /* setup xlat table */
+       init_xlat_tables();
+       /* enable the MMU */
+       enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+       /* init the GICv3 cpu and distributor interface */
+       plat_gic_driver_init();
+       plat_gic_init();
+
+       /* gpc init */
+       imx_gpc_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+       if (type == NON_SECURE)
+               return &bl33_image_ep_info;
+       if (type == SECURE)
+               return &bl32_image_ep_info;
+
+       return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+       return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+       return;
+}
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
new file mode 100644 (file)
index 0000000..7afe52d
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <gpc.h>
+#include <stdbool.h>
+#include <plat_imx8.h>
+#include <psci.h>
+#include <mmio.h>
+
+#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+       unsigned int core_id;
+       uint64_t base_addr = BL31_BASE;
+
+       core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       /* set the secure entrypoint */
+       imx_set_cpu_secure_entry(core_id, base_addr);
+       /* power up the core */
+       imx_set_cpu_pwr_on(core_id);
+
+       return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+       /* program the GIC per cpu dist and rdist interface */
+       plat_gic_pcpu_init();
+       /* enable the GICv3 cpu interface */
+       plat_gic_cpuif_enable();
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+       uint64_t mpidr = read_mpidr_el1();
+       unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       /* disable the GIC cpu interface first */
+       plat_gic_cpuif_disable();
+       /* config the core for power down */
+       imx_set_cpu_pwr_off(core_id);
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+       /* The non-secure entrypoint should be in RAM space */
+       if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
+               return PSCI_E_INVALID_PARAMS;
+
+       return PSCI_E_SUCCESS;
+}
+
+int imx_validate_power_state(unsigned int power_state,
+                        psci_power_state_t *req_state)
+{
+       int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+       int pwr_type = psci_get_pstate_type(power_state);
+       int state_id = psci_get_pstate_id(power_state);
+
+       if (pwr_lvl > PLAT_MAX_PWR_LVL)
+               return PSCI_E_INVALID_PARAMS;
+
+       if (pwr_type == PSTATE_TYPE_STANDBY) {
+               CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+               CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+       }
+
+       if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
+               CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
+               CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+       }
+
+       return PSCI_E_SUCCESS;
+}
+
+void imx_cpu_standby(plat_local_state_t cpu_state)
+{
+       dsb();
+       write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+       isb();
+
+       wfi();
+
+       write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+       isb();
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+       uint64_t base_addr = BL31_BASE;
+       uint64_t mpidr = read_mpidr_el1();
+       unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+               /* disable the cpu interface */
+               plat_gic_cpuif_disable();
+               imx_set_cpu_secure_entry(core_id, base_addr);
+               imx_set_cpu_lpm(core_id, true);
+       } else {
+               dsb();
+               write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+               isb();
+       }
+
+       if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
+               imx_set_cluster_powerdown(core_id, true);
+       else
+               imx_set_cluster_standby(true);
+
+       if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+               imx_set_sys_lpm(true);
+       }
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+       uint64_t mpidr = read_mpidr_el1();
+       unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       /* check the system level status */
+       if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+               imx_set_sys_lpm(false);
+               imx_clear_rbc_count();
+       }
+
+       /* check the cluster level power status */
+       if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
+               imx_set_cluster_powerdown(core_id, false);
+       else
+               imx_set_cluster_standby(false);
+
+       /* check the core level power status */
+       if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+               /* clear the core lpm setting */
+               imx_set_cpu_lpm(core_id, false);
+               /* enable the gic cpu interface */
+               plat_gic_cpuif_enable();
+       } else {
+               write_scr_el3(read_scr_el3() & (~0x4));
+               isb();
+       }
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+       unsigned int i;
+
+       for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
+               req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
+
+       req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
+}
+
+void __dead2 imx_system_reset(void)
+{
+       uintptr_t wdog_base = IMX_WDOG_BASE;
+       unsigned int val;
+
+       /* WDOG_B reset */
+       val = mmio_read_16(wdog_base);
+#ifdef IMX_WDOG_B_RESET
+       val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE |
+               WDOG_WCR_WDT | WDOG_WCR_SRS;
+#else
+       val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS;
+#endif
+       mmio_write_16(wdog_base, val);
+
+       mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
+       mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
+       while (1)
+               ;
+}
+
+
+
+void __dead2 imx_system_off(void)
+{
+       mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
+                       SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
+
+       while (1)
+               ;
+}
+
+void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+       if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
+               imx_set_rbc_count();
+
+       while (1)
+               wfi();
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+       .pwr_domain_on = imx_pwr_domain_on,
+       .pwr_domain_on_finish = imx_pwr_domain_on_finish,
+       .pwr_domain_off = imx_pwr_domain_off,
+       .validate_ns_entrypoint = imx_validate_ns_entrypoint,
+       .validate_power_state = imx_validate_power_state,
+       .cpu_standby = imx_cpu_standby,
+       .pwr_domain_suspend = imx_domain_suspend,
+       .pwr_domain_suspend_finish = imx_domain_suspend_finish,
+       .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+       .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+       .system_reset = imx_system_reset,
+       .system_off = imx_system_off,
+};
+
+/* export the platform specific psci ops */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+                       const plat_psci_ops_t **psci_ops)
+{
+       imx_mailbox_init(sec_entrypoint);
+       /* sec_entrypoint is used for warm reset */
+       *psci_ops = &imx_plat_psci_ops;
+
+       return 0;
+}
diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h
new file mode 100644 (file)
index 0000000..4957582
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define PLATFORM_LINKER_FORMAT         "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH           aarch64
+
+#define PLATFORM_STACK_SIZE            0x800
+#define CACHE_WRITEBACK_GRANULE                64
+
+#define PLAT_PRIMARY_CPU               0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER   4
+#define PLATFORM_CLUSTER_COUNT         1
+#define PLATFORM_CLUSTER0_CORE_COUNT   4
+#define PLATFORM_CLUSTER1_CORE_COUNT   0
+#define PLATFORM_CORE_COUNT            (PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define IMX_PWR_LVL0                   MPIDR_AFFLVL0
+#define IMX_PWR_LVL1                   MPIDR_AFFLVL1
+#define IMX_PWR_LVL2                   MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL          U(1)
+#define PLAT_MAX_PWR_LVL               U(2)
+#define PLAT_MAX_OFF_STATE             U(4)
+#define PLAT_MAX_RET_STATE             U(1)
+
+#define PLAT_WAIT_OFF_STATE            U(2)
+#define PLAT_STOP_OFF_STATE            U(3)
+
+#define BL31_BASE                      U(0x910000)
+#define BL31_LIMIT                     U(0x920000)
+#define BL32_BASE                      U(0xfe000000)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET           U(0x40200000)
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE                 U(0x38800000)
+#define PLAT_GICR_BASE                 U(0x38880000)
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE      (1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE       (1ull << 32)
+
+#define MAX_XLAT_TABLES                        4
+#define MAX_MMAP_REGIONS               14
+
+#define HAB_RVT_BASE                   U(0x00000880) /* HAB_RVT for i.MX8MQ */
+
+#define IMX_BOOT_UART_BASE             U(0x30860000)
+#define IMX_BOOT_UART_CLK_IN_HZ                25000000 /* Select 25Mhz oscillator */
+#define PLAT_CRASH_UART_BASE           IMX_BOOT_UART_BASE
+#define PLAT_CRASH_UART_CLK_IN_HZ      25000000
+#define IMX_CONSOLE_BAUDRATE           115200
+
+#define IMX_AIPS_BASE                  U(0x30200000)
+#define IMX_AIPS_SIZE                  U(0xC00000)
+#define IMX_AIPS1_BASE                 U(0x30200000)
+#define IMX_AIPS3_ARB_BASE             U(0x30800000)
+#define IMX_ANAMIX_BASE                        U(0x30360000)
+#define IMX_CCM_BASE                   U(0x30380000)
+#define IMX_SRC_BASE                   U(0x30390000)
+#define IMX_GPC_BASE                   U(0x303a0000)
+#define IMX_RDC_BASE                   U(0x303d0000)
+#define IMX_CSU_BASE                   U(0x303e0000)
+#define IMX_WDOG_BASE                  U(0x30280000)
+#define IMX_SNVS_BASE                  U(0x30370000)
+#define IMX_NOC_BASE                   U(0x32700000)
+#define IMX_TZASC_BASE                 U(0x32F80000)
+#define IMX_IOMUX_GPR_BASE             U(0x30340000)
+#define IMX_DDRC_BASE                  U(0x3d400000)
+#define IMX_DDRPHY_BASE                        U(0x3c000000)
+#define IMX_DDR_IPS_BASE               U(0x3d000000)
+#define IMX_ROM_BASE                   U(0x00000000)
+
+#define AIPSTZ1_BASE                   U(0x301f0000)
+#define AIPSTZ2_BASE                   U(0x305f0000)
+#define AIPSTZ3_BASE                   U(0x309f0000)
+#define AIPSTZ4_BASE                   U(0x32df0000)
+
+#define GPV_BASE                       U(0x32000000)
+#define GPV_SIZE                       U(0x800000)
+#define IMX_GIC_BASE                   PLAT_GICD_BASE
+#define IMX_GIC_SIZE                   U(0x200000)
+
+#define WDOG_WSR                       U(0x2)
+#define WDOG_WCR_WDZST                 BIT(0)
+#define WDOG_WCR_WDBG                  BIT(1)
+#define WDOG_WCR_WDE                   BIT(2)
+#define WDOG_WCR_WDT                   BIT(3)
+#define WDOG_WCR_SRS                   BIT(4)
+#define WDOG_WCR_WDA                   BIT(5)
+#define WDOG_WCR_SRE                   BIT(6)
+#define WDOG_WCR_WDW                   BIT(7)
+
+#define SRC_A53RCR0                    U(0x4)
+#define SRC_A53RCR1                    U(0x8)
+#define SRC_OTG1PHY_SCR                        U(0x20)
+#define SRC_OTG2PHY_SCR                        U(0x24)
+#define SRC_GPR1_OFFSET                        U(0x74)
+
+#define SNVS_LPCR                      U(0x38)
+#define SNVS_LPCR_SRTC_ENV             BIT(0)
+#define SNVS_LPCR_DP_EN                        BIT(5)
+#define SNVS_LPCR_TOP                  BIT(6)
+
+
+#define IOMUXC_GPR10                   U(0x28)
+#define GPR_TZASC_EN                   BIT(0)
+#define GPR_TZASC_EN_LOCK              BIT(16)
+
+#define OCRAM_S_BASE                   U(0x00180000)
+#define OCRAM_S_SIZE                   U(0x8000)
+#define OCRAM_S_LIMIT                  (OCRAM_S_BASE + OCRAM_S_SIZE)
+
+#define COUNTER_FREQUENCY              8000000 /* 8MHz */
+
+#define DEBUG_CONSOLE                  0
+#define IMX_WDOG_B_RESET
+#define PLAT_IMX8M                     1
diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk
new file mode 100644 (file)
index 0000000..0255268
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES          :=      -Iplat/imx/common/include               \
+                               -Iplat/imx/imx8m/include                \
+                               -Iplat/imx/imx8m/imx8mq/include
+
+IMX_GIC_SOURCES                :=      drivers/arm/gic/v3/gicv3_helpers.c      \
+                               drivers/arm/gic/v3/arm_gicv3_common.c   \
+                               drivers/arm/gic/v3/gic500.c             \
+                               drivers/arm/gic/v3/gicv3_main.c         \
+                               drivers/arm/gic/common/gic_common.c     \
+                               plat/common/plat_gicv3.c                \
+                               plat/common/plat_psci_common.c          \
+                               plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES           +=      plat/imx/common/imx8_helpers.S                  \
+                               plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c       \
+                               plat/imx/imx8m/imx8mq/imx8mq_psci.c             \
+                               plat/imx/imx8m/imx8mq/gpc.c                     \
+                               plat/imx/common/imx8_topology.c                 \
+                               plat/imx/common/imx_uart_console.S              \
+                               lib/xlat_tables/aarch64/xlat_tables.c           \
+                               lib/xlat_tables/xlat_tables_common.c            \
+                               lib/cpus/aarch64/cortex_a53.S                   \
+                               drivers/console/aarch64/console.S               \
+                               drivers/arm/tzc/tzc380.c                        \
+                               ${IMX_GIC_SOURCES}
+
+USE_COHERENT_MEM       :=      1
+RESET_TO_BL31          :=      1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+MULTI_CONSOLE_API      :=      1
diff --git a/plat/imx/imx8m/include/gpc.h b/plat/imx/imx8m/include/gpc.h
new file mode 100644 (file)
index 0000000..6fdf6ad
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_GPC_H
+#define IMX8M_GPC_H
+
+#define LPCR_A53_BSC                   0x0
+#define LPCR_A53_BSC2                  0x108
+#define LPCR_A53_AD                    0x4
+#define LPCR_M4                                0x8
+#define SLPCR                          0x14
+#define MST_CPU_MAPPING                        0x18
+#define MLPCR                          0x20
+#define PGC_ACK_SEL_A53                        0x24
+#define IMR1_CORE0_A53                 0x30
+#define IMR1_CORE1_A53                 0x40
+#define IMR1_CORE2_A53                 0x1C0
+#define IMR1_CORE3_A53                 0x1D0
+#define IMR1_CORE0_M4                  0x50
+#define SLT0_CFG                       0xB0
+#define GPC_PU_PWRHSK                  0x1FC
+#define PGC_CPU_0_1_MAPPING            0xEC
+#define CPU_PGC_UP_TRG                 0xF0
+#define PU_PGC_UP_TRG                  0xF8
+#define CPU_PGC_DN_TRG                 0xFC
+#define PU_PGC_DN_TRG                  0x104
+#define A53_CORE0_PGC                  0x800
+#define A53_PLAT_PGC                   0x900
+#define PGC_SCU_TIMING                 0x910
+
+#define MASK_DSM_TRIGGER_A53           BIT(31)
+#define IRQ_SRC_A53_WUP                        BIT(30)
+#define IRQ_SRC_C1                     BIT(29)
+#define IRQ_SRC_C0                     BIT(28)
+#define IRQ_SRC_C3                     BIT(23)
+#define IRQ_SRC_C2                     BIT(22)
+#define CPU_CLOCK_ON_LPM               BIT(14)
+#define MASTER0_LPM_HSK                        BIT(6)
+
+#define L2PGE                          BIT(31)
+#define EN_L2_WFI_PDN                  BIT(5)
+#define EN_PLAT_PDN                    BIT(4)
+
+#define SLPCR_EN_DSM                   BIT(31)
+#define SLPCR_RBC_EN                   BIT(30)
+#define SLPCR_A53_FASTWUP_STOP_MODE    BIT(17)
+#define SLPCR_A53_FASTWUP_WAIT_MODE    BIT(16)
+#define SLPCR_VSTBY                    BIT(2)
+#define SLPCR_SBYOS                    BIT(1)
+#define SLPCR_BYPASS_PMIC_READY                BIT(0)
+#define SLPCR_RBC_COUNT_SHIFT          24
+
+#define A53_DUMMY_PDN_ACK              BIT(15)
+#define A53_DUMMY_PUP_ACK              BIT(31)
+#define A53_PLAT_PDN_ACK               BIT(2)
+#define A53_PLAT_PUP_ACK               BIT(18)
+
+#define SLT_PLAT_PDN                   BIT(8)
+#define SLT_PLAT_PUP                   BIT(9)
+
+/* helper macro */
+#define A53_LPM_MASK   U(0xF)
+#define A53_LPM_WAIT   U(0x5)
+#define A53_LPM_STOP   U(0xA)
+
+#define DSM_MODE_MASK  BIT(31)
+
+#define A53_CORE_WUP_SRC(core_id)      (1 << ((core_id) < 2 ? 28 + (core_id) : 22 + (core_id) - 2))
+#define COREx_PGC_PCR(core_id)         (0x800 + (core_id) * 0x40)
+#define COREx_WFI_PDN(core_id)         (1 << ((core_id) < 2 ? (core_id) * 2 : ((core_id) - 2) * 2 + 16))
+#define COREx_IRQ_WUP(core_id)         ((core_id) < 2 ? (1 << ((core_id) * 2 + 8)) : (1 << ((core_id) * 2 + 20)))
+#define COREx_LPM_PUP(core_id)         ((core_id) < 2 ? (1 << ((core_id) * 2 + 9)) : (1 << ((core_id) * 2 + 21)))
+#define SLTx_CFG(n)                    ((SLT0_CFG + ((n) * 4)))
+#define SLT_COREx_PUP(core_id)         (0x2 << ((core_id) * 2))
+
+/* function declare */
+void imx_gpc_init(void);
+void imx_set_cpu_secure_entry(unsigned int core_index, uintptr_t sec_entrypoint);
+void imx_set_cpu_pwr_off(unsigned int core_index);
+void imx_set_cpu_pwr_on(unsigned int core_index);
+void imx_set_cpu_lpm(unsigned int core_index, bool pdn);
+void imx_set_cluster_standby(bool retention);
+void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state);
+void imx_set_sys_lpm(bool retention);
+void imx_set_rbc_count(void);
+void imx_clear_rbc_count(void);
+
+#endif /*IMX8M_GPC_H */