]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
mediatek: mt8192: Add MCDI drivers
authorJames Liao <jamesjj.liao@mediatek.com>
Mon, 15 Jun 2020 08:41:03 +0000 (16:41 +0800)
committerManish Pandey <manish.pandey2@arm.com>
Mon, 7 Dec 2020 23:27:19 +0000 (23:27 +0000)
Add MCDI related drivers to handle CPU powered on/off in CPU suspend.

Change-Id: I5110461e8eef86f8383b45f197ec5cb10dbfeb3e
Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c [new file with mode: 0644]
plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c [new file with mode: 0644]
plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h [new file with mode: 0644]
plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c [new file with mode: 0644]
plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h [new file with mode: 0644]
plat/mediatek/mt8192/include/plat_mtk_lpm.h [new file with mode: 0644]
plat/mediatek/mt8192/include/plat_pm.h [new file with mode: 0644]
plat/mediatek/mt8192/include/platform_def.h
plat/mediatek/mt8192/platform.mk

diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
new file mode 100644 (file)
index 0000000..d6d4af7
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_mcdi.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
+
+static int plat_mt_lp_cpu_rc;
+
+static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
+{
+       return 0;
+}
+
+static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
+{
+       mtk_cpc_core_on_hint_clr(cpu);
+
+       if (IS_SYSTEM_SUSPEND_STATE(state)) {
+               mtk_cpc_time_sync();
+       }
+
+       return 0;
+}
+
+static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+       return 0;
+}
+
+static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+       /* clear DBGPRCR.CORENPDRQ to allow CPU power down  */
+       write_dbgprcr_el1(0ULL);
+
+       return 0;
+}
+
+static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+       return 0;
+}
+
+static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+       return 0;
+}
+
+static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+       if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+               return -1;
+       }
+
+       mtk_cpc_mcusys_off_reflect();
+
+       return 0;
+}
+
+static int pwr_mcusys_pwron_finished(unsigned int cpu,
+                                       const psci_power_state_t *state)
+{
+       if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+               return -1;
+       }
+
+       return 0;
+}
+
+static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+       if (!IS_MCUSYS_OFF_STATE(state)) {
+               goto mt_pwr_mcusysoff_break;
+       }
+
+       if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
+               goto mt_pwr_mcusysoff_break;
+       }
+
+       return 0;
+
+mt_pwr_mcusysoff_break:
+
+       plat_mt_lp_cpu_rc = -1;
+
+       return -1;
+}
+
+static const struct mt_lpm_tz plat_pm = {
+       .pwr_prompt                     = pwr_state_prompt,
+       .pwr_reflect                    = pwr_state_reflect,
+       .pwr_cpu_on                     = pwr_cpu_pwron,
+       .pwr_cpu_dwn                    = pwr_cpu_pwrdwn,
+       .pwr_cluster_on                 = pwr_cluster_pwron,
+       .pwr_cluster_dwn                = pwr_cluster_pwrdwn,
+       .pwr_mcusys_dwn                 = pwr_mcusys_pwrdwn,
+       .pwr_mcusys_on                  = pwr_mcusys_pwron,
+       .pwr_mcusys_on_finished         = pwr_mcusys_pwron_finished
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
+{
+       mtk_cpc_init();
+
+       if (mcdi_try_init() == 0) {
+               INFO("MCDI init done.\n");
+       }
+
+       return &plat_pm;
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644 (file)
index 0000000..f8c51a1
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+       int auto_off;
+       unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(uint32_t prot_req,
+                               uint32_t resp_reg, uint32_t resp_ofs)
+{
+       uint32_t sta, retry;
+
+       retry = 0U;
+
+       while (retry++ < RETRY_CNT_MAX) {
+
+               mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+               udelay(1U);
+
+               sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+               if (sta == PROT_SUCCESS) {
+                       return CPC_SUCCESS;
+               } else if (sta == PROT_GIVEUP) {
+                       return CPC_ERR_FAIL;
+               }
+       }
+
+       return CPC_ERR_TIMEOUT;
+}
+
+int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+       return mtk_cpc_last_core_prot(
+                       MCUSYS_PROT_SET,
+                       CPC_MCUSYS_LAST_CORE_RESP,
+                       MCUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_mcusys_prot_release(void)
+{
+       mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
+{
+       return mtk_cpc_last_core_prot(
+                       CPUSYS_PROT_SET,
+                       CPC_MCUSYS_MP_LAST_CORE_RESP,
+                       CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
+{
+       mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+       uint32_t backup_cnt;
+       uint32_t curr_cnt;
+       uint32_t cnt_mask = GENMASK(14, 0);
+       uint32_t clr_mask = GENMASK(1, 0);
+
+       /* Single Cluster */
+       backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+       curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+       /* Get off count if dormant count is 0 */
+       if ((curr_cnt & cnt_mask) == 0U) {
+               curr_cnt = (curr_cnt >> 16) & cnt_mask;
+       } else {
+               curr_cnt = curr_cnt & cnt_mask;
+       }
+
+       mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+       mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
+}
+
+static inline void mtk_cpc_mcusys_off_en(void)
+{
+       mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
+}
+
+static inline void mtk_cpc_mcusys_off_dis(void)
+{
+       mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+       mtk_cpc_mcusys_off_dis();
+       mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+       if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+               return CPC_ERR_FAIL;
+       }
+
+       mtk_cpc_cluster_cnt_backup();
+       mtk_cpc_mcusys_off_en();
+
+       return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu)
+{
+       mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(unsigned int cpu)
+{
+       mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+       uint32_t id;
+
+       for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
+               mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+               memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+                               (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+                               CPC_TRACE_SIZE);
+       }
+}
+
+void mtk_cpc_time_sync(void)
+{
+       uint64_t kt;
+       uint32_t systime_l, systime_h;
+
+       kt = sched_clock();
+       systime_l = mmio_read_32(CNTSYS_L_REG);
+       systime_h = mmio_read_32(CNTSYS_H_REG);
+
+       /* sync kernel timer to cpc */
+       mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+       mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+       /* sync system timer to cpc */
+       mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+       mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(uint32_t cfg, uint32_t data)
+{
+       uint32_t val;
+       uint32_t reg = 0U;
+
+       switch (cfg) {
+       case CPC_SMC_CONFIG_PROF:
+               reg = CPC_MCUSYS_CPC_DBG_SETTING;
+               val = mmio_read_32(reg);
+               val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
+               break;
+       case CPC_SMC_CONFIG_AUTO_OFF:
+               reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
+               val = mmio_read_32(reg);
+               if (data != 0U) {
+                       val |= CPC_AUTO_OFF_EN;
+                       cpc.auto_off = 1;
+               } else {
+                       val &= ~CPC_AUTO_OFF_EN;
+                       cpc.auto_off = 0;
+               }
+               break;
+       case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+               reg = CPC_MCUSYS_CPC_OFF_THRES;
+               cpc.auto_thres_tick = us_to_ticks(data);
+               val = cpc.auto_thres_tick;
+               break;
+       case CPC_SMC_CONFIG_CNT_CLR:
+               reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
+               val = GENMASK(1, 0);    /* clr_mask */
+               break;
+       case CPC_SMC_CONFIG_TIME_SYNC:
+               mtk_cpc_time_sync();
+               break;
+       default:
+               break;
+       }
+
+       if (reg != 0U) {
+               mmio_write_32(reg, val);
+       }
+}
+
+static uint32_t mtk_cpc_read_config(uint32_t cfg)
+{
+       uint32_t res = 0U;
+
+       switch (cfg) {
+       case CPC_SMC_CONFIG_PROF:
+               res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
+                       1U : 0U;
+               break;
+       case CPC_SMC_CONFIG_AUTO_OFF:
+               res = cpc.auto_off;
+               break;
+       case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+               res = ticks_to_us(cpc.auto_thres_tick);
+               break;
+       case CPC_SMC_CONFIG_CNT_CLR:
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+       uint64_t res = 0ULL;
+
+       switch (act) {
+       case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+               mtk_cpc_dump_timestamp();
+               break;
+       case CPC_SMC_EVENT_GIC_DPG_SET:
+               /* isolated_status = x2; */
+               break;
+       case CPC_SMC_EVENT_CPC_CONFIG:
+               mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
+               break;
+       case CPC_SMC_EVENT_READ_CONFIG:
+               res = mtk_cpc_read_config((uint32_t)arg1);
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+void mtk_cpc_init(void)
+{
+       mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
+                       mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
+                       | CPC_DBG_EN
+                       | CPC_CALC_EN);
+
+       cpc.auto_off = 1;
+       cpc.auto_thres_tick = us_to_ticks(8000);
+
+       mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+                       mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
+                       | CPC_OFF_PRE_EN
+                       | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
+
+       mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644 (file)
index 0000000..19dd6a2
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND    1
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r)    (uint32_t)(MTK_MCDI_SRAM_BASE + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE         U(0x20)
+#define CPC_TRACE_ID_NUM       U(10)
+#define CPC_TRACE_SRAM(id)     (CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP CPUIDLE_SRAM_REG(0x1F0)
+#define CPC_MCUSYS_CNT         CPUIDLE_SRAM_REG(0x1F4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS     BIT(1)
+#define CPC_PWR_ON_PRIORITY    BIT(2)
+#define CPC_AUTO_OFF_EN                BIT(5)
+#define CPC_DORMANT_WAIT_EN    BIT(14)
+#define CPC_CTRL_EN            BIT(16)
+#define CPC_OFF_PRE_EN         BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ(0xA818) : last core protection */
+#define CPUSYS_PROT_SET                BIT(0)
+#define MCUSYS_PROT_SET                BIT(8)
+#define CPUSYS_PROT_CLR                BIT(8)
+#define MCUSYS_PROT_CLR                BIT(9)
+
+#define CPC_PROT_RESP_MASK     U(0x3)
+#define CPUSYS_RESP_OFS                U(16)
+#define MCUSYS_RESP_OFS                U(30)
+
+#define cpusys_resp(r)         (((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+#define mcusys_resp(r)         (((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+
+#define RETRY_CNT_MAX          U(1000)
+
+#define PROT_RETRY             U(0)
+#define PROT_SUCCESS           U(1)
+#define PROT_GIVEUP            U(2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING(0xAB00): debug setting */
+#define CPC_PROF_EN            BIT(0)
+#define CPC_DBG_EN             BIT(1)
+#define CPC_FREEZE             BIT(2)
+#define CPC_CALC_EN            BIT(3)
+
+enum {
+       CPC_SUCCESS = 0,
+
+       CPC_ERR_FAIL,
+       CPC_ERR_TIMEOUT,
+
+       NF_CPC_ERR
+};
+
+enum {
+       CPC_SMC_EVENT_DUMP_TRACE_DATA,
+       CPC_SMC_EVENT_GIC_DPG_SET,
+       CPC_SMC_EVENT_CPC_CONFIG,
+       CPC_SMC_EVENT_READ_CONFIG,
+
+       NF_CPC_SMC_EVENT
+};
+
+enum {
+       CPC_SMC_CONFIG_PROF,
+       CPC_SMC_CONFIG_AUTO_OFF,
+       CPC_SMC_CONFIG_AUTO_OFF_THRES,
+       CPC_SMC_CONFIG_CNT_CLR,
+       CPC_SMC_CONFIG_TIME_SYNC,
+
+       NF_CPC_SMC_CONFIG
+};
+
+#define us_to_ticks(us)                ((us) * 13)
+#define ticks_to_us(tick)      ((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster);
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu);
+void mtk_cpc_core_on_hint_clr(unsigned int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c
new file mode 100644 (file)
index 0000000..df74122
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mt_mcdi.h>
+
+/* Read/Write */
+#define APMCU_MCUPM_MBOX_AP_READY      U(0)
+#define APMCU_MCUPM_MBOX_RESERVED_1    U(1)
+#define APMCU_MCUPM_MBOX_RESERVED_2    U(2)
+#define APMCU_MCUPM_MBOX_RESERVED_3    U(3)
+#define APMCU_MCUPM_MBOX_PWR_CTRL_EN   U(4)
+#define APMCU_MCUPM_MBOX_L3_CACHE_MODE U(5)
+#define APMCU_MCUPM_MBOX_BUCK_MODE     U(6)
+#define APMCU_MCUPM_MBOX_ARMPLL_MODE   U(7)
+/* Read only */
+#define APMCU_MCUPM_MBOX_TASK_STA      U(8)
+#define APMCU_MCUPM_MBOX_RESERVED_9    U(9)
+#define APMCU_MCUPM_MBOX_RESERVED_10   U(10)
+#define APMCU_MCUPM_MBOX_RESERVED_11   U(11)
+
+/* CPC mode - Read/Write */
+#define APMCU_MCUPM_MBOX_WAKEUP_CPU    U(12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
+#define MCUPM_MCUSYS_CTRL              BIT(0)
+#define MCUPM_BUCK_CTRL                        BIT(1)
+#define MCUPM_ARMPLL_CTRL              BIT(2)
+#define MCUPM_CM_CTRL                  BIT(3)
+#define MCUPM_PWR_CTRL_MASK            GENMASK(3, 0)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
+#define MCUPM_BUCK_NORMAL_MODE         U(0) /* default */
+#define MCUPM_BUCK_LP_MODE             U(1)
+#define MCUPM_BUCK_OFF_MODE            U(2)
+#define NF_MCUPM_BUCK_MODE             U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
+#define MCUPM_ARMPLL_ON                        U(0) /* default */
+#define MCUPM_ARMPLL_GATING            U(1)
+#define MCUPM_ARMPLL_OFF               U(2)
+#define NF_MCUPM_ARMPLL_MODE           U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
+#define MCUPM_TASK_UNINIT              U(0)
+#define MCUPM_TASK_INIT                        U(1)
+#define MCUPM_TASK_INIT_FINISH         U(2)
+#define MCUPM_TASK_WAIT                        U(3)
+#define MCUPM_TASK_RUN                 U(4)
+#define MCUPM_TASK_PAUSE               U(5)
+
+#define SSPM_MBOX_3_BASE               U(0x0c55fce0)
+
+#define MCDI_NOT_INIT                  0
+#define MCDI_INIT_1                    1
+#define MCDI_INIT_2                    2
+#define MCDI_INIT_DONE                 3
+
+static int mcdi_init_status __section("tzfw_coherent_mem");
+
+static inline uint32_t mcdi_mbox_read(uint32_t id)
+{
+       return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
+}
+
+static inline void mcdi_mbox_write(uint32_t id, uint32_t val)
+{
+       mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val);
+}
+
+static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
+{
+       mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
+}
+
+static void mtk_set_mcupm_pll_mode(uint32_t mode)
+{
+       if (mode < NF_MCUPM_ARMPLL_MODE) {
+               mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
+       }
+}
+
+static void mtk_set_mcupm_buck_mode(uint32_t mode)
+{
+       if (mode < NF_MCUPM_BUCK_MODE) {
+               mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
+       }
+}
+
+static int mtk_mcupm_is_ready(void)
+{
+       unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+       return (sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH);
+}
+
+static int mcdi_init_1(void)
+{
+       unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+       if (sta != MCUPM_TASK_INIT) {
+               return -1;
+       }
+
+       mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+       mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+       mtk_mcupm_pwr_ctrl_setting(
+                        MCUPM_MCUSYS_CTRL |
+                        MCUPM_BUCK_CTRL |
+                        MCUPM_ARMPLL_CTRL);
+
+       mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
+
+       return 0;
+}
+
+static int mcdi_init_2(void)
+{
+       return mtk_mcupm_is_ready() ? 0 : -1;
+}
+
+int mcdi_try_init(void)
+{
+       if (mcdi_init_status == MCDI_INIT_DONE) {
+               return 0;
+       }
+
+       if (mcdi_init_status == MCDI_NOT_INIT) {
+               mcdi_init_status = MCDI_INIT_1;
+       }
+
+       if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
+               mcdi_init_status = MCDI_INIT_2;
+       }
+
+       if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
+               mcdi_init_status = MCDI_INIT_DONE;
+       }
+
+       return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h
new file mode 100644 (file)
index 0000000..f3545aa
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MCDI_H
+#define MT_MCDI_H
+
+int mcdi_try_init(void);
+
+#endif /* MT_MCDI_H */
diff --git a/plat/mediatek/mt8192/include/plat_mtk_lpm.h b/plat/mediatek/mt8192/include/plat_mtk_lpm.h
new file mode 100644 (file)
index 0000000..8ba8b93
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, 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(8)
+#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/mt8192/include/plat_pm.h b/plat/mediatek/mt8192/include/plat_pm.h
new file mode 100644 (file)
index 0000000..a2881ce
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, 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 e6e1f8d0a40a3219d43ab11d9a69ef7b425bfcf2..8d43dc8a92e80faa51b1d22cf3675de188033941 100644 (file)
@@ -23,6 +23,8 @@
 #define MTK_DEV_RNG1_SIZE    0x10000000
 #define MTK_DEV_RNG2_BASE    0x0c000000
 #define MTK_DEV_RNG2_SIZE    0x600000
+#define MTK_MCDI_SRAM_BASE      0x11B000
+#define MTK_MCDI_SRAM_MAP_SIZE  0x1000
 
 #define GPIO_BASE        (IO_PHYS + 0x00005000)
 #define SPM_BASE         (IO_PHYS + 0x00006000)
index e1da9c17a9b15f05ba1d6909e84567e527c25f58..93b059e93fa99213adf10284c9dcd08647f42cb7 100644 (file)
@@ -11,6 +11,7 @@ PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
                  -I${MTK_PLAT_SOC}/include/                       \
                  -I${MTK_PLAT_SOC}/drivers/                       \
                  -I${MTK_PLAT_SOC}/drivers/gpio/                  \
+                 -I${MTK_PLAT_SOC}/drivers/mcdi/                  \
                  -I${MTK_PLAT_SOC}/drivers/spmc/                  \
                  -I${MTK_PLAT_SOC}/drivers/timer/
 
@@ -40,6 +41,9 @@ BL31_SOURCES    += common/desc_image_load.c                              \
                    ${MTK_PLAT_SOC}/plat_mt_gic.c                         \
                    ${MTK_PLAT_SOC}/plat_mt_cirq.c                        \
                    ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
+                   ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c              \
+                   ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c          \
+                   ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c                \
                    ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c                 \
                    ${MTK_PLAT_SOC}/drivers/timer/mt_timer.c