summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBai Ping <ping.bai@nxp.com>2017-06-26 10:47:47 +0800
committerAnson Huang <Anson.Huang@nxp.com>2017-07-12 23:33:09 +0800
commitec605c1e2586c59501f85059febebdcc564306e2 (patch)
tree4381da7d5ffcefe054c058ba195fae2655cc34b4
parent6f14ea4b73e0f2289a3a747542cb2a5848407003 (diff)
i.mx8mq: Add basic support for i.mx8mq
Add basic support for i.MX8MQ. 1. SMP support is ok. 2. basic suspend/resume support is ok. Signed-off-by: Bai Ping <ping.bai@nxp.com>
-rw-r--r--lib/psci/psci_main.c4
-rw-r--r--plat/freescale/common/mxcuart_console.S270
-rw-r--r--plat/freescale/imx8mq/gpc.c456
-rw-r--r--plat/freescale/imx8mq/imx8m_bl31_setup.c203
-rw-r--r--plat/freescale/imx8mq/imx8m_psci.c215
-rw-r--r--plat/freescale/imx8mq/include/fsl_sip.h24
-rw-r--r--plat/freescale/imx8mq/include/platform_def.h52
-rw-r--r--plat/freescale/imx8mq/include/soc.h67
-rw-r--r--plat/freescale/imx8mq/platform.mk27
-rw-r--r--plat/freescale/imx8mq/sip_svc.c80
10 files changed, 1398 insertions, 0 deletions
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 4178d188..2f42b812 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -18,6 +18,7 @@
extern void imx8qm_kill_cpu(unsigned int target_idx);
extern void imx8qxp_kill_cpu(unsigned int target_idx);
+extern void imx8m_kill_cpu(unsigned int target_idx);
/*******************************************************************************
* PSCI frontend api for servicing SMCs. Described in the PSCI spec.
@@ -240,6 +241,9 @@ int psci_affinity_info(u_register_t target_affinity,
#ifdef PLAT_IMX8QXP
imx8qxp_kill_cpu(target_idx);
#endif
+#ifdef PLAT_IMX8M
+ imx8m_kill_cpu(target_idx);
+#endif
return ret;
}
diff --git a/plat/freescale/common/mxcuart_console.S b/plat/freescale/common/mxcuart_console.S
new file mode 100644
index 00000000..ebaf315c
--- /dev/null
+++ b/plat/freescale/common/mxcuart_console.S
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of NXP nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm_macros.S>
+
+/* UART Control Register Bit Fields.*/
+#define URXD_CHARRDY (1<<15)
+#define URXD_ERR (1<<14)
+#define URXD_OVRRUN (1<<13)
+#define URXD_FRMERR (1<<12)
+#define URXD_BRK (1<<11)
+#define URXD_PRERR (1<<10)
+#define URXD_RX_DATA (0xFF)
+#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
+#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
+#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
+#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
+#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
+#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
+#define UCR1_IREN (1<<7) /* Infrared interface enable */
+#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
+#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
+#define UCR1_SNDBRK (1<<4) /* Send break */
+#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
+#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
+#define UCR1_DOZE (1<<1) /* Doze */
+#define UCR1_UARTEN (1<<0) /* UART enabled */
+#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
+#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
+#define UCR2_CTSC (1<<13) /* CTS pin control */
+#define UCR2_CTS (1<<12) /* Clear to send */
+#define UCR2_ESCEN (1<<11) /* Escape enable */
+#define UCR2_PREN (1<<8) /* Parity enable */
+#define UCR2_PROE (1<<7) /* Parity odd/even */
+#define UCR2_STPB (1<<6) /* Stop */
+#define UCR2_WS (1<<5) /* Word size */
+#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
+#define UCR2_TXEN (1<<2) /* Transmitter enabled */
+#define UCR2_RXEN (1<<1) /* Receiver enabled */
+#define UCR2_SRST (1<<0) /* SW reset */
+#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
+#define UCR3_PARERREN (1<<12) /* Parity enable */
+#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
+#define UCR3_DSR (1<<10) /* Data set ready */
+#define UCR3_DCD (1<<9) /* Data carrier detect */
+#define UCR3_RI (1<<8) /* Ring indicator */
+#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
+#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
+#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
+#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
+#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
+#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
+#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
+#define UCR3_BPEN (1<<0) /* Preset registers enable */
+#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
+#define UCR4_INVR (1<<9) /* Inverted infrared reception */
+#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
+#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
+#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
+#define UCR4_IRSC (1<<5) /* IR special case */
+#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
+#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
+#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
+#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
+#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
+#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
+#define UFCR_RFDIV_SHF 7 /* Reference freq divider shift */
+#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
+#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
+#define USR1_RTSS (1<<14) /* RTS pin status */
+#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
+#define USR1_RTSD (1<<12) /* RTS delta */
+#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
+#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
+#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
+#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
+#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
+#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
+#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
+#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
+#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
+#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
+#define USR2_IDLE (1<<12) /* Idle condition */
+#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
+#define USR2_WAKE (1<<7) /* Wake */
+#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
+#define USR2_TXDC (1<<3) /* Transmitter complete */
+#define USR2_BRCD (1<<2) /* Break condition */
+#define USR2_ORE (1<<1) /* Overrun error */
+#define USR2_RDR (1<<0) /* Recv data ready */
+#define UTS_FRCPERR (1<<13) /* Force parity error */
+#define UTS_LOOP (1<<12) /* Loop tx and rx */
+#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
+#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
+#define UTS_TXFULL (1<<4) /* TxFIFO full */
+#define UTS_RXFULL (1<<3) /* RxFIFO full */
+#define UTS_SOFTRST (1<<0) /* Software reset */
+
+#define URXD 0x0 /* Receiver Register */
+#define UTXD 0x40 /* Transmitter Register */
+#define UCR1 0x80 /* Control Register 1 */
+#define UCR2 0x84 /* Control Register 2 */
+#define UCR3 0x88 /* Control Register 3 */
+#define UCR4 0x8c /* Control Register 4 */
+#define UFCR 0x90 /* FIFO Control Register */
+#define USR1 0x94 /* Status Register 1 */
+#define USR2 0x98 /* Status Register 2 */
+#define UESC 0x9c /* Escape Character Register */
+#define UTIM 0xa0 /* Escape Timer Register */
+#define UBIR 0xa4 /* BRM Incremental Register */
+#define UBMR 0xa8 /* BRM Modulator Register */
+#define UBRC 0xac /* Baud Rate Count Register */
+#define UTS 0xb4 /* UART Test Register (mx31) */
+
+#define TXTL 2 /* reset default */
+#define RXTL 1 /* reset default */
+#define RFDIV 4 /* divide input clock by 2 */
+
+ .globl console_core_init
+ .globl console_core_putc
+ .globl console_core_getc
+ .globl console_core_flush
+
+/* console_core_init */
+func console_core_init
+ mov w0, wzr
+ ret
+ /* Check the input base address */
+ cbz x0, init_fail
+ /* Check baud rate and uart clock for sanity */
+ cbz w1, init_fail
+ cbz w2, init_fail
+
+ /* clear UCR1 and UCR2 */
+ str wzr, [x0, #UCR1]
+ str wzr, [x0, #UCR2]
+
+ /* Check SRST bit of UCR2 */
+
+ /* Set UCR3 and UCR4 */
+ mov w3, #0x0704
+ orr w3, w3, #UCR3_ADNIMP
+ str w3, [x0, #UCR3]
+
+ mov w3, #0x8000
+ str w3, [x0, #UCR4]
+
+ mov w3, #0x2b
+ str w3, [x0, #UESC]
+
+ str wzr, [x0, #UTIM]
+ str wzr, [x0, #UTS]
+
+ /* Set baud rate */
+ mov w4, #RFDIV
+ lsl w3, w4, #UFCR_RFDIV_SHF
+ mov w4, #TXTL
+ orr w3, w3, w4, lsl #UFCR_TXTL_SHF
+ mov w4, #RXTL
+ orr w3, w3, w4, lsl #UFCR_RXTL_SHF
+ str w3, [x0, #UFCR]
+
+ mov w3, #0xF
+ str w3, [x0, #UBIR]
+
+ lsl w3, w2, #1
+ udiv w3, w1, w3
+ str w3, [x0, #UBMR]
+
+ /* Configure the UCR2 and UCR1 */
+ mov w3, #UCR2_WS
+ orr w3, w3, #UCR2_IRTS
+ orr w3, w3, #UCR2_RXEN
+ orr w3, w3, #UCR2_TXEN
+ orr w3, w3, #UCR2_SRST
+ str w3, [x0, #UCR2]
+
+ mov w3, #UCR1_UARTEN
+ str w3, [x0, #UCR1]
+init_fail:
+ ret
+endfunc console_core_init
+
+ /* --------------------------------------------------------
+ * int console_core_putc(int c, unsigned int base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or -1 on error.
+ * In : w0 - character to be printed
+ * x1 - console base address
+ * Out : return -1 on error else return character.
+ * Clobber list : x2
+ * --------------------------------------------------------
+ */
+func console_core_putc
+ /* Check the input parameter */
+ cbz w1, putc_error
+
+ str w0, [x1, #UTXD]
+1:
+ ldr w2, [x1, #UTS]
+ tbz w2, #6, 1b
+
+ cmp w0, #0xA
+ b.ne 2f
+ mov w0, #0xD
+ b console_core_putc
+2:
+ ret
+putc_error:
+ mov w0, #-1
+ ret
+endfunc console_core_putc
+
+ /* ---------------------------------------------
+ * int console_core_getc(unsigned int base_addr)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or -1 on error.
+ * In : x0 - console base address
+ * Out : return -1 on error else return character.
+ * Clobber list : x0, x1, x2
+ * ---------------------------------------------
+ */
+func console_core_getc
+ 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_core_getc
+
+/* console_core_flush */
+func console_core_flush
+ mov w0, wzr
+ ret
+endfunc console_core_flush
diff --git a/plat/freescale/imx8mq/gpc.c b/plat/freescale/imx8mq/gpc.c
new file mode 100644
index 00000000..58744c24
--- /dev/null
+++ b/plat/freescale/imx8mq/gpc.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <debug.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <smcc_helpers.h>
+#include <std_svc.h>
+#include <types.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <fsl_sip.h>
+#include <soc.h>
+
+#define GPC_LPCR_A53_BSC 0x0
+#define GPC_LPCR_A53_BSC2 0x108
+#define GPC_LPCR_A53_AD 0x4
+#define GPC_LPCR_M4 0x8
+#define GPC_SLPCR 0x14
+#define GPC_MST_CPU_MAPPING 0x18
+#define GPC_PGC_ACK_SEL_A53 0x24
+#define GPC_IMR1_CORE0_A53 0x30
+#define GPC_IMR2_CORE0_A53 0x34
+#define GPC_IMR3_CORE0_A53 0x38
+#define GPC_IMR4_CORE0_A53 0x3c
+#define GPC_IMR1_CORE1_A53 0x40
+#define GPC_IMR2_CORE1_A53 0x44
+#define GPC_IMR3_CORE1_A53 0x48
+#define GPC_IMR4_CORE1_A53 0x4c
+#define GPC_IMR1_CORE2_A53 0x1c0
+#define GPC_IMR2_CORE2_A53 0x1c4
+#define GPC_IMR3_CORE2_A53 0x1c8
+#define GPC_IMR4_CORE2_A53 0x1cc
+#define GPC_IMR1_CORE3_A53 0x1d0
+#define GPC_IMR2_CORE3_A53 0x1d4
+#define GPC_IMR3_CORE3_A53 0x1d8
+#define GPC_IMR4_CORE3_A53 0x1dc
+#define GPC_PGC_CPU_0_1_MAPPING 0xec
+#define GPC_PGC_CORE0_TIMMING 0x804
+#define GPC_PGC_CORE1_TIMMING 0x844
+#define GPC_PGC_CORE2_TIMMING 0x884
+#define GPC_PGC_CORE3_TIMMING 0x8c4
+#define GPC_PGC_SCU_TIMMING 0x910
+#define GPC_SLOT0_CFG 0xb0
+
+#define LPCR_A53_BSC_CPU_CLK_ON_LPM 0x4000
+#define LPCR_A53_BSC_LPM0 0x3
+#define LPCR_A53_BSC_LPM1 0xc
+#define LPCR_A53_BSC2_LPM2 0x3
+#define LPCR_A53_BSC2_LPM3 0xc
+
+#define LPCR_A53_AD_L2PGE 0x80000000
+#define LPCR_A53_AD_EN_C3_PUP 0x8000000
+#define LPCR_A53_AD_EN_C3_IRQ_PUP 0x4000000
+#define LPCR_A53_AD_EN_C2_PUP 0x2000000
+#define LPCR_A53_AD_EN_C2_IRQ_PUP 0x1000000
+#define LPCR_A53_AD_EN_C3_PDN 0x80000
+#define LPCR_A53_AD_EN_C3_WFI_PDN 0x40000
+#define LPCR_A53_AD_EN_C2_PDN 0x20000
+#define LPCR_A53_AD_EN_C2_WFI_PDN 0x10000
+#define LPCR_A53_AD_EN_C1_PUP 0x800
+#define LPCR_A53_AD_EN_C1_IRQ_PUP 0x400
+#define LPCR_A53_AD_EN_C0_PUP 0x200
+#define LPCR_A53_AD_EN_C0_IRQ_PUP 0x100
+#define LPCR_A53_AD_EN_L2_WFI_PDN 0x20
+#define LPCR_A53_AD_EN_PLAT_PDN 0x10
+#define LPCR_A53_AD_EN_C1_PDN 0x8
+#define LPCR_A53_AD_EN_C1_WFI_PDN 0x4
+#define LPCR_A53_AD_EN_C0_PDN 0x2
+#define LPCR_A53_AD_EN_C0_WFI_PDN 0x1
+
+#define A53_LPM_WAIT 0x5
+#define A53_LPM_STOP 0xa
+
+#define SLPCR_EN_DSM 0x80000000
+#define SLPCR_RBC_EN 0x40000000
+#define SLPCR_VSTBY 0x4
+#define SLPCR_SBYOS 0x2
+#define SLPCR_BYPASS_PMIC_READY 0x1
+#define SLPCR_A53_FASTWUP_STOP (1 << 17)
+#define SLPCR_A53_FASTWUP_WAIT (1 << 16)
+
+#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
+#define GPC_CPU_PGC_SW_PDN_REQ 0xf4
+#define BM_CPU_PGC_SW_PDN_PUP_REQ 0x1
+
+#define GPC_ARM_PGC 0x800
+#define PGC_PCR 0
+
+static uint32_t gpc_saved_imrs[128];
+static uint32_t gpc_wake_irqs[128];
+//static uint32_t gpc_mf_irqs[128];
+
+void imx_gpc_set_m_core_pgc(unsigned int cpu, bool pdn)
+{
+ uintptr_t val;
+
+ val = mmio_read_32(IMX_GPC_BASE + GPC_ARM_PGC + cpu * 64);
+ val &= ~(0x1 << PGC_PCR);
+
+ if(pdn)
+ val |= 0x1 << PGC_PCR;
+ mmio_write_32(IMX_GPC_BASE + GPC_ARM_PGC + cpu * 64, val);
+}
+
+void imx_gpc_set_lpm_mode(enum imx_cpu_pwr_mode mode)
+{
+ uint32_t val1, val2, val3, val4;
+
+ val1 = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC);
+ val2 = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC2);
+ val3 = mmio_read_32(IMX_GPC_BASE + GPC_SLPCR);
+ val4 = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_AD);
+
+ /* all core's LPM setting must be same */
+ val1 &= ~(LPCR_A53_BSC_LPM0 | LPCR_A53_BSC_LPM1);
+ val2 &= ~(LPCR_A53_BSC2_LPM2 | LPCR_A53_BSC2_LPM3);
+ val3 &= ~(SLPCR_EN_DSM | SLPCR_RBC_EN | SLPCR_VSTBY |
+ SLPCR_SBYOS | SLPCR_BYPASS_PMIC_READY);
+ val4 |= (1 << 5);
+
+ switch(mode) {
+ case WAIT_CLOCKED:
+ break;
+ case WAIT_UNCLOCKED:
+ val1 |= A53_LPM_WAIT;
+ val2 |= A53_LPM_WAIT;
+ val1 &= ~LPCR_A53_BSC_CPU_CLK_ON_LPM;
+ break;
+ case STOP_POWER_ON:
+ val1 |= A53_LPM_STOP;
+ val2 |= A53_LPM_STOP;
+ val1 &= ~LPCR_A53_BSC_CPU_CLK_ON_LPM;
+ val3 |= SLPCR_EN_DSM;
+ val3 |= SLPCR_RBC_EN;
+ val3 |= SLPCR_BYPASS_PMIC_READY;
+ break;
+ case STOP_POWER_OFF:
+ val1 |= A53_LPM_STOP;
+ val2 |= A53_LPM_STOP;
+ val1 &= ~LPCR_A53_BSC_CPU_CLK_ON_LPM;
+ val3 |= SLPCR_EN_DSM;
+ val3 |= SLPCR_A53_FASTWUP_STOP;
+ val3 |= SLPCR_RBC_EN;
+ val3 |= SLPCR_VSTBY;
+ val3 |= SLPCR_SBYOS;
+ val3 |= SLPCR_BYPASS_PMIC_READY;
+ val4 &= ~(1 << 5);
+ break;
+ default:
+ break;
+ }
+
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC, val1);
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC2, val2);
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_AD, val4);
+ mmio_write_32(IMX_GPC_BASE + GPC_SLPCR, val3);
+}
+
+/* enable CORE LPM PDN/WUP in AD register */
+void imx_gpc_set_cpu_power_gate_by_lpm(unsigned int cpu, bool pdn)
+{
+ uint32_t mask, val;
+
+ val = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_AD);
+
+ switch(cpu) {
+ case 0:
+ mask = LPCR_A53_AD_EN_C0_PDN | LPCR_A53_AD_EN_C0_PUP;
+ break;
+ case 1:
+ mask = LPCR_A53_AD_EN_C1_PDN | LPCR_A53_AD_EN_C1_PUP;
+ break;
+ case 2:
+ mask = LPCR_A53_AD_EN_C2_PDN | LPCR_A53_AD_EN_C3_PUP;
+ break;
+ case 3:
+ mask = LPCR_A53_AD_EN_C3_PDN | LPCR_A53_AD_EN_C3_PUP;
+ break;
+ default:
+ return;
+ }
+
+ if (pdn)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_AD, val);
+}
+
+/* enable PLAT/SCU power down in AD register */
+void imx_gpc_set_plat_power_gate_by_lpm(bool pdn)
+{
+ uint32_t val;
+
+ val = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_AD);
+ val &= ~(LPCR_A53_AD_EN_PLAT_PDN | LPCR_A53_AD_L2PGE);
+
+ if (pdn)
+ val |= LPCR_A53_AD_EN_PLAT_PDN | LPCR_A53_AD_L2PGE;
+
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_AD, val);
+}
+
+void imx_gpc_set_slot_ack(uint32_t index, enum imx_gpc_slot m_core,
+ bool mode, bool ack)
+{
+ uint32_t val, shift;
+
+ if (index > 10) {
+ tf_printf("Invalid slot index\n");
+ return;
+ }
+ /* set slot */
+ val = mmio_read_32(IMX_GPC_BASE + GPC_SLOT0_CFG + index * 4);
+ val |= (mode + 1) << m_core * 2;
+ mmio_write_32(IMX_GPC_BASE + GPC_SLOT0_CFG + index * 4, val);
+ /* set ack */
+ if (ack) {
+ shift = m_core >= A53_SCU ? 2 : 0;
+ val = mmio_read_32(IMX_GPC_BASE + GPC_PGC_ACK_SEL_A53);
+ /* clear dummy ack */
+ val &= ~(1 << (15 + (mode ? 16: 0)));
+ val |= 1 << (shift + (mode ? 16 : 0));
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_ACK_SEL_A53, val);
+ }
+}
+
+/* cpu: cpu index */
+void imx_gpc_set_core_pdn_pup_by_software(unsigned int cpu, bool pdn)
+{
+ uint32_t val, index;
+
+ val = mmio_read_32(IMX_GPC_BASE + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ));
+
+ /*Set the core PCR bit before sw PUP/PDN trigger */
+ imx_gpc_set_m_core_pgc(cpu, true);
+
+ index = cpu < 2 ? cpu : cpu + 1;
+ val |= (BM_CPU_PGC_SW_PDN_PUP_REQ << index);
+ mmio_write_32(IMX_GPC_BASE + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ), val);
+
+ while((mmio_read_32(IMX_GPC_BASE + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) &
+ BM_CPU_PGC_SW_PDN_PUP_REQ) != 0)
+ ;
+
+ /*Clear the core PCR bit after sw PUP/PDN trigger */
+ imx_gpc_set_m_core_pgc(cpu, false);
+}
+
+void imx_gpc_pre_suspend(bool arm_power_off)
+{
+ unsigned int i;
+
+ /* set the LPM mode */
+ if (arm_power_off) {
+ /* enable core 0/1/2/3 power down/up with low power mode */
+ /* enable plat power down/up with low power mode */
+
+ /*
+ * to avoid confuse, we use slot 0~4 for power down.
+ * slot 5~9 for power up.
+ * power down slot sequence:
+ * slot 0 -> CORE0,
+ * SLOT 1 -> Mega/Fast mix,
+ * SLOT 2 -> SCU
+ *
+ * SLOT 5 -> Mega/Fast mix,
+ * SLOT 6 -> SCU
+ * SLOT 7 -> CORE0
+ */
+ /* SCU slot ack as the power down ack */
+ /* CORE0 slot ack as the power up ack */
+ imx_gpc_set_lpm_mode(STOP_POWER_OFF);
+ imx_gpc_set_slot_ack(0, A53_CORE0, false, false);
+ imx_gpc_set_slot_ack(2, A53_SCU, false, true);
+
+ imx_gpc_set_slot_ack(6, A53_SCU, true, false);
+ imx_gpc_set_slot_ack(7, A53_CORE0, true, true);
+ imx_gpc_set_m_core_pgc(0, true);
+ imx_gpc_set_m_core_pgc(4, true);
+
+ imx_gpc_set_cpu_power_gate_by_lpm(0, true);
+ imx_gpc_set_plat_power_gate_by_lpm(true);
+ } else {
+ imx_gpc_set_lpm_mode(STOP_POWER_ON);
+ }
+
+ for (i = 0; i < 4; i++) {
+ gpc_saved_imrs[i] = mmio_read_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + i * 4);
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + i * 4, ~gpc_wake_irqs[i]);
+ }
+
+}
+
+void imx_gpc_post_resume(void)
+{
+ int i;
+ /* set LPM mode WAIT CLOCKED */
+ imx_gpc_set_lpm_mode(WAIT_CLOCKED);
+ /* clear lpm power gate of core and plat */
+ imx_gpc_set_cpu_power_gate_by_lpm(0, false);
+ imx_gpc_set_plat_power_gate_by_lpm(false);
+ /* clear PGC PDN bit */
+ imx_gpc_set_m_core_pgc(0, false);
+ imx_gpc_set_m_core_pgc(4, false);
+
+ for (i = 0; i < 4; i++) {
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + i * 4, gpc_saved_imrs[i]);
+ }
+
+ /* skip slot m4 use , clear slots */
+ for(i = 0; i < 10; i ++) {
+ if (i == 1 || i == 5)
+ continue;
+ mmio_write_32(IMX_GPC_BASE +GPC_SLOT0_CFG + i * 0x4, 0x0);
+ }
+ /* set DUMMY PDN/PUP ACK by default for A53 domain */
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_ACK_SEL_A53, 1 << 31 | 1 << 15);
+}
+
+static void imx_gpc_hwirq_mask(unsigned int hwirq)
+{
+ uintptr_t reg;
+ unsigned int val;
+
+ reg = IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + (hwirq / 32) * 4;
+ val = mmio_read_32(reg);
+ val |= 1 << hwirq % 32;
+ mmio_write_32(reg, val);
+}
+
+static void imx_gpc_hwirq_unmask(unsigned int hwirq)
+{
+ uintptr_t reg;
+ unsigned int val;
+
+ reg = IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + (hwirq / 32) * 4;
+ val = mmio_read_32(reg);
+ val &= ~(1 << hwirq % 32);
+ mmio_write_32(reg, val);
+}
+
+static void imx_gpc_set_wake(uint32_t hwirq, unsigned int on)
+{
+ uint32_t mask, idx;
+
+ mask = 1 << hwirq % 32;
+ idx = hwirq / 32;
+ gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
+ gpc_wake_irqs[idx] & ~mask;
+}
+
+static void imx_gpc_pm_domain_enable(uint32_t domain_id, uint32_t on)
+{
+ uint32_t val;
+ uintptr_t reg;
+
+ reg = IMX_GPC_BASE + (on ? 0xf8 : 0x104);
+ val = 1 << domain_id;
+ mmio_write_32(reg, val);
+ while(mmio_read_32(reg) & val)
+ ;
+}
+
+void imx_gpc_init(void)
+{
+ unsigned int val;
+ int i;
+ /* mask all the interrupt by default */
+ for (i = 0; i < 4; i ++) {
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + i * 4, ~0x0);
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE1_A53 + i * 4, ~0x0);
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE2_A53 + i * 4, ~0x0);
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE3_A53 + i * 4, ~0x0);
+ }
+
+ /* 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.
+ */
+ mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53, ~0x1);
+
+ /* use external IRQs to wakeup C0~C3 from LPM */
+ val = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC);
+ val |= 0x70c00000;
+ /* clear the MASTER0 LPM handshake */
+ val &= ~(1 << 6);
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_A53_BSC, val);
+
+ /* mask M4 DSM trigger if M4 is NOT enabled */
+ val = mmio_read_32(IMX_GPC_BASE + GPC_LPCR_M4);
+ val |= 1 << 31;
+ mmio_write_32(IMX_GPC_BASE + GPC_LPCR_M4, val);
+
+ /* set mega/fast mix in A53 domain */
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_CPU_0_1_MAPPING, 0x1);
+
+ /* set SCU timming */
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_SCU_TIMMING,
+ (0x59 << 10) | 0x5B | (0x2 << 20));
+
+ /* set A53 core power up timming */
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_CORE0_TIMMING, 0x1a << 7);
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_CORE1_TIMMING, 0x1a << 7);
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_CORE2_TIMMING, 0x1a << 7);
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_CORE3_TIMMING, 0x1a << 7);
+
+ /* set DUMMY PDN/PUP ACK by default for A53 domain */
+ mmio_write_32(IMX_GPC_BASE + GPC_PGC_ACK_SEL_A53, 1 << 31 | 1 << 15);
+ /* clear DSM by default */
+ val = mmio_read_32(IMX_GPC_BASE + GPC_SLPCR);
+ val &= ~(1 << 31);
+ /* TODO if M4 is not enabled, clear more SLPCR bits */
+ mmio_write_32(IMX_GPC_BASE + GPC_SLPCR, val);
+}
+
+int imx_gpc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3)
+{
+ switch(x1) {
+ case FSL_SIP_CONFIG_GPC_SET_WAKE:
+ imx_gpc_set_wake(x2, x3);
+ break;
+ case FSL_SIP_CONFIG_GPC_MASK:
+ imx_gpc_hwirq_mask(x2);
+ break;
+ case FSL_SIP_CONFIG_GPC_UNMASK:
+ imx_gpc_hwirq_unmask(x2);
+ break;
+ case FSL_SIP_CONFIG_GPC_PM_DOMAIN:
+ imx_gpc_pm_domain_enable(x2, x3);
+ break;
+ default:
+ return SMC_UNK;
+ }
+
+ return 0;
+}
diff --git a/plat/freescale/imx8mq/imx8m_bl31_setup.c b/plat/freescale/imx8mq/imx8m_bl31_setup.c
new file mode 100644
index 00000000..9bc2fbbc
--- /dev/null
+++ b/plat/freescale/imx8mq/imx8m_bl31_setup.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright 2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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 <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <plat_imx8.h>
+#include <xlat_tables.h>
+#include <soc.h>
+
+/* linker defined symbols */
+extern unsigned long __RO_START__;
+extern unsigned long __RO_END__;
+extern unsigned long __BL31_END__;
+
+#if USE_COHERENT_MEM
+extern unsigned long __COHERENT_RAM_START__;
+extern unsigned long __COHERENT_RAM_END__;
+
+#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+#endif
+
+#define BL31_RO_BASE (unsigned long)(&__RO_START__)
+#define BL31_RO_LIMIT (unsigned long)(&__RO_END__)
+#define BL31_END (unsigned long)(&__BL31_END__)
+
+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;
+}
+
+#define SCTR_BASE_ADDR 0x306c0000
+#define CNTFID0_OFF 0x20
+#define CNTFID1_OFF 0x24
+
+#define SC_CNTCR_ENABLE (1 << 0)
+#define SC_CNTCR_HDBG (1 << 1)
+#define SC_CNTCR_FREQ0 (1 << 8)
+#define SC_CNTCR_FREQ1 (1 << 9)
+
+unsigned int freq;
+
+void system_counter_init(void)
+{
+ int val;
+
+ /* Update with accurate clock frequency */
+ freq = mmio_read_32(SCTR_BASE_ADDR + CNTFID0_OFF);
+
+ val = mmio_read_32(SCTR_BASE_ADDR + CNTCR_OFF);
+ val &= ~(SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1);
+ val |= SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG;
+ mmio_write_32(SCTR_BASE_ADDR + CNTCR_OFF, val);
+}
+
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+ void *plat_params_from_bl2)
+{
+ int i;
+ /* enable CSU NS access permission */
+ for (i = 0; i < 64; i++) {
+ mmio_write_32(0x303e0000 + i * 4, 0xffffffff);
+ }
+
+ mmio_write_32(0x303a00ec, 0x0000ffff);
+ /* Power up VPU, DISP, GPU etc */
+ mmio_write_32(0x303a00f8, 0x3fef);
+
+ /* config the AIPSTZ1 */
+ mmio_write_32(0x301f0000, 0x77777777);
+ mmio_write_32(0x301f0004, 0x77777777);
+ mmio_write_32(0x301f0040, 0x0);
+ mmio_write_32(0x301f0044, 0x0);
+ mmio_write_32(0x301f0048, 0x0);
+ mmio_write_32(0x301f004c, 0x0);
+ mmio_write_32(0x301f0050, 0x0);
+
+ /* config the AIPSTZ3 */
+ mmio_write_32(0x309f0000, 0x77777777);
+ mmio_write_32(0x309f0004, 0x77777777);
+ mmio_write_32(0x309f0040, 0x0);
+ mmio_write_32(0x309f0044, 0x0);
+ mmio_write_32(0x309f0048, 0x0);
+ mmio_write_32(0x309f004c, 0x0);
+ mmio_write_32(0x309f0050, 0x0);
+
+ /* enable the system counter */
+ system_counter_init();
+
+ /*
+ * 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);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ /* add the mmap */
+ mmap_add_region(BL31_BASE, BL31_BASE, 0x10000,
+ MT_MEMORY | MT_RW);
+ mmap_add_region(BL31_BASE, BL31_BASE, BL31_RO_LIMIT - BL31_RO_BASE,
+ MT_MEMORY | MT_RO);
+ mmap_add_region(IMX_BOOT_UART_BASE, IMX_BOOT_UART_BASE,
+ 0x1000, MT_DEVICE | MT_RW);
+ mmap_add_region(IMX_SRC_BASE, IMX_SRC_BASE,
+ 0x1000, MT_DEVICE | MT_RW);
+ mmap_add_region(IMX_GPC_BASE, IMX_GPC_BASE, 0x1000, MT_DEVICE | MT_RW);
+ mmap_add_region(IMX_ANAMIX_BASE, IMX_ANAMIX_BASE, 0x1000, MT_DEVICE | MT_RW);
+ mmap_add_region(PLAT_GICD_BASE, PLAT_GICD_BASE, 0x80000,
+ MT_DEVICE | MT_RW);
+ mmap_add_region(PLAT_GICR_BASE, PLAT_GICR_BASE, 0x80000,
+ MT_DEVICE | MT_RW);
+#if USE_COHERENT_MEM
+ mmap_add_region(BL31_COHERENT_RAM_BASE, BL31_COHERENT_RAM_BASE,
+ BL31_COHERENT_RAM_LIMIT - BL31_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW);
+#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 freq;
+}
diff --git a/plat/freescale/imx8mq/imx8m_psci.c b/plat/freescale/imx8mq/imx8m_psci.c
new file mode 100644
index 00000000..f53c81eb
--- /dev/null
+++ b/plat/freescale/imx8mq/imx8m_psci.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright 2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <plat_imx8.h>
+#include <psci.h>
+#include <mmio.h>
+#include <soc.h>
+
+#define SCR_A53RCR1_OFFSET 0x08
+#define SRC_GPR1_OFFSET 0x74
+#define ARM_PGC 0x800
+#define PGC_PCR 1
+#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
+#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
+
+extern void imx_gpc_set_core_pdn_pup_by_software(unsigned int cpu, bool pdn);
+extern void imx_gpc_set_cpu_power_gate_by_wfi(unsigned int cpu, bool pdn);
+
+const unsigned char imx_power_domain_tree_desc[] = {
+ /* number of root nodes */
+ PWR_DOMAIN_AT_MAX_LVL,
+ /* number of child at the first node */
+ PLATFORM_CLUSTER_COUNT,
+ PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+void imx8m_kill_cpu(unsigned int target_idx)
+{
+ unsigned int val1;
+
+ /* Disable the secondary core */
+ val1 = mmio_read_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET);
+ val1 &= ~(1 << target_idx);
+ mmio_write_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET, val1);
+
+ imx_gpc_set_core_pdn_pup_by_software(target_idx, true);
+}
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+ int ret = PSCI_E_SUCCESS;
+ unsigned int cpu_id, reg;
+
+ uint64_t base_addr = BL31_BASE;
+
+ tf_printf("cpu on\n");
+ cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+ /* core power up sequence
+ * 1. Assert nCPUPORESET
+ * 2. power the core.
+ * 3. Deassert reset.
+ */
+ reg = mmio_read_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET);
+ reg &= ~(1 << cpu_id);
+ mmio_write_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET, reg);
+
+ /* Set CPU jump address */
+ if (cpu_id > 0) {
+ base_addr >>= 2;
+ mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (cpu_id << 3),
+ ((uint32_t)(base_addr >> 22) & 0xFFFF));
+ mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (cpu_id << 3) + 4,
+ ((uint32_t)base_addr & 0x003FFFFF));
+ }
+
+ imx_gpc_set_core_pdn_pup_by_software(cpu_id, false);
+
+ /* Kick CPU here */
+ reg = mmio_read_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET);
+ reg |= (1 << cpu_id);
+ mmio_write_32(IMX_SRC_BASE + SCR_A53RCR1_OFFSET, reg);
+
+ return ret;
+}
+
+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)
+{
+ plat_gic_cpuif_disable();
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+ /* TODO */
+ 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);
+
+ if (pwr_lvl > PLAT_MAX_PWR_LVL)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Sanity check the requested afflvl */
+ if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
+ if (pwr_lvl != MPIDR_AFFLVL0)
+ return PSCI_E_INVALID_PARAMS;
+ /* power domain in standby state */
+ req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
+
+ return PSCI_E_SUCCESS;
+ }
+
+ return 0;
+}
+
+void imx_cpu_standby(plat_local_state_t cpu_state)
+{
+ dsb();
+ write_icc_igrpen1_el1(1);
+ write_scr_el3(read_scr_el3() | 0x4);
+ isb();
+
+ wfi();
+
+ write_icc_igrpen1_el1(0);
+ write_scr_el3(read_scr_el3() & (~0x4));
+ isb();
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint64_t base_addr = BL31_BASE;
+ plat_gic_cpuif_disable();
+
+ /* imx gpc pre suspend */
+ imx_gpc_pre_suspend(true);
+
+ base_addr >>= 2;
+ mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET ,
+ ((uint32_t)(base_addr >> 22) & 0xFFFF));
+ mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + 4,
+ ((uint32_t)base_addr & 0x003FFFFF));
+
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ /* imx gpc post resume */
+ imx_gpc_post_resume();
+ /* enable the GICv3 cpu interface */
+ plat_gic_cpuif_enable();
+}
+
+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_MAX_RET_STATE;
+}
+
+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,
+ .get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+};
+
+/* 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/freescale/imx8mq/include/fsl_sip.h b/plat/freescale/imx8mq/include/fsl_sip.h
new file mode 100644
index 00000000..73fa08d4
--- /dev/null
+++ b/plat/freescale/imx8mq/include/fsl_sip.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SOC_FSL_SIP_H
+#define __SOC_FSL_SIP_H
+
+#define FSL_SIP_GPC 0xC2000000
+#define FSL_SIP_CONFIG_GPC_MASK 0x00
+#define FSL_SIP_CONFIG_GPC_UNMASK 0x01
+#define FSL_SIP_CONFIG_GPC_SET_WAKE 0x02
+#define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03
+
+#endif
diff --git a/plat/freescale/imx8mq/include/platform_def.h b/plat/freescale/imx8mq/include/platform_def.h
new file mode 100644
index 00000000..8d5dffb7
--- /dev/null
+++ b/plat/freescale/imx8mq/include/platform_def.h
@@ -0,0 +1,52 @@
+#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH aarch64
+
+#define PLATFORM_STACK_SIZE 0X400
+#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_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 1
+#define PLAT_MAX_PWR_LVL 2
+#define PLAT_MAX_OFF_STATE 2
+#define PLAT_MAX_RET_STATE 1
+
+#define BL31_BASE 0x40001000
+#define BL31_LIMIT 0x40021000
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET 0x40021000
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE 0x38800000
+#define PLAT_GICR_BASE 0x38880000
+
+#define PLAT_FSL_ADDR_SPACE_SIZE (1ull << 32)
+#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 16
+
+#define IMX_BOOT_UART_BASE 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_ANAMIX_BASE 0x30360000
+#define IMX_SRC_BASE 0x30390000
+#define IMX_GPC_BASE 0x303a0000
+
+#define COUNTER_FREQUENCY 8000000 /* 8MHz */
+
+#define DEBUG_CONSOLE 0
+#define PLAT_IMX8M 1
diff --git a/plat/freescale/imx8mq/include/soc.h b/plat/freescale/imx8mq/include/soc.h
new file mode 100644
index 00000000..ebce7ea8
--- /dev/null
+++ b/plat/freescale/imx8mq/include/soc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __IMX_SOC_H
+#define __IMX_SOC_H
+
+enum imx_cpu_pwr_mode {
+ WAIT_CLOCKED, /* wfi only */
+ WAIT_UNCLOCKED, /* WAIT */
+ WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */
+ STOP_POWER_ON, /* just STOP */
+ STOP_POWER_OFF, /* STOP + SRPG */
+};
+
+enum imx_gpc_slot {
+ A53_CORE0,
+ A53_CORE1,
+ A53_CORE2,
+ A53_CORE3,
+ A53_SCU,
+};
+
+enum imx_gpc_pu_slot {
+ FAST_MEGA_MIX,
+ MIPI_PHY,
+ PCIE1_PHY,
+ OTG1_PHY,
+ OTG2_PHY,
+ RESERVED,
+ CORE1_M4,
+ DDR1_PHY,
+ DDR2_PHY,
+ GPU,
+ VPU,
+ HDMI_PHY,
+ DSIP,
+ MIPI_CSI1,
+ MIPI_CSI2,
+ PCIE2_PHY,
+};
+
+void imx_gpc_set_m_core_pgc(unsigned int cpu, bool pdn);
+void imx_gpc_set_lpm_mode(enum imx_cpu_pwr_mode mode);
+void imx_gpc_set_cpu_power_gate_by_lpm(unsigned int cpu, bool pdn);
+void imx_gpc_set_plat_power_gate_by_lpm(bool pdn);
+void imx_gpc_set_core_pdn_pup_by_software(unsigned int cpu, bool pdn);
+void imx_gpc_set_cpu_ppower_gate_by_wfi(unsigned int cpu, bool pdn);
+void imx_gpc_pre_suspend(bool arm_power_off);
+void imx_gpc_post_resume(void);
+void imx_gpc_init(void);
+
+
+void imx_enable_cpu(unsigned int cpu, bool enable);
+int imx_is_m4_enabled(void);
+void imx_set_cpu_jump_addr(unsigned int cpu, void *jump_addr);
+#endif /* __IMX_SOC_H */
diff --git a/plat/freescale/imx8mq/platform.mk b/plat/freescale/imx8mq/platform.mk
new file mode 100644
index 00000000..ec51a899
--- /dev/null
+++ b/plat/freescale/imx8mq/platform.mk
@@ -0,0 +1,27 @@
+PLAT_INCLUDES := -Iplat/freescale/imx8mq/include \
+ -Iplat/freescale/common/include \
+
+PLAT_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \
+ drivers/arm/gic/v3/gicv3_main.c \
+ drivers/arm/gic/common/gic_common.c \
+ plat/common/plat_gicv3.c \
+ plat/freescale/common/plat_imx8_gic.c
+
+BL31_SOURCES += plat/freescale/common/imx8_helpers.S \
+ plat/freescale/common/mxcuart_console.S \
+ plat/freescale/imx8mq/imx8m_bl31_setup.c \
+ plat/freescale/imx8mq/gpc.c \
+ plat/freescale/imx8mq/imx8m_psci.c \
+ plat/freescale/imx8mq/sip_svc.c \
+ plat/freescale/common/imx8_topology.c \
+ plat/common/plat_psci_common.c \
+ 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 \
+ ${PLAT_GIC_SOURCES} \
+
+ENABLE_PLAT_COMPAT := 0
+USE_COHERENT_MEM := 0
+RESET_TO_BL31 := 1
+ERROR_DEPRECATED := 1
diff --git a/plat/freescale/imx8mq/sip_svc.c b/plat/freescale/imx8mq/sip_svc.c
new file mode 100644
index 00000000..0bf9cd3e
--- /dev/null
+++ b/plat/freescale/imx8mq/sip_svc.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright 2017 NXP
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <fsl_sip.h>
+#include <runtime_svc.h>
+#include <smcc_helpers.h>
+#include <std_svc.h>
+#include <stdint.h>
+#include <uuid.h>
+
+extern int imx_gpc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3);
+
+/* Setup i.MX platform specific services Services */
+static int32_t plat_svc_setup(void)
+{
+ /* gpc init ?*/
+ NOTICE("sip svc init\n");
+ return 0;
+}
+
+/* i.MX platform specific service SMC handler */
+uintptr_t imx_svc_smc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ uint64_t flags)
+{
+ NOTICE("smc_fid is %x\n", smc_fid);
+ switch (smc_fid) {
+ case FSL_SIP_GPC:
+ SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3));
+ break;
+ default:
+ WARN("Uimplemented SIP Service Call: 0x%x \n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ break;
+ }
+}
+
+/* Rigister SIP Service Calls as runtime service */
+DECLARE_RT_SVC(
+ imx_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ plat_svc_setup,
+ imx_svc_smc_handler
+);