summaryrefslogtreecommitdiff
path: root/plat/imx/imx8mm/gpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'plat/imx/imx8mm/gpc.c')
-rw-r--r--plat/imx/imx8mm/gpc.c677
1 files changed, 677 insertions, 0 deletions
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 <debug.h>
+#include <gicv3.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <smcc_helpers.h>
+#include <std_svc.h>
+#include <types.h>
+#include <mmio.h>
+#include <plat_imx8.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <fsl_sip.h>
+#include <soc.h>
+
+#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;
+}