From 6aafe1fcd7296eded1163d919b6ce018487e8645 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Fri, 11 May 2018 13:58:31 +0800 Subject: plat: imx8mm: add basic imx8mm support i.MX8MM is a new soc of the i.MX8M family, this patch add the basic support for i.MX8MM. further code optimization needed. WAIT mode support is currently disabled, will be enabled later. Signed-off-by: Bai Ping --- plat/imx/common/sip_svc.c | 10 +- plat/imx/imx8mm/gpc.c | 677 +++++++++++++++++++++++++++++++++ plat/imx/imx8mm/imx8mm_bl31_setup.c | 230 +++++++++++ plat/imx/imx8mm/imx8mm_psci.c | 253 ++++++++++++ plat/imx/imx8mm/include/platform_def.h | 85 +++++ plat/imx/imx8mm/include/soc.h | 33 ++ plat/imx/imx8mm/misc.c | 60 +++ plat/imx/imx8mm/platform.mk | 41 ++ 8 files changed, 1385 insertions(+), 4 deletions(-) create mode 100644 plat/imx/imx8mm/gpc.c create mode 100644 plat/imx/imx8mm/imx8mm_bl31_setup.c create mode 100644 plat/imx/imx8mm/imx8mm_psci.c create mode 100644 plat/imx/imx8mm/include/platform_def.h create mode 100644 plat/imx/imx8mm/include/soc.h create mode 100644 plat/imx/imx8mm/misc.c create mode 100644 plat/imx/imx8mm/platform.mk (limited to 'plat') diff --git a/plat/imx/common/sip_svc.c b/plat/imx/common/sip_svc.c index 9432c12e..02728556 100644 --- a/plat/imx/common/sip_svc.c +++ b/plat/imx/common/sip_svc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. - * Copyright 2017 NXP + * Copyright 2017-2018 NXP * * SPDX-License-Identifier: BSD-3-Clause */ @@ -90,12 +90,14 @@ uintptr_t imx_svc_smc_handler(uint32_t smc_fid, NOTICE("smc_fid is %x\n", smc_fid); switch (smc_fid) { #ifdef PLAT_IMX8M - case FSL_SIP_GPC: - SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3)); - break; case FSL_SIP_DDR_DVFS: SMC_RET1(handle, lpddr4_dvfs_handler(smc_fid, x1, x2, x3)); break; +#endif +#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM) + case FSL_SIP_GPC: + SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3)); + break; case FSL_SIP_SRC: SMC_RET1(handle, imx_src_handler(smc_fid, x1, x2, x3)); break; diff --git a/plat/imx/imx8mm/gpc.c b/plat/imx/imx8mm/gpc.c new file mode 100644 index 00000000..319e1054 --- /dev/null +++ b/plat/imx/imx8mm/gpc.c @@ -0,0 +1,677 @@ +/* + * Copyright 2018 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPC_MST_CPU_MAPPING 0x18 +#define GPC_PGC_ACK_SEL_A53 0x24 +#define GPC_IMR1_CORE0_A53 0x30 +#define GPC_IMR1_CORE1_A53 0x40 +#define GPC_IMR1_CORE0_M4 0x50 +#define GPC_IMR1_CORE2_A53 0x1c0 +#define GPC_IMR1_CORE3_A53 0x1d0 +#define GPC_PGC_CPU_0_1_MAPPING 0xec +#define GPC_PGC_SCU_TIMMING 0x910 + +#define CPU_PGC_SW_PUP_TRG 0xf0 +#define CPU_PGC_SW_PDN_TRG 0xfc +#define BM_CPU_PGC_SW_PDN_PUP_REQ 0x1 + +#define PGC_PCR 0 + +#define LPCR_A53_BSC 0x0 +#define LPCR_A53_BSC2 0x108 +#define LPCR_M4 0x8 +#define SLPCR 0x14 +#define SLPCR_EN_DSM (1 << 31) +#define SLPCR_RBC_EN (1 << 30) +#define SLPCR_A53_FASTWUP_STOP (1 << 17) +#define SLPCR_A53_FASTWUP_WAIT (1 << 16) +#define SLPCR_VSTBY (1 << 2) +#define SLPCR_SBYOS (1 << 1) +#define SLPCR_BYPASS_PMIC_READY 0x1 +#define A53_LPM_WAIT 0x5 +#define A53_LPM_STOP 0xa +#define A53_CLK_ON_LPM (1 << 14) + +#define SRC_GPR1_OFFSET 0x74 + + +/* AD */ +#define LPCR_A53_AD 0x4 +#define L2PGE (1 << 31) +#define EN_L2_WFI_PDN (1 << 5) +#define EN_PLAT_PDN (1 << 4) + +#define PU_PGC_UP_TRG 0xf8 +#define PU_PGC_DN_TRG 0x104 +#define GPC_PU_PWRHSK 0x1fc + +/* SLOT */ +#define PGC_ACK_SEL_A53 0x24 +#define SLT0_CFG 0xb0 +#define SLT1_CFG 0xb4 +#define SLT2_CFG 0xb8 +#define SLT3_CFG 0xbc + +/* ack for slot pup/pdn */ +#define A53_DUMMY_PGC_PUP_ACK (1 << 31) +#define NOC_PGC_PUP_ACK (1 << 19) +#define PLAT_PGC_PUP_ACK (1 << 18) +#define A53_DUMMY_PGC_PDN_ACK (1 << 15) +#define NOC_PGC_PDN_ACK (1 << 3) +#define PLAT_PGC_PDN_ACK (1 << 2) + +/* pdn/pup bit define for slot control */ +#define NOC_PUP_SLT_CTRL (1 << 11) +#define NOC_PDN_SLT_CTRL (1 << 10) +#define PLAT_PUP_SLT_CTRL (1 << 9) +#define PLAT_PDN_SLT_CTRL (1 << 8) + +#define PLAT_PGC_PCR 0x900 +#define NOC_PGC_PCR 0xa40 + +#define MIPI_PGC 0xc00 +#define PCIE_PGC 0xc40 +#define OTG1_PGC 0xc80 +#define OTG2_PGC 0xcc0 +#define GPU2D_PGC 0xd80 +#define GPUMIX_PGC 0xdc0 +#define VPUMIX_PGC 0xe00 +#define GPU3D_PGC 0xe40 +#define DISPMIX_PGC 0xe80 +#define VPU_G1_PGC 0xec0 +#define VPU_G2_PGC 0xf00 +#define VPU_H1_PGC 0xf40 + +#define MIPI_PWR_REQ (1 << 0) +#define PCIE_PWR_REQ (1 << 1) +#define OTG1_PWR_REQ (1 << 2) +#define OTG2_PWR_REQ (1 << 3) +#define GPU2D_PWR_REQ (1 << 6) +#define GPUMIX_PWR_REQ (1 << 7) +#define VPUMIX_PWR_REQ (1 << 8) +#define GPU3D_PWR_REQ (1 << 9) +#define DISPMIX_PWR_REQ (1 << 10) +#define VPU_G1_PWR_REQ (1 << 11) +#define VPU_G2_PWR_REQ (1 << 12) +#define VPU_H1_PWR_REQ (1 << 13) + +#define DISPMIX_ADB400_SYNC (1 << 7) +#define VPUMIX_ADB400_SYNC (1 << 8) +#define GPU3D_ADB400_SYNC (1 << 9) +#define GPU2D_ADB400_SYNC (1 << 10) +#define GPUMIX_ADB400_SYNC (1 << 11) +#define DISPMIX_ADB400_ACK (1 << 25) +#define VPUMIX_ADB400_ACK (1 << 26) +#define GPU3D_ADB400_ACK (1 << 27) +#define GPU2D_ADB400_ACK (1 << 28) +#define GPUMIX_ADB400_ACK (1 << 29) + +#define MIPI_PGC 0xc00 +#define PCIE_PGC 0xc40 +#define OTG1_PGC 0xc80 +#define OTG2_PGC 0xcc0 +#define GPU2D_PGC 0xd80 +#define GPUMIX_PGC 0xdc0 +#define VPUMIX_PGC 0xe00 +#define GPU3D_PGC 0xe40 +#define DISPMIX_PGC 0xe80 +#define VPU_G1_PGC 0xec0 +#define VPU_G2_PGC 0xf00 +#define VPU_H1_PGC 0xf40 + +#define IMX_PD_DOMAIN(name) \ + { \ + .pwr_req = name##_PWR_REQ, \ + .pgc_offset = name##_PGC, \ + .need_sync = false, \ + .init_on = true, \ + } + +#define IMX_MIX_DOMAIN(name) \ + { \ + .pwr_req = name##_PWR_REQ, \ + .pgc_offset = name##_PGC, \ + .adb400_sync = name##_ADB400_SYNC, \ + .adb400_ack = name##_ADB400_ACK, \ + .need_sync = true, \ + .init_on = true, \ + } + +#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 LPM_MODE(local_state) (local_state == PLAT_WAIT_OFF_STATE ? A53_LPM_WAIT : A53_LPM_STOP) +#define A53_CORE_WUP_SRC(core_id) (1 << (core_id < 2 ? 28 + core_id : 22 + core_id - 2)) + +#define IMR_MASK_ALL 0xffffffff +#define IRQ_SRC_A53_WUP 30 + +struct imx_pwr_domain { + uint32_t pwr_req; + uint32_t adb400_sync; + uint32_t adb400_ack; + uint32_t pgc_offset; + bool need_sync; + bool init_on; +}; + +/* PU domain */ +static struct imx_pwr_domain pu_domains[] = { + IMX_PD_DOMAIN(MIPI), + IMX_PD_DOMAIN(PCIE), + IMX_PD_DOMAIN(OTG1), + IMX_PD_DOMAIN(OTG2), + IMX_MIX_DOMAIN(GPU2D), + IMX_MIX_DOMAIN(GPUMIX), + IMX_MIX_DOMAIN(VPUMIX), + IMX_MIX_DOMAIN(GPU3D), + IMX_MIX_DOMAIN(DISPMIX), + IMX_PD_DOMAIN(VPU_G1), + IMX_PD_DOMAIN(VPU_G2), +}; + +static uint32_t gpc_imr_offset[] = { 0x30, 0x40, 0x1c0, 0x1d0, }; +/* save gic dist&redist context when NOC wrapper is power down */ +static struct plat_gic_ctx imx_gicv3_ctx; + +void imx_set_cpu_secure_entry(int core_id, uint64_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(int core_id) +{ + uint32_t val; + + /* enable the wfi power down of the core */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + val |= COREx_WFI_PDN(core_id); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + + /* assert the pcg pcr bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id)); + val |= (1 << 0); + mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val); +}; + +/* use the sw method to power up the core */ +void imx_set_cpu_pwr_on(int core_id) +{ + uint32_t val; + + /* clear the wfi power down bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + val &= ~COREx_WFI_PDN(core_id); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + + /* assert the ncpuporeset */ + val = mmio_read_32(IMX_SRC_BASE + 0x8); + val &= ~(1 << core_id); + mmio_write_32(IMX_SRC_BASE + 0x8, val); + + /* assert the pcg pcr bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id)); + val |= (1 << 0); + mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val); + + /* sw power up the core */ + val = mmio_read_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG); + val |= (1 << core_id); + mmio_write_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG, val); + + /* wait for the power up finished */ + while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG) & (1 << core_id)) != 0) + ; + /* deassert the pcg pcr bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id)); + val &= ~(1 << 0); + mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val); + + /* deassert the ncpuporeset */ + val = mmio_read_32(IMX_SRC_BASE + 0x8); + val |= (1 << core_id); + mmio_write_32(IMX_SRC_BASE + 0x8, val); +} + +/* if out of lpm, we need to do reverse steps */ +void imx_set_cpu_lpm(int core_id, bool pdn) +{ + uint32_t val; + + if (pdn) { + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + /* enable the core WFI power down */ + val |= COREx_WFI_PDN(core_id); + /* enable the core IRQ wakeup */ + val |= COREx_IRQ_WUP(core_id); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + + /* assert the pcg pcr bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id)); + val |= (1 << 0); + mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val); + } else { + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + /* disable the core WFI power down */ + val &= ~COREx_WFI_PDN(core_id); + /* disable the core IRQ wakeup */ + val &= ~COREx_IRQ_WUP(core_id); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + /* deassert the pcg pcr bit of the core */ + val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id)); + val &= ~(1 << 0); + mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val); + } +} + +/* + * SLOT 0 is used for A53 PLAT poewr down, + * SLOT 1 is used for A53 NOC power down, + * SLOT 2 is used for A53 NOC power up, + * SLOT 3 is used for A53 PLAT power up, + * when enter LPM power down, NOC's ACK is used, + * when out of LPM, SCU's ACK is used + */ +void imx_a53_plat_slot_config(bool pdn) +{ + uint32_t pgc_pcr, slot_ack, pdn_slot_cfg, pup_slot_cfg; + + pdn_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT0_CFG); + pup_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT3_CFG); + pgc_pcr = mmio_read_32(IMX_GPC_BASE + PLAT_PGC_PCR); + + /* enable PLAT PGC PCR */ + pgc_pcr |= 0x1; + mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR, pgc_pcr); + + + if (pdn) { + /* config a53 plat pdn/pup slot */ + pdn_slot_cfg |= PLAT_PDN_SLT_CTRL; + pup_slot_cfg |= PLAT_PUP_SLT_CTRL; + /* config a53 plat pdn/pup ack */ + slot_ack = PLAT_PGC_PDN_ACK | PLAT_PGC_PUP_ACK; + /* enable PLAT PGC PCR */ + pgc_pcr |= 0x1; + + } else { + /* clear slot/ack config */ + pdn_slot_cfg &= ~PLAT_PDN_SLT_CTRL; + pup_slot_cfg &= ~PLAT_PUP_SLT_CTRL; + slot_ack = A53_DUMMY_PGC_PDN_ACK | A53_DUMMY_PGC_PUP_ACK; + /* enable PLAT PGC PCR */ + pgc_pcr &= ~0x1; + } + + mmio_write_32(IMX_GPC_BASE + SLT0_CFG, pdn_slot_cfg); + mmio_write_32(IMX_GPC_BASE + SLT3_CFG, pup_slot_cfg); + mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, slot_ack); + mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR, pgc_pcr); +} + +void imx_noc_slot_config(bool pdn) +{ + uint32_t pgc_pcr, slot_ack, pdn_slot_cfg, pup_slot_cfg; + + pdn_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT1_CFG); + pup_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT2_CFG); + slot_ack = mmio_read_32(IMX_GPC_BASE + PGC_ACK_SEL_A53); + pgc_pcr = mmio_read_32(IMX_GPC_BASE + NOC_PGC_PCR); + + if (pdn) { + pdn_slot_cfg |= NOC_PDN_SLT_CTRL; + pup_slot_cfg |= NOC_PUP_SLT_CTRL; + + /* clear a53's PDN ack, use NOC's PDN ack */ + slot_ack &= ~0xffff; + slot_ack |= NOC_PGC_PDN_ACK; + /* enable NOC PGC PCR */ + pgc_pcr |= 0x1; + } else { + pdn_slot_cfg &= ~NOC_PDN_SLT_CTRL; + pup_slot_cfg &= ~NOC_PUP_SLT_CTRL; + slot_ack = A53_DUMMY_PGC_PUP_ACK | A53_DUMMY_PGC_PDN_ACK; + /* disable NOC PGC PCR */ + pgc_pcr&= ~0x1; + } + + mmio_write_32(IMX_GPC_BASE + SLT1_CFG, pdn_slot_cfg); + mmio_write_32(IMX_GPC_BASE + SLT2_CFG, pup_slot_cfg); + mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, slot_ack); + mmio_write_32(IMX_GPC_BASE + NOC_PGC_PCR, pgc_pcr); +} + +/* TODO for cpu clock gate off wait mode */ +void imx_set_cluster_standby(bool enter) +{ + +} + +/* set the BSC and BSC2 LPM bit, and other bit in AD */ +void imx_set_cluster_powerdown(int last_core, uint8_t power_state) +{ + uint32_t val; + + if (is_local_state_off(power_state)) { + + /* config A53 cluster LPM mode */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + val |= LPM_MODE(power_state); /* enable the C0~1 LPM */ + val &= ~A53_CLK_ON_LPM; + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* enable C2-3's LPM */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC2); + val |= LPM_MODE(power_state); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC2, val); + + /* 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); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + + /* config SLOT for PLAT power up/down */ + imx_a53_plat_slot_config(true); + } else { + /* clear the slot and ack for cluster power down */ + imx_a53_plat_slot_config(false); + + /* reverse the cluster level setting */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + val &= ~0xf; /* clear the C0~1 LPM */ + val |= A53_CLK_ON_LPM; + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC2); + val &= ~0xf; + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC2, val); + + /* 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); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + } +} + +/* only handle the SLPCR and DDR retention */ +/* config the PLLs override setting */ +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); + /* TODO DDR retention */ + } else { + /* TODO DDR retention */ + } + mmio_write_32(IMX_GPC_BASE + SLPCR, val); +} + +void imx_set_rbc_count(void) +{ + uint32_t val; + + val = mmio_read_32(IMX_GPC_BASE + SLPCR); + val |= (0x3f << 24); + mmio_write_32(IMX_GPC_BASE + SLPCR, val); +} + +void imx_clear_rbc_count(void) +{ + uint32_t val; + + val = mmio_read_32(IMX_GPC_BASE + SLPCR); + val &= ~(0x3f << 24); + mmio_write_32(IMX_GPC_BASE + SLPCR, val); + +} +void imx_anamix_pre_suspend() +{ + /* TODO */ +} + +void imx_anamix_post_resume(void) +{ + /* TODO */ +} + +void noc_wrapper_pre_suspend(unsigned int proc_num) +{ + /* FIXME enable NOC power down on real silicon */ +#if 0 + imx_noc_slot_config(true); +#endif + /* + * gic redistributor context save must be called when + * the GIC CPU interface is disabled and before distributor save. + */ + plat_gic_save(proc_num, &imx_gicv3_ctx); +} + +void noc_wrapper_post_resume(unsigned int proc_num) +{ + /* FIXME enable NOC power down on real silicon */ +#if 0 + imx_noc_slot_config(false); +#endif + /* restore gic context */ + plat_gic_restore(proc_num, &imx_gicv3_ctx); +} + +/* use external IRQ wakeup source for LPM if NOC power down */ +void imx_set_sys_wakeup(int last_core, bool pdn) +{ + uint32_t irq_mask, val; + gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; + + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + if (pdn) { + /* select the external IRQ as the LPM wakeup source */ + val |= (1 << IRQ_SRC_A53_WUP); + /* select the external IRQ as last core's wakeup source */ + val &= ~A53_CORE_WUP_SRC(last_core); + } else { + val &= ~(1 << IRQ_SRC_A53_WUP); + val |= A53_CORE_WUP_SRC(last_core); + } + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* clear last core's IMR based on GIC's mask setting */ + for (int i = 0; i < 4; i++) { + if (pdn) + irq_mask = ~dist_ctx->gicd_isenabler[i]; + else + irq_mask = IMR_MASK_ALL; + + mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4, + irq_mask); + } +} + +static void imx_gpc_pm_domain_enable(uint32_t domain_id, uint32_t on) +{ + uint32_t val; + + struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id]; + + /* FIXME, will remove after runtime PM is ok */ + return; + + if (on) { + /* clear the PGC bit */ + val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset); + val &= ~(1 << 0); + mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val); + + /* power up the domain */ + val = mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG); + val |= pwr_domain->pwr_req; + mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, val); + + /* handle the ADB400 sync */ + if (!pwr_domain->init_on && pwr_domain->need_sync) { + /* clear adb power down request */ + val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK); + val |= pwr_domain->adb400_sync; + mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val); + + /* wait for adb power request ack */ + while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) + ; + } + + /* special fixup for dispmix */ + if (pwr_domain->pwr_req == DISPMIX_PWR_REQ) { + mmio_write_32(0x303845d0, 0x3); + mmio_write_32(0x32e28000, 0x7f); + mmio_write_32(0x32e28004, 0x1fff); + mmio_write_32(0x32e28008, 0x30000); + } + } else { + /* TODO for bringup purpose */ + return; + /* set the PGC bit */ + val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset); + val |= (1 << 0); + mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val); + + /* handle the ADB400 sync */ + if (!pwr_domain->init_on && pwr_domain->need_sync) { + /* set adb power down request */ + val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK); + val &= ~(pwr_domain->adb400_sync); + mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val); + + /* wait for adb power request ack */ + while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) + ; + } + + /* power down the domain */ + val = mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG); + val |= pwr_domain->pwr_req; + mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, val); + } + + pwr_domain->init_on = false; +} + +void imx_gpc_init(void) +{ + unsigned int val; + int i; + + /* mask all the wakeup irq 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); + mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_M4 + i * 4, ~0x0); + } + + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + /* use GIC wake_request to wakeup C0~C3 from LPM */ + val |= 0x30c00000; + /* clear the MASTER0 LPM handshake */ + val &= ~(1 << 6); + val &= ~(1 << 7); + val &= ~(1 << 8); + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* mask M4 DSM trigger if M4 is NOT enabled */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_M4); + val |= 1 << 31; + mmio_write_32(IMX_GPC_BASE + LPCR_M4, val); + + /*set all mix/PU in A53 domain */ + mmio_write_32(IMX_GPC_BASE + GPC_PGC_CPU_0_1_MAPPING, 0xffff); + + /* TODO release dispmix sft reset */ + /* enable all the PU for bringup up purpose */ + mmio_write_32(IMX_GPC_BASE + 0xf8, 0x3fcf); + mmio_write_32(0x303845d0, 0x3); + mmio_write_32(0x32e28000, 0x7f); + mmio_write_32(0x32e28004, 0x1fff); + mmio_write_32(0x32e28008, 0x30000); + + /* set SCU timming */ + mmio_write_32(IMX_GPC_BASE + GPC_PGC_SCU_TIMMING, + (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_PGC_PUP_ACK | A53_DUMMY_PGC_PDN_ACK); + /* clear DSM by default */ + val = mmio_read_32(IMX_GPC_BASE + SLPCR); + val &= ~SLPCR_EN_DSM; + /* enable the fast wakeup wait mode */ + val |= SLPCR_A53_FASTWUP_WAIT; + /* TODO if M4 is not enabled, clear more SLPCR bits */ + mmio_write_32(IMX_GPC_BASE + SLPCR, val); + + /* + * 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. + */ + val = mmio_read_32(0x30390020); + val &= ~0x1; + mmio_write_32(0x30390020, val); + val = mmio_read_32(0x30390024); + val &= ~0x1; + mmio_write_32(0x30390024, 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_PM_DOMAIN: + imx_gpc_pm_domain_enable(x2, x3); + break; + default: + return SMC_UNK; + } + + return 0; +} diff --git a/plat/imx/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8mm/imx8mm_bl31_setup.c new file mode 100644 index 00000000..310832ff --- /dev/null +++ b/plat/imx/imx8mm/imx8mm_bl31_setup.c @@ -0,0 +1,230 @@ +/* + * Copyright 2017 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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) + +#define GPR_TZASC_EN (1 << 0) +#define GPR_TZASC_EN_LOCK (1 << 16) + +#if 1 +void bl31_tzc380_setup(void) +{ + unsigned int val; + + val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x28); + if ((val & GPR_TZASC_EN) != GPR_TZASC_EN) + return; + + NOTICE("Configureing TZASC380\n"); + + 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); + + tzc380_dump_state(); +} + +static void imx8mm_aips_config(void) +{ + /* 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 AIPSTZ2 */ + mmio_write_32(0x305f0000, 0x77777777); + mmio_write_32(0x305f0004, 0x77777777); + mmio_write_32(0x305f0040, 0x0); + mmio_write_32(0x305f0044, 0x0); + mmio_write_32(0x305f0048, 0x0); + mmio_write_32(0x305f004c, 0x0); + mmio_write_32(0x305f0050, 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); + + /* config the AIPSTZ4 */ + mmio_write_32(0x32df0000, 0x77777777); + mmio_write_32(0x32df0004, 0x77777777); + mmio_write_32(0x32df0040, 0x0); + mmio_write_32(0x32df0044, 0x0); + mmio_write_32(0x32df0048, 0x0); + mmio_write_32(0x32df004c, 0x0); + mmio_write_32(0x32df0050, 0x0); +} +#endif + +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(0x303e0000 + i * 4, 0xffffffff); + } + + /* config the aips access permission */ + imx8mm_aips_config(); + +#if DEBUG_CONSOLE + console_init(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, + IMX_CONSOLE_BAUDRATE); +#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); + +#ifdef TEE_IMX8 + /* Populate entry point information for BL32 */ + SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = 0; + /* Pass TEE base and size to uboot */ + bl33_image_ep_info.args.arg1 = 0xFE000000; + bl33_image_ep_info.args.arg2 = 0x2000000; +#endif + bl31_tzc380_setup(); +} + +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); + /* Map GPV */ + mmap_add_region(IMX_GPV_BASE, IMX_GPV_BASE, IMX_GPV_SIZE, MT_DEVICE | MT_RW); + /* Map AIPS 1~3 */ + mmap_add_region(IMX_AIPS_BASE, IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW); + /* map AIPS4 */ + mmap_add_region(0x32c00000, 0x32c00000, 0x400000, MT_DEVICE | MT_RW); + /* map GIC */ + mmap_add_region(PLAT_GIC_BASE, PLAT_GIC_BASE, 0x100000, 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) +{ + /* enable the GIC clock */ + mmio_write_32(0x303845c0, 0x3); + /* 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/imx8mm/imx8mm_psci.c b/plat/imx/imx8mm/imx8mm_psci.c new file mode 100644 index 00000000..f4521e64 --- /dev/null +++ b/plat/imx/imx8mm/imx8mm_psci.c @@ -0,0 +1,253 @@ +/* + * Copyright 2018 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SNVS_LPCR 0x38 + +#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]) + +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, +}; + +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 < 0x40000000) + 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_WAIT_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() | 0x4); + isb(); + + wfi(); + + 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; + 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(); + /* set the resume entry */ + imx_set_cpu_secure_entry(core_id, base_addr); + imx_set_cpu_lpm(core_id, true); + } else { + /* TODO cluster level clock gate off ? */ + dsb(); + write_scr_el3(read_scr_el3() | 0x4); + isb(); + } + + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { + imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state)); + } else + imx_set_cluster_standby(true); + + /* do system level power mode setting */ + if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { + imx_set_sys_lpm(true); + imx_anamix_pre_suspend(); + noc_wrapper_pre_suspend(core_id); + /* set the wakeup source based on GIC SPI config */ + imx_set_sys_wakeup(core_id, 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); + /* clear the system wakeup setting */ + imx_set_sys_wakeup(core_id, false); + imx_anamix_post_resume(); + noc_wrapper_post_resume(core_id); + 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, PSCI_LOCAL_STATE_RUN); + } 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) | (7 << 2) | (1 << 0); +#else + val = (val & 0x00FF) | (4 << 2) | (1 << 0); +#endif + mmio_write_16(wdog_base, val); + + mmio_write_16(wdog_base + 0x2, 0x5555); + mmio_write_16(wdog_base + 0x2, 0xaaaa); + while (1) + ; +} + +void __dead2 imx_system_off(void) +{ + mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, 0x61); + + tf_printf("Unable to poweroff system\n"); + + 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(); + + /* TODO need to workaround the PLL disable glitch */ + } + + 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) +{ + /* sec_entrypoint is used for warm reset */ + imx_mailbox_init(sec_entrypoint); + + *psci_ops = &imx_plat_psci_ops; + + return 0; +} diff --git a/plat/imx/imx8mm/include/platform_def.h b/plat/imx/imx8mm/include/platform_def.h new file mode 100644 index 00000000..23ea26e5 --- /dev/null +++ b/plat/imx/imx8mm/include/platform_def.h @@ -0,0 +1,85 @@ +#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_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 4 +#define PLAT_MAX_RET_STATE 1 + +#define PLAT_WAIT_OFF_STATE 2 +#define PLAT_STOP_OFF_STATE 3 + +#define BL31_BASE 0x910000 +#define BL31_LIMIT 0x920000 +#define BL32_BASE 0xfe000000 + +/* non-secure uboot base */ +#define PLAT_NS_IMAGE_OFFSET 0x40200000 + +/* GICv3 base address */ +#define PLAT_GIC_BASE 0x38800000 +#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 12 + +#define HAB_RVT_BASE 0x00000900 /* HAB_RVT for i.MX8MM */ + +#define IMX_BOOT_UART_BASE 0x30890000 +#define IMX_BOOT_UART_CLK_IN_HZ 24000000 /* Select 24Mhz OSC */ + +#define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE +#define PLAT_CRASH_UART_CLK_IN_HZ 24000000 +#define IMX_CONSOLE_BAUDRATE 115200 + +#define IMX_AIPSTZ1 0x301f0000 +#define IMX_AIPSTZ2 0x305f0000 +#define IMX_AIPSTZ3 0x309f0000 +#define IMX_AIPSTZ4 0x32df0000 + +#define IMX_AIPS_BASE 0x30000000 +#define IMX_AIPS_SIZE 0xC00000 +#define IMX_GPV_BASE 0x32000000 +#define IMX_GPV_SIZE 0x800000 +#define IMX_AIPS1_BASE 0x30200000 +#define IMX_AIPS4_BASE 0x32c00000 +#define IMX_ANAMIX_BASE 0x30360000 +#define IMX_SRC_BASE 0x30390000 +#define IMX_GPC_BASE 0x303a0000 +#define IMX_WDOG_BASE 0x30280000 +#define IMX_SNVS_BASE 0x30370000 +#define IMX_NOC_BASE 0x32700000 +#define IMX_TZASC_BASE 0x32F80000 +#define IMX_IOMUX_GPR_BASE 0x30340000 +#define IMX_DDRC_BASE 0x3d400000 +#define IMX_DDRPHY_BASE 0x3c000000 +#define IMX_DDR_IPS_BASE 0x3d000000 +#define IMX_ROM_BASE 0x0 + +#define OCRAM_S_BASE 0x00180000 +#define OCRAM_S_SIZE 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_IMX8MM 1 diff --git a/plat/imx/imx8mm/include/soc.h b/plat/imx/imx8mm/include/soc.h new file mode 100644 index 00000000..475b0bc8 --- /dev/null +++ b/plat/imx/imx8mm/include/soc.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __IMX_SOC_H +#define __IMX_SOC_H + +void imx_gpc_set_m_core_pgc(unsigned int cpu, bool pdn); +void imx_anamix_pre_suspend(void); +void imx_anamix_post_resume(void); +void imx_gpc_init(void); + +void imx_set_cpu_secure_entry(int cpu_id, uintptr_t sec_entrypoint); +void imx_set_cpu_pwr_off(int cpu_id); +void imx_set_cpu_pwr_on(int cpu_id); +void imx_set_cpu_lpm(int cpu_id, bool pdn); +void imx_set_lpm_wakeup(bool pdn); +void imx_set_cluster_standby(bool pdn); +void imx_set_cluster_powerdown(int last_core, uint8_t power_state); +void imx_set_sys_lpm(bool retention); +void imx_set_sys_wakeup(int last_core, bool pdn); +void imx_set_rbc_count(void); +void imx_clear_rbc_count(void); + +void noc_wrapper_pre_suspend(unsigned int proc_num); +void noc_wrapper_post_resume(unsigned int proc_num); + +void ddrc_enter_retention(void); +void ddrc_exit_retention(void); + +#endif /* __IMX_SOC_H */ diff --git a/plat/imx/imx8mm/misc.c b/plat/imx/imx8mm/misc.c new file mode 100644 index 00000000..9c2c0ace --- /dev/null +++ b/plat/imx/imx8mm/misc.c @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define M4RCR (0xC) +#define SRC_SCR_M4_ENABLE_OFFSET 3 +#define SRC_SCR_M4_ENABLE_MASK (1 << 3) +#define SRC_SCR_M4C_NON_SCLR_RST_OFFSET 0 +#define SRC_SCR_M4C_NON_SCLR_RST_MASK (1 << 0) + +#define DIGPROG 0x800 + +int imx_src_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, + u_register_t x3) +{ + uint32_t val; + + switch(x1) { + case FSL_SIP_SRC_M4_START: + val = mmio_read_32(IMX_SRC_BASE + M4RCR); + val &= ~SRC_SCR_M4C_NON_SCLR_RST_MASK; + val |= SRC_SCR_M4_ENABLE_MASK; + mmio_write_32(IMX_SRC_BASE + M4RCR, val); + break; + case FSL_SIP_SRC_M4_STARTED: + val = mmio_read_32(IMX_SRC_BASE + M4RCR); + return !(val & SRC_SCR_M4C_NON_SCLR_RST_MASK); + default: + return SMC_UNK; + + }; + + return 0; +} + +int imx_soc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, + u_register_t x3) +{ + return mmio_read_32(IMX_ANAMIX_BASE + DIGPROG); +} + +int imx_noc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, + u_register_t x3) +{ + return 0; +} diff --git a/plat/imx/imx8mm/platform.mk b/plat/imx/imx8mm/platform.mk new file mode 100644 index 00000000..70439c44 --- /dev/null +++ b/plat/imx/imx8mm/platform.mk @@ -0,0 +1,41 @@ +PLAT_INCLUDES := -Iplat/imx/imx8mm/include \ + -Iplat/imx/common/include \ + +PLAT_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/imx/common/plat_imx8_gic.c + +BL31_SOURCES += plat/imx/common/imx8_helpers.S \ + plat/imx/common/mxcuart_console.S \ + plat/imx/common/sip_svc.c \ + plat/imx/imx8mm/imx8mm_bl31_setup.c \ + plat/imx/imx8mm/gpc.c \ + plat/imx/imx8mm/misc.c \ + plat/imx/common/imx8m/hab.c \ + plat/imx/imx8mm/imx8mm_psci.c \ + plat/imx/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} \ + ${PLAT_DDR_SOURCES} \ + drivers/arm/tzc/tzc380.c + +ENABLE_PLAT_COMPAT := 0 +USE_COHERENT_MEM := 0 +MULTI_CONSOLE_API := 1 +RESET_TO_BL31 := 1 +ERROR_DEPRECATED := 1 +#XLAT_TABLE_IN_OCRAM_S := 1 +#STACK_IN_OCRAM_S := 1 +ifneq (${SPD},none) +$(eval $(call add_define,TEE_IMX8)) +endif +#$(eval $(call add_define,XLAT_TABLE_IN_OCRAM_S)) +#$(eval $(call add_define,STACK_IN_OCRAM_S)) -- cgit v1.2.3