]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
feat(plat/mediatek/mt8186): add CPU hotplug
authorGarmin.Chang <Garmin.Chang@mediatek.com>
Mon, 8 Nov 2021 03:30:40 +0000 (11:30 +0800)
committerRex-BC Chen <rex-bc.chen@mediatek.corp-partner.google.com>
Wed, 22 Dec 2021 10:06:53 +0000 (18:06 +0800)
Implement PSCI platform operations to support CPU hotplug and MCDI.

TEST=bringup 8 CPUs successfully on kernel stage.
BUG=b:202871018

Change-Id: Ibd5423b70b3ca3f91edaa48d7ca5bc094e751510
Signed-off-by: Garmin.Chang <Garmin.Chang@mediatek.com>
plat/mediatek/mt8186/drivers/spmc/mtspmc.c [new file with mode: 0644]
plat/mediatek/mt8186/drivers/spmc/mtspmc.h [new file with mode: 0644]
plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h [new file with mode: 0644]
plat/mediatek/mt8186/include/mcucfg.h [new file with mode: 0644]
plat/mediatek/mt8186/include/plat_mtk_lpm.h [new file with mode: 0644]
plat/mediatek/mt8186/include/plat_pm.h [new file with mode: 0644]
plat/mediatek/mt8186/include/platform_def.h
plat/mediatek/mt8186/plat_pm.c
plat/mediatek/mt8186/platform.mk

diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.c b/plat/mediatek/mt8186/drivers/spmc/mtspmc.c
new file mode 100644 (file)
index 0000000..91ef096
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mtspmc.h>
+#include <mtspmc_private.h>
+#include <plat/common/platform.h>
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+       mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+       mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+       /* Clear cpu's cpc sw hint */
+       mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr)
+{
+       assert(cluster == 0U);
+
+       mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu)
+{
+       assert(cluster == 0U);
+
+       return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64)
+{
+       uint32_t reg;
+
+       assert(cluster == 0U);
+
+       reg = per_cluster(cluster, MCUCFG_INITARCH);
+
+       if (arm64) {
+               mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+       } else {
+               mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+       }
+}
+
+/*
+ * Return subsystem's power state.
+ *
+ * @mask: mask to SPM_CPU_PWR_STATUS to query the power state
+ *        of one subsystem.
+ * RETURNS:
+ * 0 (the subsys was powered off)
+ * 1 (the subsys was powered on)
+ */
+bool spm_get_powerstate(uint32_t mask)
+{
+       return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask);
+}
+
+bool spm_get_cluster_powerstate(unsigned int cluster)
+{
+       assert(cluster == 0U);
+
+       return spm_get_powerstate(MP0_CPUTOP);
+}
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu)
+{
+       uint32_t mask = BIT(cpu);
+
+       assert(cluster == 0U);
+
+       return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+       unsigned int cpu = plat_my_core_pos();
+
+
+       INFO("SPM: enable CPC mode\n");
+
+       mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
+
+       mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
+       mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
+
+       mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+       mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+       mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
+
+       mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+
+       /* Clear bootup cpu's cpc sw hint */
+       mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+
+       return 0;
+}
+
+/*
+ * Power on a core with specified cluster and core index
+ *
+ * @cluster: the cluster ID of the CPU which to be powered on
+ * @cpu: the CPU ID of the CPU which to be powered on
+ */
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu)
+{
+       /* info CPC that CPU hotplug on */
+       mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+
+       /* Set mp0_spmc_pwr_on_cpuX = 1 */
+       mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+
+       /* wait for power on ack */
+       while (!spm_get_cpu_powerstate(cluster, cpu))
+               ;
+
+       /* info CPC that CPU hotplug off */
+       mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+}
+
+/*
+ * Power off a core with specified cluster and core index
+ *
+ * @cluster: the cluster ID of the CPU which to be powered off
+ * @cpu: the CPU ID of the CPU which to be powered off
+ */
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu)
+{
+       /* Set mp0_spmc_pwr_on_cpuX = 0 */
+       mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+}
+
+/*
+ * Power off a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered off
+ */
+void spm_poweroff_cluster(unsigned int cluster)
+{
+       /* No need to power on/off cluster on single cluster platform */
+       assert(false);
+}
+
+/*
+ * Power on a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered on
+ */
+void spm_poweron_cluster(unsigned int cluster)
+{
+       /* No need to power on/off cluster on single cluster platform */
+       assert(false);
+}
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc.h
new file mode 100644 (file)
index 0000000..768599b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_H
+#define MTSPMC_H
+
+#include <stdint.h>
+
+int spmc_init(void);
+
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu);
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu);
+
+void spm_poweroff_cluster(unsigned int cluster);
+void spm_poweron_cluster(unsigned int cluster);
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu);
+bool spm_get_cluster_powerstate(unsigned int cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64);
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu);
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h
new file mode 100644 (file)
index 0000000..472b54c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_PRIVATE_H
+#define MTSPMC_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+unsigned long read_cpuectlr(void);
+void write_cpuectlr(unsigned long cpuectlr);
+
+unsigned long read_cpupwrctlr_el1(void);
+void write_cpupwrctlr_el1(unsigned long cpuectlr);
+
+/* per_cpu/cluster helper */
+struct per_cpu_reg {
+       unsigned int cluster_addr;
+       unsigned int cpu_stride;
+};
+
+#define per_cpu(cluster, cpu, reg)     \
+       (reg[cluster].cluster_addr + (cpu << reg[cluster].cpu_stride))
+
+#define per_cluster(cluster, reg)      (reg[cluster].cluster_addr)
+
+#define SPM_REG(ofs)                   (uint32_t)(SPM_BASE + (ofs))
+#define MCUCFG_REG(ofs)                        (uint32_t)(MCUCFG_BASE + (ofs))
+#define INFRACFG_AO_REG(ofs)           (uint32_t)(INFRACFG_AO_BASE + (ofs))
+
+/* SPMC related registers */
+#define SPM_POWERON_CONFIG_EN          SPM_REG(0x000)
+/* bit-fields of SPM_POWERON_CONFIG_EN */
+#define PROJECT_CODE                   (U(0xb16) << 16)
+#define BCLK_CG_EN                     BIT(0)
+
+#define SPM_PWR_STATUS                 SPM_REG(0x16c)
+#define SPM_PWR_STATUS_2ND             SPM_REG(0x170)
+#define SPM_CPU_PWR_STATUS             SPM_REG(0x174)
+
+/* bit-fields of SPM_PWR_STATUS */
+#define MD                             BIT(0)
+#define CONN                           BIT(1)
+#define DDRPHY                         BIT(2)
+#define DISP                           BIT(3)
+#define MFG                            BIT(4)
+#define ISP                            BIT(5)
+#define INFRA                          BIT(6)
+#define VDEC                           BIT(7)
+#define MP0_CPUTOP                     BIT(8)
+#define MP0_CPU0                       BIT(9)
+#define MP0_CPU1                       BIT(10)
+#define MP0_CPU2                       BIT(11)
+#define MP0_CPU3                       BIT(12)
+#define MCUSYS                         BIT(14)
+#define MP0_CPU4                       BIT(15)
+#define MP0_CPU5                       BIT(16)
+#define MP0_CPU6                       BIT(17)
+#define MP0_CPU7                       BIT(18)
+#define VEN                            BIT(21)
+
+/* SPMC related registers */
+#define SPM_MCUSYS_PWR_CON             SPM_REG(0x200)
+#define SPM_MP0_CPUTOP_PWR_CON         SPM_REG(0x204)
+#define SPM_MP0_CPU0_PWR_CON           SPM_REG(0x208)
+#define SPM_MP0_CPU1_PWR_CON           SPM_REG(0x20c)
+#define SPM_MP0_CPU2_PWR_CON           SPM_REG(0x210)
+#define SPM_MP0_CPU3_PWR_CON           SPM_REG(0x214)
+#define SPM_MP0_CPU4_PWR_CON           SPM_REG(0x218)
+#define SPM_MP0_CPU5_PWR_CON           SPM_REG(0x21c)
+#define SPM_MP0_CPU6_PWR_CON           SPM_REG(0x220)
+#define SPM_MP0_CPU7_PWR_CON           SPM_REG(0x224)
+
+/* bit-fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK                     BIT(31)
+#define VPROC_EXT_OFF                  BIT(7)
+#define DORMANT_EN                     BIT(6)
+#define RESETPWRON_CONFIG              BIT(5)
+#define PWR_CLK_DIS                    BIT(4)
+#define PWR_ON                         BIT(2)
+#define PWR_RST_B                      BIT(0)
+
+/* per_cpu registers for SPM_MP0_CPU_PWR_CON */
+static const struct per_cpu_reg SPM_CPU_PWR[] = {
+       { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U }
+};
+
+/* per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */
+static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
+       { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U }
+};
+
+/* MCUCFG related registers */
+#define MCUCFG_MP0_CLUSTER_CFG5                MCUCFG_REG(0xc8e4)
+/* reset vectors */
+#define MCUCFG_MP0_CLUSTER_CFG8                MCUCFG_REG(0xc900)
+#define MCUCFG_MP0_CLUSTER_CFG10       MCUCFG_REG(0xc908)
+#define MCUCFG_MP0_CLUSTER_CFG12       MCUCFG_REG(0xc910)
+#define MCUCFG_MP0_CLUSTER_CFG14       MCUCFG_REG(0xc918)
+#define MCUCFG_MP0_CLUSTER_CFG16       MCUCFG_REG(0xc920)
+#define MCUCFG_MP0_CLUSTER_CFG18       MCUCFG_REG(0xc928)
+#define MCUCFG_MP0_CLUSTER_CFG20       MCUCFG_REG(0xc930)
+#define MCUCFG_MP0_CLUSTER_CFG22       MCUCFG_REG(0xc938)
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG */
+static const struct per_cpu_reg MCUCFG_BOOTADDR[] = {
+       { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U }
+};
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */
+static const struct per_cpu_reg MCUCFG_INITARCH[] = {
+       { .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U }
+};
+
+#define MCUCFG_INITARCH_CPU_BIT(cpu)   BIT(16U + cpu)
+/* CPC control */
+#define MCUCFG_CPC_FLOW_CTRL_CFG       MCUCFG_REG(0xa814)
+#define MCUCFG_CPC_SPMC_PWR_STATUS     MCUCFG_REG(0xa840)
+
+/* bit-fields of CPC_FLOW_CTRL_CFG */
+#define CPC_CTRL_ENABLE                        BIT(16)
+#define SSPM_ALL_PWR_CTRL_EN           BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu)         BIT(21 + cpu)
+
+/* bit-fields of CPC_SPMC_PWR_STATUS */
+#define CORE_SPMC_PWR_ON_ACK           GENMASK(11, 0)
+
+/* APB module infracfg_ao */
+#define INFRA_TOPAXI_PROTECTEN         INFRACFG_AO_REG(0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0    INFRACFG_AO_REG(0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1    INFRACFG_AO_REG(0x0228)
+#define INFRA_TOPAXI_PROTECTEN_SET     INFRACFG_AO_REG(0x02a0)
+#define INFRA_TOPAXI_PROTECTEN_CLR     INFRACFG_AO_REG(0x02a4)
+#define INFRA_TOPAXI_PROTECTEN_1       INFRACFG_AO_REG(0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1  INFRACFG_AO_REG(0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1  INFRACFG_AO_REG(0x0258)
+#define INFRA_TOPAXI_PROTECTEN_1_SET   INFRACFG_AO_REG(0x02a8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR   INFRACFG_AO_REG(0x02ac)
+
+/* bit-fields of INFRA_TOPAXI_PROTECTEN */
+#define MP0_SPMC_PROT_STEP1_0_MASK     BIT(12)
+#define MP0_SPMC_PROT_STEP1_1_MASK     (BIT(26) | BIT(12))
+
+/* SPARK */
+#define VOLTAGE_04                     U(0x40)
+#define VOLTAGE_05                     U(0x60)
+
+#define PTP3_CPU0_SPMC_SW_CFG          MCUCFG_REG(0x200)
+#define CPU0_ILDO_CONTROL5             MCUCFG_REG(0x334)
+#define CPU0_ILDO_CONTROL8             MCUCFG_REG(0x340)
+
+/* bit-fields of CPU0_ILDO_CONTROL5 */
+#define ILDO_RET_VOSEL                 GENMASK(7, 0)
+
+/* bit-fields of PTP3_CPU_SPMC_SW_CFG */
+#define SW_SPARK_EN                    BIT(0)
+
+/* bit-fields of CPU0_ILDO_CONTROL8 */
+#define ILDO_BYPASS_B                  BIT(0)
+
+static const struct per_cpu_reg MCUCFG_SPARK[] = {
+       { .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL5[] = {
+       { .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL8[] = {
+       { .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U }
+};
+
+#endif /* MTSPMC_PRIVATE_H */
diff --git a/plat/mediatek/mt8186/include/mcucfg.h b/plat/mediatek/mt8186/include/mcucfg.h
new file mode 100644 (file)
index 0000000..78a01a8
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER__ */
+
+#include <platform_def.h>
+
+#define MCUCFG_REG(ofs)                        (uint32_t)(MCUCFG_BASE + (ofs))
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8))
+
+#define MP2_CPUCFG                     MCUCFG_REG(0x2208)
+
+#define MP2_CPU0_STANDBYWFE            BIT(4)
+#define MP2_CPU1_STANDBYWFE            BIT(5)
+
+#define MP0_CPUTOP_SPMC_CTL            MCUCFG_REG(0x788)
+#define MP1_CPUTOP_SPMC_CTL            MCUCFG_REG(0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL       MCUCFG_REG(0x790)
+
+#define sw_spark_en                    BIT(0)
+#define sw_no_wait_for_q_channel       BIT(1)
+#define sw_fsm_override                        BIT(2)
+#define sw_logic_pre1_pdb              BIT(3)
+#define sw_logic_pre2_pdb              BIT(4)
+#define sw_logic_pdb                   BIT(5)
+#define sw_iso                         BIT(6)
+#define sw_sram_sleepb                 (U(0x3F) << 7)
+#define sw_sram_isointb                        BIT(13)
+#define sw_clk_dis                     BIT(14)
+#define sw_ckiso                       BIT(15)
+#define sw_pd                          (U(0x3F) << 16)
+#define sw_hot_plug_reset              BIT(22)
+#define sw_pwr_on_override_en          BIT(23)
+#define sw_pwr_on                      BIT(24)
+#define sw_coq_dis                     BIT(25)
+#define logic_pdbo_all_off_ack         BIT(26)
+#define logic_pdbo_all_on_ack          BIT(27)
+#define logic_pre2_pdbo_all_on_ack     BIT(28)
+#define logic_pre1_pdbo_all_on_ack     BIT(29)
+
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \
+       (MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL          MCUCFG_REG(0x1c30)
+#define CPUSYS0_CPU1_SPMC_CTL          MCUCFG_REG(0x1c34)
+#define CPUSYS0_CPU2_SPMC_CTL          MCUCFG_REG(0x1c38)
+#define CPUSYS0_CPU3_SPMC_CTL          MCUCFG_REG(0x1c3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL          MCUCFG_REG(0x3c30)
+#define CPUSYS1_CPU1_SPMC_CTL          MCUCFG_REG(0x3c34)
+#define CPUSYS1_CPU2_SPMC_CTL          MCUCFG_REG(0x3c38)
+#define CPUSYS1_CPU3_SPMC_CTL          MCUCFG_REG(0x3c3C)
+
+#define cpu_sw_spark_en                        BIT(0)
+#define cpu_sw_no_wait_for_q_channel   BIT(1)
+#define cpu_sw_fsm_override            BIT(2)
+#define cpu_sw_logic_pre1_pdb          BIT(3)
+#define cpu_sw_logic_pre2_pdb          BIT(4)
+#define cpu_sw_logic_pdb               BIT(5)
+#define cpu_sw_iso                     BIT(6)
+#define cpu_sw_sram_sleepb             BIT(7)
+#define cpu_sw_sram_isointb            BIT(8)
+#define cpu_sw_clk_dis                 BIT(9)
+#define cpu_sw_ckiso                   BIT(10)
+#define cpu_sw_pd                      (U(0x1F) << 11)
+#define cpu_sw_hot_plug_reset          BIT(16)
+#define cpu_sw_powr_on_override_en     BIT(17)
+#define cpu_sw_pwr_on                  BIT(18)
+#define cpu_spark2ldo_allswoff         BIT(19)
+#define cpu_pdbo_all_on_ack            BIT(20)
+#define cpu_pre2_pdbo_allon_ack                BIT(21)
+#define cpu_pre1_pdbo_allon_ack                BIT(22)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES               MCUCFG_REG(0xa714)
+#define CPC_MCUSYS_PWR_CTRL                    MCUCFG_REG(0xa804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG           MCUCFG_REG(0xa814)
+#define CPC_MCUSYS_LAST_CORE_REQ               MCUCFG_REG(0xa818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP           MCUCFG_REG(0xa81c)
+#define CPC_MCUSYS_LAST_CORE_RESP              MCUCFG_REG(0xa824)
+#define CPC_MCUSYS_PWR_ON_MASK                 MCUCFG_REG(0xa828)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET          MCUCFG_REG(0xa8a8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR          MCUCFG_REG(0xa8ac)
+#define CPC_MCUSYS_CPC_DBG_SETTING             MCUCFG_REG(0xab00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE      MCUCFG_REG(0xab04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE      MCUCFG_REG(0xab08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE      MCUCFG_REG(0xab0c)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE      MCUCFG_REG(0xab10)
+#define CPC_MCUSYS_TRACE_SEL                   MCUCFG_REG(0xab14)
+#define CPC_MCUSYS_TRACE_DATA                  MCUCFG_REG(0xab20)
+#define CPC_MCUSYS_CLUSTER_COUNTER             MCUCFG_REG(0xab70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR         MCUCFG_REG(0xab74)
+#define SPARK2LDO                              MCUCFG_REG(0x2700)
+/* APB module mcucfg */
+#define MP0_CA7_CACHE_CONFIG           MCUCFG_REG(0x000)
+#define MP0_AXI_CONFIG                 MCUCFG_REG(0x02C)
+#define MP0_MISC_CONFIG0               MCUCFG_REG(0x030)
+#define MP0_MISC_CONFIG1               MCUCFG_REG(0x034)
+#define MP0_MISC_CONFIG2               MCUCFG_REG(0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu) (MP0_MISC_CONFIG2 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3               MCUCFG_REG(0x03C)
+#define MP0_MISC_CONFIG9               MCUCFG_REG(0x054)
+#define MP0_CA7_MISC_CONFIG            MCUCFG_REG(0x064)
+
+#define MP0_RW_RSVD0                   MCUCFG_REG(0x06C)
+
+
+#define MP1_CA7_CACHE_CONFIG           MCUCFG_REG(0x200)
+#define MP1_AXI_CONFIG                 MCUCFG_REG(0x22C)
+#define MP1_MISC_CONFIG0               MCUCFG_REG(0x230)
+#define MP1_MISC_CONFIG1               MCUCFG_REG(0x234)
+#define MP1_MISC_CONFIG2               MCUCFG_REG(0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu) (MP1_MISC_CONFIG2 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3               MCUCFG_REG(0x23C)
+#define MP1_MISC_CONFIG9               MCUCFG_REG(0x254)
+#define MP1_CA7_MISC_CONFIG            MCUCFG_REG(0x264)
+
+#define CCI_ADB400_DCM_CONFIG          MCUCFG_REG(0x740)
+#define SYNC_DCM_CONFIG                        MCUCFG_REG(0x744)
+
+#define MP0_CLUSTER_CFG0               MCUCFG_REG(0xC8D0)
+
+#define MP0_SPMC                       MCUCFG_REG(0x788)
+#define MP1_SPMC                       MCUCFG_REG(0x78C)
+#define MP2_AXI_CONFIG                 MCUCFG_REG(0x220C)
+#define MP2_AXI_CONFIG_ACINACTM                BIT(0)
+#define MP2_AXI_CONFIG_AINACTS         BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM                        BIT(4)
+#define MPx_AXI_CONFIG_AINACTS                 BIT(5)
+#define MPx_CA7_MISC_CONFIG_standbywfil2       BIT(28)
+
+#define MP0_CPU0_STANDBYWFE            BIT(20)
+#define MP0_CPU1_STANDBYWFE            BIT(21)
+#define MP0_CPU2_STANDBYWFE            BIT(22)
+#define MP0_CPU3_STANDBYWFE            BIT(23)
+
+#define MP1_CPU0_STANDBYWFE            BIT(20)
+#define MP1_CPU1_STANDBYWFE            BIT(21)
+#define MP1_CPU2_STANDBYWFE            BIT(22)
+#define MP1_CPU3_STANDBYWFE            BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL         MCUCFG_REG(0x1c00)
+#define CPUSYS0_SPARKEN                        MCUCFG_REG(0x1c04)
+#define CPUSYS0_AMUXSEL                        MCUCFG_REG(0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL         MCUCFG_REG(0x3c00)
+#define CPUSYS1_SPARKEN                        MCUCFG_REG(0x3c04)
+#define CPUSYS1_AMUXSEL                        MCUCFG_REG(0x3c08)
+
+#define MP2_PWR_RST_CTL                        MCUCFG_REG(0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0          MCUCFG_REG(0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1          MCUCFG_REG(0x22A4)
+
+#define MP2_COQ                                MCUCFG_REG(0x22BC)
+#define MP2_COQ_SW_DIS                 BIT(0)
+
+#define MP2_CA15M_MON_SEL              MCUCFG_REG(0x2400)
+#define MP2_CA15M_MON_L                        MCUCFG_REG(0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL          MCUCFG_REG(0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL          MCUCFG_REG(0x2438)
+#define CPUSYS2_CPU0_SPMC_STA          MCUCFG_REG(0x2434)
+#define CPUSYS2_CPU1_SPMC_STA          MCUCFG_REG(0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL          MCUCFG_REG(0x068)
+#define MP1_CA7L_DBG_PWR_CTRL          MCUCFG_REG(0x268)
+#define BIG_DBG_PWR_CTRL               MCUCFG_REG(0x75C)
+
+#define MP2_SW_RST_B                   BIT(0)
+#define MP2_TOPAON_APB_MASK            BIT(1)
+
+#define B_SW_HOT_PLUG_RESET            BIT(30)
+
+#define B_SW_PD_OFFSET                 (18U)
+#define B_SW_PD                                (U(0x3f) << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET                (12U)
+#define B_SW_SRAM_SLEEPB               (U(0x3f) << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB              BIT(9)
+#define B_SW_ISO                       BIT(8)
+#define B_SW_LOGIC_PDB                 BIT(7)
+#define B_SW_LOGIC_PRE2_PDB            BIT(6)
+#define B_SW_LOGIC_PRE1_PDB            BIT(5)
+#define B_SW_FSM_OVERRIDE              BIT(4)
+#define B_SW_PWR_ON                    BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN                BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET         (6U)
+#define B_FSM_STATE_OUT_MASK           (U(0x1f) << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK    BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK     BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK        BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK        BIT(2)
+
+#define B_FSM_OFF                      (0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON                       (1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET                      (2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum {
+       MP0_CPUCFG_64BIT_SHIFT = 12U,
+       MP1_CPUCFG_64BIT_SHIFT = 28U,
+       MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT,
+       MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT
+};
+
+enum {
+       MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U,
+       MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U,
+       MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U,
+       MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U,
+       MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U,
+
+       MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+               U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+       MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+               U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+       MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+               U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+       MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+               U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+       MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+               U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+       MP1_AINACTS_SHIFT = 4U,
+       MP1_AINACTS = 1U << MP1_AINACTS_SHIFT
+};
+
+enum {
+       MP1_SW_CG_GEN_SHIFT = 12U,
+       MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+       MP1_L2RSTDISABLE_SHIFT = 14U,
+       MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT
+};
+#endif /* __ASSEMBLER__ */
+
+#endif  /* MCUCFG_H */
diff --git a/plat/mediatek/mt8186/include/plat_mtk_lpm.h b/plat/mediatek/mt8186/include/plat_mtk_lpm.h
new file mode 100644 (file)
index 0000000..347f358
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MTK_LPM_H
+#define PLAT_MTK_LPM_H
+
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+
+#define MT_IRQ_REMAIN_MAX      U(32)
+#define MT_IRQ_REMAIN_CAT_LOG  BIT(31)
+
+struct mt_irqremain {
+       unsigned int count;
+       unsigned int irqs[MT_IRQ_REMAIN_MAX];
+       unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+       unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+#define PLAT_RC_STATUS_READY           BIT(0)
+#define PLAT_RC_STATUS_FEATURE_EN      BIT(1)
+#define PLAT_RC_STATUS_UART_NONSLEEP   BIT(31)
+
+struct mt_lpm_tz {
+       int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state);
+       int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state);
+
+       int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state);
+       int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state);
+
+       int (*pwr_cluster_on)(unsigned int cpu,
+                                       const psci_power_state_t *state);
+       int (*pwr_cluster_dwn)(unsigned int cpu,
+                                       const psci_power_state_t *state);
+
+       int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state);
+       int (*pwr_mcusys_on_finished)(unsigned int cpu,
+                                       const psci_power_state_t *state);
+       int (*pwr_mcusys_dwn)(unsigned int cpu,
+                                       const psci_power_state_t *state);
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void);
+
+#endif /* PLAT_MTK_LPM_H */
diff --git a/plat/mediatek/mt8186/include/plat_pm.h b/plat/mediatek/mt8186/include/plat_pm.h
new file mode 100644 (file)
index 0000000..436db34
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PM_H
+#define PLAT_PM_H
+
+#include <lib/utils_def.h>
+
+#define MT_PLAT_PWR_STATE_CPU                  U(1)
+#define MT_PLAT_PWR_STATE_CLUSTER              U(2)
+#define MT_PLAT_PWR_STATE_MCUSYS               U(3)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE         U(8)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND       U(9)
+
+#define MTK_LOCAL_STATE_RUN                    U(0)
+#define MTK_LOCAL_STATE_RET                    U(1)
+#define MTK_LOCAL_STATE_OFF                    U(2)
+
+#define MTK_AFFLVL_CPU                         U(0)
+#define MTK_AFFLVL_CLUSTER                     U(1)
+#define MTK_AFFLVL_MCUSYS                      U(2)
+#define MTK_AFFLVL_SYSTEM                      U(3)
+
+#define IS_CLUSTER_OFF_STATE(s)                                        \
+               is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER])
+#define IS_MCUSYS_OFF_STATE(s)                                 \
+               is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS])
+#define IS_SYSTEM_SUSPEND_STATE(s)                             \
+               is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM])
+
+#define IS_PLAT_SUSPEND_ID(stateid)                            \
+               ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE)    \
+               || (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* PLAT_PM_H */
index 5a565562f420b53cf5bfecb82d4db63a2789f3f4..479a8d4bc7936672407ce9cb7e231c8c6a8434dd 100644 (file)
@@ -19,6 +19,8 @@
 #define MTK_DEV_RNG2_BASE      MT_GIC_BASE
 #define MTK_DEV_RNG2_SIZE      0x600000
 
+#define SPM_BASE               (IO_PHYS + 0x00006000)
+
 /*******************************************************************************
  * GPIO related constants
  ******************************************************************************/
index 6e3ab37a22f7f9a37c345d0733c1e4b3e65efac4..b014297b21e6e86c8fd14c00df8315876786d923 100644 (file)
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+/* common headers */
+#include <assert.h>
+
+#include <arch_helpers.h>
 #include <common/debug.h>
 #include <lib/psci/psci.h>
 
+/* platform specific headers */
+#include <mt_gic_v3.h>
+#include <mtspmc.h>
+#include <plat/common/platform.h>
+#include <plat_mtk_lpm.h>
+#include <plat_params.h>
+#include <plat_pm.h>
+
+/*
+ * Cluster state request:
+ * [0] : The CPU requires cluster power down
+ * [1] : The CPU requires cluster power on
+ */
+#define coordinate_cluster(onoff)      write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron()     coordinate_cluster(1)
+#define coordinate_cluster_pwroff()    coordinate_cluster(0)
+
+/* platform secure entry point */
+static uintptr_t secure_entrypoint;
+/* per-CPU power state */
+static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
+
+/* platform CPU power domain - ops */
+static const struct mt_lpm_tz *plat_mt_pm;
+
+static inline int plat_mt_pm_invoke(int (*func)(unsigned int cpu,
+                                               const psci_power_state_t *state),
+                                   int cpu, const psci_power_state_t *state)
+{
+       int ret = -1;
+
+       if (func != NULL) {
+               ret = func(cpu, state);
+       }
+       return ret;
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cpu_pwrdwn_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       (void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_dwn, cpu, state);
+
+       if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
+                       (req_pstate == 0U)) { /* hotplug off */
+               coordinate_cluster_pwroff();
+       }
+
+       /* Prevent interrupts from spuriously waking up this CPU */
+       mt_gic_rdistif_save();
+       gicv3_cpuif_disable(cpu);
+       gicv3_rdistif_off(cpu);
+}
+
+static void plat_cpu_pwron_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       (void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_on, cpu, state);
+
+       coordinate_cluster_pwron();
+
+       /*
+        * If mcusys does power down before then restore
+        * all CPUs' GIC Redistributors
+        */
+       if (IS_MCUSYS_OFF_STATE(state)) {
+               mt_gic_rdistif_restore_all();
+       } else {
+               gicv3_rdistif_on(cpu);
+               gicv3_cpuif_enable(cpu);
+               mt_gic_rdistif_init();
+               mt_gic_rdistif_restore();
+       }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cluster_pwrdwn_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_dwn, cpu, state) != 0) {
+               coordinate_cluster_pwron();
+
+               /*
+                * TODO:
+                * Return on fail and add a 'return' here before
+                * adding any code following the if-block.
+                */
+       }
+}
+
+static void plat_cluster_pwron_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_on, cpu, state) != 0) {
+               /*
+                * TODO:
+                * return on fail and add a 'return' here before
+                * adding any code following the if-block.
+                */
+       }
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_mcusys_pwrdwn_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_dwn, cpu, state) != 0) {
+               return;         /* return on fail */
+       }
+
+       mt_gic_distif_save();
+       gic_sgi_save_all();
+}
+
+static void plat_mcusys_pwron_common(unsigned int cpu,
+               const psci_power_state_t *state, unsigned int req_pstate)
+{
+       assert(cpu == plat_my_core_pos());
+       assert(plat_mt_pm != NULL);
+
+       if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on, cpu, state) != 0) {
+               /* return on fail */
+               return;
+       }
+
+       mt_gic_init();
+       mt_gic_distif_restore();
+       gic_sgi_restore_all();
+
+       (void)plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on_finished, cpu, state);
+}
+
+/* plat_psci_ops implementation */
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+       uint64_t scr;
+
+       scr = read_scr_el3();
+       write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+       isb();
+       dsb();
+       wfi();
+
+       write_scr_el3(scr);
+}
+
+static int plat_power_domain_on(u_register_t mpidr)
+{
+       unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+       unsigned int cluster = 0U;
+
+       if (cpu >= PLATFORM_CORE_COUNT) {
+               return PSCI_E_INVALID_PARAMS;
+       }
+
+       if (!spm_get_cluster_powerstate(cluster)) {
+               spm_poweron_cluster(cluster);
+       }
+
+       /* init CPU reset arch as AARCH64 */
+       mcucfg_init_archstate(cluster, cpu, true);
+       mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
+       spm_poweron_cpu(cluster, cpu);
+
+       return PSCI_E_SUCCESS;
+}
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+       unsigned long mpidr = read_mpidr_el1();
+       unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+       assert(cpu < PLATFORM_CORE_COUNT);
+
+       /* Allow IRQs to wakeup this core in IDLE flow */
+       mcucfg_enable_gic_wakeup(0U, cpu);
+
+       if (IS_CLUSTER_OFF_STATE(state)) {
+               plat_cluster_pwron_common(cpu, state, 0U);
+       }
+
+       plat_cpu_pwron_common(cpu, state, 0U);
+}
+
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+       unsigned long mpidr = read_mpidr_el1();
+       unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+       assert(cpu < PLATFORM_CORE_COUNT);
+
+       plat_cpu_pwrdwn_common(cpu, state, 0U);
+       spm_poweroff_cpu(0U, cpu);
+
+       /* prevent unintended IRQs from waking up the hot-unplugged core */
+       mcucfg_disable_gic_wakeup(0U, cpu);
+
+       if (IS_CLUSTER_OFF_STATE(state)) {
+               plat_cluster_pwrdwn_common(cpu, state, 0U);
+       }
+}
+
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+       unsigned int cpu = plat_my_core_pos();
+
+       assert(cpu < PLATFORM_CORE_COUNT);
+       assert(plat_mt_pm != NULL);
+
+       (void)plat_mt_pm_invoke(plat_mt_pm->pwr_prompt, cpu, state);
+
+       /* Perform the common CPU specific operations */
+       plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+
+       if (IS_CLUSTER_OFF_STATE(state)) {
+               /* Perform the common cluster specific operations */
+               plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+       }
+
+       if (IS_MCUSYS_OFF_STATE(state)) {
+               /* Perform the common mcusys specific operations */
+               plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+       }
+}
+
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+       unsigned int cpu = plat_my_core_pos();
+
+       assert(cpu < PLATFORM_CORE_COUNT);
+       assert(plat_mt_pm != NULL);
+
+       if (IS_MCUSYS_OFF_STATE(state)) {
+               /* Perform the common mcusys specific operations */
+               plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
+       }
+
+       if (IS_CLUSTER_OFF_STATE(state)) {
+               /* Perform the common cluster specific operations */
+               plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
+       }
+
+       /* Perform the common CPU specific operations */
+       plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
+
+       (void)plat_mt_pm_invoke(plat_mt_pm->pwr_reflect, cpu, state);
+}
+
+static int plat_validate_power_state(unsigned int power_state,
+                                       psci_power_state_t *req_state)
+{
+       unsigned int pstate = psci_get_pstate_type(power_state);
+       unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+       unsigned int cpu = plat_my_core_pos();
+
+       if (aff_lvl > PLAT_MAX_PWR_LVL) {
+               return PSCI_E_INVALID_PARAMS;
+       }
+
+       if (pstate == PSTATE_TYPE_STANDBY) {
+               req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+       } else {
+               unsigned int i;
+               unsigned int pstate_id = psci_get_pstate_id(power_state);
+               plat_local_state_t s = MTK_LOCAL_STATE_OFF;
+
+               /* Use pstate_id to be power domain state */
+               if (pstate_id > s) {
+                       s = (plat_local_state_t)pstate_id;
+               }
+
+               for (i = 0U; i <= aff_lvl; i++) {
+                       req_state->pwr_domain_state[i] = s;
+               }
+       }
+
+       plat_power_state[cpu] = power_state;
+       return PSCI_E_SUCCESS;
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+       unsigned int lv;
+       unsigned int cpu = plat_my_core_pos();
+
+       for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
+               req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
+       }
+
+       plat_power_state[cpu] =
+                       psci_make_powerstate(
+                               MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+                               PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+
+       flush_dcache_range((uintptr_t)
+                       &plat_power_state[cpu],
+                       sizeof(plat_power_state[cpu]));
+}
+
 static const plat_psci_ops_t plat_psci_ops = {
+       .cpu_standby                    = plat_cpu_standby,
+       .pwr_domain_on                  = plat_power_domain_on,
+       .pwr_domain_on_finish           = plat_power_domain_on_finish,
+       .pwr_domain_off                 = plat_power_domain_off,
+       .pwr_domain_suspend             = plat_power_domain_suspend,
+       .pwr_domain_suspend_finish      = plat_power_domain_suspend_finish,
+       .validate_power_state           = plat_validate_power_state,
+       .get_sys_suspend_power_state    = plat_get_sys_suspend_power_state
 };
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
                        const plat_psci_ops_t **psci_ops)
 {
        *psci_ops = &plat_psci_ops;
+       secure_entrypoint = sec_entrypoint;
+
+       /*
+        * init the warm reset config for boot CPU
+        * reset arch as AARCH64
+        * reset addr as function bl31_warm_entrypoint()
+        */
+       mcucfg_init_archstate(0U, 0U, true);
+       mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
+
+       spmc_init();
 
        return 0;
 }
index dd4b3afbff1034faeee245c179e4ba9f387c78b4..31a030a85ef737c95ee0f063d3ff4516ce5b8379 100644 (file)
@@ -16,6 +16,7 @@ PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
                  -I${MTK_PLAT_SOC}/drivers/gpio/               \
                  -I${MTK_PLAT_SOC}/drivers/pmic/                  \
                  -I${MTK_PLAT_SOC}/drivers/rtc/                   \
+                 -I${MTK_PLAT_SOC}/drivers/spmc/                  \
                  -I${MTK_PLAT_SOC}/include/
 
 GICV3_SUPPORT_GIC600        :=      1
@@ -55,6 +56,7 @@ BL31_SOURCES += common/desc_image_load.c                              \
                 ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
                 ${MTK_PLAT_SOC}/drivers/pmic/pmic.c                   \
                 ${MTK_PLAT_SOC}/drivers/rtc/rtc.c                     \
+                ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c                 \
                 ${MTK_PLAT_SOC}/plat_pm.c                             \
                 ${MTK_PLAT_SOC}/plat_sip_calls.c                      \
                 ${MTK_PLAT_SOC}/plat_topology.c