Commit 258f6a2d authored by Madhukar Pappireddy's avatar Madhukar Pappireddy Committed by TrustedFirmware Code Review
Browse files

Merge changes I4bd4612a,Id13a06d4,I0ea7f610,Ie6a7063b into integration

* changes:
  mediatek: mt8192: Add Vcore DVFS driver
  mediatek: mt8192: Add SPM suspend driver
  mediatek: mt8192: supports mcusys off when system suspend
  mediatek: mt8192: Add lpm driver
parents c0f0ab53 f3febcca
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mt_lp_rm.h>
#include <stddef.h>
struct platform_mt_resource_manager {
unsigned int count;
struct mt_resource_manager *plat_rm;
};
static struct platform_mt_resource_manager plat_mt_rm;
int mt_lp_rm_register(struct mt_resource_manager *rm)
{
unsigned int i;
struct mt_resource_constraint *const *rc;
if ((rm == NULL) || (rm->consts == NULL) ||
(plat_mt_rm.plat_rm != NULL)) {
return MT_RM_STATUS_BAD;
}
for (i = 0U, rc = rm->consts; *rc != NULL; i++, rc++) {
if ((*rc)->init != NULL) {
(*rc)->init();
}
}
plat_mt_rm.plat_rm = rm;
plat_mt_rm.count = i;
return MT_RM_STATUS_OK;
}
int mt_lp_rm_reset_constraint(int idx, unsigned int cpuid, int stateid)
{
struct mt_resource_constraint const *rc = NULL;
if ((plat_mt_rm.plat_rm == NULL) || (idx < 0) ||
(idx >= plat_mt_rm.count)) {
return MT_RM_STATUS_BAD;
}
rc = plat_mt_rm.plat_rm->consts[idx];
if ((rc == NULL) || (rc->reset == NULL)) {
return MT_RM_STATUS_BAD;
}
return rc->reset(cpuid, stateid);
}
int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
int stateid, void *priv)
{
int i, res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if ((rm == NULL) || (idx < 0) || (idx >= plat_mt_rm.count)) {
return res;
}
/* If subsys clk/mtcmos is on, add block-resource-off flag */
if (rm->update != NULL) {
res = rm->update(rm->consts, stateid, priv);
if (res != 0) {
return res;
}
}
for (i = idx, rc = (rm->consts + idx); *rc != NULL; i++, rc++) {
if (((*rc)->is_valid != NULL) &&
((*rc)->is_valid(cpuid, stateid))) {
if (((*rc)->run != NULL) &&
((*rc)->run(cpuid, stateid) == 0)) {
res = i;
break;
}
}
}
return res;
}
int mt_lp_rm_do_update(int stateid, int type, void const *p)
{
int res = MT_RM_STATUS_BAD;
struct mt_resource_constraint *const *rc;
struct mt_resource_manager *rm = plat_mt_rm.plat_rm;
if (rm == NULL) {
return res;
}
for (rc = rm->consts; *rc != NULL; rc++) {
if ((*rc)->update != NULL) {
res = (*rc)->update(stateid, type, p);
if (res != MT_RM_STATUS_OK) {
break;
}
}
}
return res;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_LP_RM_H
#define MT_LP_RM_H
#include <stdbool.h>
#define MT_RM_STATUS_OK 0
#define MT_RM_STATUS_BAD -1
enum PLAT_MT_LPM_RC_TYPE {
PLAT_RC_UPDATE_CONDITION,
PLAT_RC_UPDATE_REMAIN_IRQS
};
struct mt_resource_constraint {
int level;
int (*init)(void);
bool (*is_valid)(unsigned int cpu, int stateid);
int (*update)(int stateid, int type, const void *p);
int (*run)(unsigned int cpu, int stateid);
int (*reset)(unsigned int cpu, int stateid);
unsigned int (*allow)(int stateid);
};
struct mt_resource_manager {
int (*update)(struct mt_resource_constraint **con,
int stateid, void *priv);
struct mt_resource_constraint **consts;
};
extern int mt_lp_rm_register(struct mt_resource_manager *rm);
extern int mt_lp_rm_find_and_run_constraint(int idx, unsigned int cpuid,
int stateid, void *priv);
extern int mt_lp_rm_reset_constraint(int constraint_id, unsigned int cpuid,
int stateid);
extern int mt_lp_rm_do_update(int stateid, int type, void const *p);
#endif /* MT_LP_RM_H */
......@@ -31,6 +31,10 @@
#define MTK_SIP_KERNEL_BOOT_AARCH32 0x82000200
#define MTK_SIP_KERNEL_BOOT_AARCH64 0xC2000200
/* VCORE */
#define MTK_SIP_VCORE_CONTROL_ARCH32 0x82000506
#define MTK_SIP_VCORE_CONTROL_ARCH64 0xC2000506
/* Mediatek SiP Calls error code */
enum {
MTK_SIP_E_SUCCESS = 0,
......
......@@ -19,6 +19,8 @@ const mmap_region_t plat_mmap[] = {
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(MTK_MCDI_SRAM_BASE, MTK_MCDI_SRAM_MAP_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
{ 0 }
};
......
......@@ -19,6 +19,7 @@
#include <emi_mpu/emi_mpu.h>
#include <gpio/mtgpio.h>
#include <mt_gic_v3.h>
#include <mt_spm.h>
#include <mt_timer.h>
#include <mtk_dcm.h>
#include <plat_params.h>
......@@ -100,6 +101,7 @@ void bl31_platform_setup(void)
plat_mt8192_gpio_init();
mt_systimer_init();
generic_delay_timer_init();
spm_boot_init();
}
/*******************************************************************************
......
......@@ -12,6 +12,8 @@
#include <lib/spinlock.h>
#include <mt_cpu_pm_cpc.h>
#include <mt_lp_irqremain.h>
#include <mt_lp_rm.h>
#include <mt_mcdi.h>
#include <plat_mtk_lpm.h>
#include <plat_pm.h>
......@@ -73,27 +75,49 @@ static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
static int pwr_mcusys_pwron_finished(unsigned int cpu,
const psci_power_state_t *state)
{
int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
return -1;
}
mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
mt_lp_irqremain_release();
return 0;
}
static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
{
int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];
if (!IS_MCUSYS_OFF_STATE(state)) {
goto mt_pwr_mcusysoff_break;
}
if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
if (mcdi_try_init() != 0) {
goto mt_pwr_mcusysoff_break;
}
if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
goto mt_pwr_mcusysoff_break;
}
plat_mt_lp_cpu_rc =
mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);
if (plat_mt_lp_cpu_rc < 0) {
goto mt_pwr_mcusysoff_reflect;
}
mt_lp_irqremain_aquire();
return 0;
mt_pwr_mcusysoff_break:
mt_pwr_mcusysoff_reflect:
mtk_cpc_mcusys_off_reflect();
mt_pwr_mcusysoff_break:
plat_mt_lp_cpu_rc = -1;
return -1;
......@@ -119,5 +143,7 @@ const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
INFO("MCDI init done.\n");
}
mt_lp_irqremain_init();
return &plat_pm;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mt_lp_rm.h>
#include <mt_lp_irqremain.h>
#include <plat_mtk_lpm.h>
#include <plat_mt_cirq.h>
#define EDMA0_IRQ_ID U(448)
#define MDLA_IRQ_ID U(446)
#define MALI4_IRQ_ID U(399)
#define MALI3_IRQ_ID U(398)
#define MALI2_IRQ_ID U(397)
#define MALI1_IRQ_ID U(396)
#define MALI0_IRQ_ID U(395)
#define VPU_CORE1_IRQ_ID U(453)
#define VPU_CORE0_IRQ_ID U(452)
#define MD_WDT_IRQ_ID U(110)
#define KEYPAD_IRQ_ID U(106)
#define MD_WDT_WAKESRC 0x2000000
#define KEYPAD_WAKESRC 0x4
static struct mt_irqremain remain_irqs;
int mt_lp_irqremain_submit(void)
{
if (remain_irqs.count == 0) {
return -1;
}
set_wakeup_sources(remain_irqs.irqs, remain_irqs.count);
mt_lp_rm_do_update(-1, PLAT_RC_UPDATE_REMAIN_IRQS, &remain_irqs);
return 0;
}
int mt_lp_irqremain_aquire(void)
{
if (remain_irqs.count == 0) {
return -1;
}
mt_cirq_sw_reset();
mt_cirq_clone_gic();
mt_cirq_enable();
return 0;
}
int mt_lp_irqremain_release(void)
{
if (remain_irqs.count == 0) {
return -1;
}
mt_cirq_flush();
mt_cirq_disable();
return 0;
}
void mt_lp_irqremain_init(void)
{
uint32_t idx;
remain_irqs.count = 0;
/* level edma0 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = EDMA0_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mdla */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MDLA_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mali4 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MALI4_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mali3 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MALI3_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mali2 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MALI2_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mali1 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MALI1_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level mali0 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MALI0_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level vpu core1 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = VPU_CORE1_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* level vpu core0 */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = VPU_CORE0_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = 0;
remain_irqs.count++;
/* edge mdwdt */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = MD_WDT_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = MD_WDT_WAKESRC;
remain_irqs.count++;
/* edge keypad */
idx = remain_irqs.count;
remain_irqs.irqs[idx] = KEYPAD_IRQ_ID;
remain_irqs.wakeupsrc_cat[idx] = 0;
remain_irqs.wakeupsrc[idx] = KEYPAD_WAKESRC;
remain_irqs.count++;
mt_lp_irqremain_submit();
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_LP_IRQREMAIN_H
#define MT_LP_IRQREMAIN_H
extern int mt_lp_irqremain_submit(void);
extern int mt_lp_irqremain_aquire(void);
extern int mt_lp_irqremain_release(void);
extern void mt_lp_irqremain_init(void);
#endif /* MT_LP_IRQREMAIN_H */
......@@ -5,6 +5,7 @@
*/
#include <cdefs.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
......@@ -144,5 +145,7 @@ int mcdi_try_init(void)
mcdi_init_status = MCDI_INIT_DONE;
}
INFO("mcdi ready for mcusys-off-idle and system suspend\n");
return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
}
#
# Copyright (c) 2020, MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Enable or disable spm feature
MT_SPM_FEATURE_SUPPORT = yes
# Enable or disable cirq restore
MT_SPM_CIRQ_FEATURE_SUPPORT = yes
# sspm notifier support
MT_SPM_SSPM_NOTIFIER_SUPPORT = yes
CUR_SPM_FOLDER = ${MTK_PLAT_SOC}/drivers/spm
# spm common files
PLAT_SPM_SOURCE_FILES_COMMON += \
${CUR_SPM_FOLDER}/mt_spm.c \
${CUR_SPM_FOLDER}/mt_spm_conservation.c \
${CUR_SPM_FOLDER}/mt_spm_internal.c \
${CUR_SPM_FOLDER}/mt_spm_pmic_wrap.c \
${CUR_SPM_FOLDER}/mt_spm_vcorefs.c
# spm platform dependcy files
PLAT_SPM_SOURCE_FILES += \
${CUR_SPM_FOLDER}/constraints/mt_spm_rc_bus26m.c \
${CUR_SPM_FOLDER}/constraints/mt_spm_rc_cpu_buck_ldo.c \
${CUR_SPM_FOLDER}/constraints/mt_spm_rc_dram.c \
${CUR_SPM_FOLDER}/constraints/mt_spm_rc_syspll.c \
${CUR_SPM_FOLDER}/mt_spm_cond.c \
${CUR_SPM_FOLDER}/mt_spm_suspend.c \
${CUR_SPM_FOLDER}/mt_spm_idle.c
ifeq (${MT_SPM_FEATURE_SUPPORT}, no)
PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_UNSUPPORT
BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += ${PLAT_SPM_SOURCE_FILES_COMMON}
else
BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
${PLAT_SPM_SOURCE_FILES_COMMON} \
${PLAT_SPM_SOURCE_FILES}
endif
ifeq (${MT_SPM_CIRQ_FEATURE_SUPPORT}, no)
PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_CIRQ_UNSUPPORT
endif
ifeq (${MT_SPM_SSPM_NOTIFIER_SUPPORT}, no)
PLAT_SPM_DEBUG_CFLAGS += -DATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
else
BL31_MT_LPM_PLAT_SPM_SOURCE_FILES += \
${CUR_SPM_FOLDER}/notifier/mt_spm_sspm_notifier.c
endif
$(info --------------------------------------)
$(info SPM build flags: ${PLAT_SPM_DEBUG_CFLAGS})
$(info SPM build files: ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES})
$(info --------------------------------------)
# Common makefile for platform.mk
PLAT_INCLUDES += \
${PLAT_SPM_DEBUG_CFLAGS} \
-I${CUR_SPM_FOLDER}/ \
-I${CUR_SPM_FOLDER}/constraints/ \
-I${CUR_SPM_FOLDER}/notifier/
PLAT_BL_COMMON_SOURCES += ${BL31_MT_LPM_PLAT_SPM_SOURCE_FILES}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mt_lp_rm.h>
#include <mt_spm.h>
#include <mt_spm_cond.h>
#include <mt_spm_constraint.h>
#include <mt_spm_conservation.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_notifier.h>
#include <mt_spm_rc_internal.h>
#include <mt_spm_resource_req.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <plat_pm.h>
#include <plat_mtk_lpm.h>
#ifndef ATF_PLAT_CIRQ_UNSUPPORT
#include <mt_gic_v3.h>
#include <plat_mt_cirq.h>
#endif
#define CONSTRAINT_BUS26M_ALLOW \
(MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
#define CONSTRAINT_BUS26M_PCM_FLAG \
(SPM_FLAG_DISABLE_INFRA_PDN | \
SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_VCORE_DFS | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_ENABLE_TIA_WORKAROUND | \
SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
#define CONSTRAINT_BUS26M_PCM_FLAG1 \
(SPM_FLAG1_DISABLE_MD26M_CK_OFF)
#define CONSTRAINT_BUS26M_RESOURCE_REQ 0U
static unsigned int bus26m_ext_opand;
static struct mt_irqremain *refer2remain_irq;
static struct mt_spm_cond_tables cond_bus26m = {
.name = "bus26m",
.table_cg = {
0x07CBF1FC, /* MTCMOS1 */
0x0A0D8856, /* INFRA0 */
0x03AF9A00, /* INFRA1 */
0x86000650, /* INFRA2 */
0xC800C000, /* INFRA3 */
0x00000000, /* INFRA4 */
0x4000007C, /* INFRA5 */
0x280E0800, /* MMSYS0 */
0x00000001, /* MMSYS1 */
0x00000000, /* MMSYS2 */
},
.table_pll = (PLL_BIT_UNIVPLL | PLL_BIT_MFGPLL |
PLL_BIT_MSDCPLL | PLL_BIT_TVDPLL |
PLL_BIT_MMPLL),
};
static struct mt_spm_cond_tables cond_bus26m_res = {
.table_cg = { 0U },
.table_pll = 0U,
};
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_BUS26M,
.valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_COND_LATCH),
.cond_block = 0U,
.enter_cnt = 0U,
.cond_res = &cond_bus26m_res,
};
/*
* Cirq will take the place of gic when gic is off.
* However, cirq cannot work if 26m clk is turned off when system idle/suspend.
* Therefore, we need to set irq pending for specific wakeup source.
*/
#ifdef ATF_PLAT_CIRQ_UNSUPPORT
#define do_irqs_delivery()
#else
static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
unsigned int irq_index,
struct wake_status *wakeup)
{
INFO("[SPM] r12 = 0x%08x(0x%08x), flag = 0x%08x 0x%08x 0x%08x\n",
wakeup->tr.comm.r12, wakeup->md32pcm_wakeup_sta,
wakeup->tr.comm.debug_flag, wakeup->tr.comm.b_sw_flag0,
wakeup->tr.comm.b_sw_flag1);
INFO("irq:%u(0x%08x) set pending\n",
irqs->wakeupsrc[irq_index], irqs->irqs[irq_index]);
}
static void do_irqs_delivery(void)
{
unsigned int idx;
int res = 0;
struct wake_status *wakeup = NULL;
struct mt_irqremain *irqs = refer2remain_irq;
res = spm_conservation_get_result(&wakeup);
if ((res != 0) && (irqs == NULL)) {
return;
}
for (idx = 0U; idx < irqs->count; ++idx) {
if (((wakeup->tr.comm.r12 & irqs->wakeupsrc[idx]) != 0U) ||
((wakeup->raw_sta & irqs->wakeupsrc[idx]) != 0U)) {
if ((irqs->wakeupsrc_cat[idx] &
MT_IRQ_REMAIN_CAT_LOG) != 0U) {
mt_spm_irq_remain_dump(irqs, idx, wakeup);
}
mt_irq_set_pending(irqs->irqs[idx]);
}
}
}
#endif
static void spm_bus26m_conduct(struct spm_lp_scen *spm_lp,
unsigned int *resource_req)
{
spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG;
spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG1;
*resource_req |= CONSTRAINT_BUS26M_RESOURCE_REQ;
}
bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id)
{
(void)cpu;
(void)state_id;
return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
}
int spm_update_rc_bus26m(int state_id, int type, const void *val)
{
const struct mt_spm_cond_tables *tlb;
const struct mt_spm_cond_tables *tlb_check;
int res = MT_RM_STATUS_OK;
if (val == NULL) {
return MT_RM_STATUS_BAD;
}
if (type == PLAT_RC_UPDATE_CONDITION) {
tlb = (const struct mt_spm_cond_tables *)val;
tlb_check = (const struct mt_spm_cond_tables *)&cond_bus26m;
status.cond_block =
mt_spm_cond_check(state_id, tlb, tlb_check,
((status.valid &
MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
&cond_bus26m_res : NULL);
} else if (type == PLAT_RC_UPDATE_REMAIN_IRQS) {
refer2remain_irq = (struct mt_irqremain *)val;
} else {
res = MT_RM_STATUS_BAD;
}
return res;
}
unsigned int spm_allow_rc_bus26m(int state_id)
{
(void)state_id;
return CONSTRAINT_BUS26M_ALLOW;
}
int spm_run_rc_bus26m(unsigned int cpu, int state_id)
{
(void)cpu;
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, CONSTRAINT_BUS26M_ALLOW |
(IS_PLAT_SUSPEND_ID(state_id) ?
MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_enter(state_id,
(MT_SPM_EX_OP_SET_WDT |
MT_SPM_EX_OP_HW_S1_DETECT |
bus26m_ext_opand),
CONSTRAINT_BUS26M_RESOURCE_REQ);
} else {
mt_spm_idle_generic_enter(state_id, MT_SPM_EX_OP_HW_S1_DETECT,
spm_bus26m_conduct);
}
return 0;
}
int spm_reset_rc_bus26m(unsigned int cpu, int state_id)
{
unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
(void)cpu;
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
ext_op |= (bus26m_ext_opand | MT_SPM_EX_OP_SET_WDT);
mt_spm_suspend_resume(state_id, ext_op, NULL);
bus26m_ext_opand = 0U;
} else {
mt_spm_idle_generic_resume(state_id, ext_op, NULL);
status.enter_cnt++;
}
do_irqs_delivery();
return 0;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mt_spm.h>
#include <mt_spm_cond.h>
#include <mt_spm_constraint.h>
#include <mt_spm_conservation.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_notifier.h>
#include <mt_spm_rc_internal.h>
#include <mt_spm_resource_req.h>
#include <mt_spm_reg.h>
#include <mt_spm_suspend.h>
#include <plat_pm.h>
#define CONSTRAINT_CPU_BUCK_PCM_FLAG \
(SPM_FLAG_DISABLE_INFRA_PDN | \
SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_VCORE_DFS | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
#define CONSTRAINT_CPU_BUCK_PCM_FLAG1 0U
#define CONSTRAINT_CPU_BUCK_RESOURCE_REQ \
(MT_SPM_DRAM_S1 | \
MT_SPM_DRAM_S0 | \
MT_SPM_SYSPLL | \
MT_SPM_INFRA | \
MT_SPM_26M | \
MT_SPM_XO_FPM)
static unsigned int cpubuckldo_status = MT_SPM_RC_VALID_SW;
static unsigned int cpubuckldo_enter_cnt;
static void spm_cpu_bcuk_ldo_conduct(struct spm_lp_scen *spm_lp,
unsigned int *resource_req)
{
spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG;
spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG1;
*resource_req |= CONSTRAINT_CPU_BUCK_RESOURCE_REQ;
}
bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
{
(void)cpu;
(void)state_id;
return IS_MT_RM_RC_READY(cpubuckldo_status);
}
unsigned int spm_allow_rc_cpu_buck_ldo(int state_id)
{
(void)state_id;
return MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF;
}
int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
{
(void)cpu;
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER,
(IS_PLAT_SUSPEND_ID(state_id) ?
MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_enter(state_id,
MT_SPM_EX_OP_SET_WDT,
CONSTRAINT_CPU_BUCK_RESOURCE_REQ);
} else {
mt_spm_idle_generic_enter(state_id, 0U,
spm_cpu_bcuk_ldo_conduct);
}
cpubuckldo_enter_cnt++;
return 0;
}
int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
{
(void)cpu;
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_resume(state_id, MT_SPM_EX_OP_SET_WDT, NULL);
} else {
mt_spm_idle_generic_resume(state_id, 0U, NULL);
}
return 0;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <mt_lp_rm.h>
#include <mt_spm.h>
#include <mt_spm_cond.h>
#include <mt_spm_constraint.h>
#include <mt_spm_conservation.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_notifier.h>
#include <mt_spm_resource_req.h>
#include <mt_spm_reg.h>
#include <mt_spm_rc_internal.h>
#include <mt_spm_suspend.h>
#include <plat_pm.h>
#include <plat_mtk_lpm.h>
#define CONSTRAINT_DRAM_ALLOW \
(MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF)
#define CONSTRAINT_DRAM_PCM_FLAG \
(SPM_FLAG_DISABLE_INFRA_PDN | \
SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_VCORE_DFS | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
#define CONSTRAINT_DRAM_PCM_FLAG1 0U
#define CONSTRAINT_DRAM_RESOURCE_REQ \
(MT_SPM_SYSPLL | \
MT_SPM_INFRA | \
MT_SPM_26M)
static struct mt_spm_cond_tables cond_dram = {
.name = "dram",
.table_cg = {
0x078BF1FC, /* MTCMOS1 */
0x080D8856, /* INFRA0 */
0x03AF9A00, /* INFRA1 */
0x86000640, /* INFRA2 */
0xC800C000, /* INFRA3 */
0x00000000, /* INFRA4 */
0x00000000, /* INFRA5 */
0x200C0000, /* MMSYS0 */
0x00000000, /* MMSYS1 */
0x00000000, /* MMSYS2 */
},
.table_pll = 0U,
};
static struct mt_spm_cond_tables cond_dram_res = {
.table_cg = { 0U },
.table_pll = 0U,
};
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_DRAM,
.valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_COND_LATCH |
MT_SPM_RC_VALID_XSOC_BBLPM),
.cond_block = 0U,
.enter_cnt = 0U,
.cond_res = &cond_dram_res,
};
static void spm_dram_conduct(struct spm_lp_scen *spm_lp,
unsigned int *resource_req)
{
spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG;
spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_DRAM_PCM_FLAG1;
*resource_req |= CONSTRAINT_DRAM_RESOURCE_REQ;
}
bool spm_is_valid_rc_dram(unsigned int cpu, int state_id)
{
(void)cpu;
(void)state_id;
return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
}
int spm_update_rc_dram(int state_id, int type, const void *val)
{
const struct mt_spm_cond_tables *tlb;
const struct mt_spm_cond_tables *tlb_check;
int res = MT_RM_STATUS_OK;
if (val == NULL) {
return MT_RM_STATUS_BAD;
}
if (type == PLAT_RC_UPDATE_CONDITION) {
tlb = (const struct mt_spm_cond_tables *)val;
tlb_check = (const struct mt_spm_cond_tables *)&cond_dram;
status.cond_block =
mt_spm_cond_check(state_id, tlb, tlb_check,
((status.valid &
MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
&cond_dram_res : NULL);
} else {
res = MT_RM_STATUS_BAD;
}
return res;
}
unsigned int spm_allow_rc_dram(int state_id)
{
(void)state_id;
return CONSTRAINT_DRAM_ALLOW;
}
int spm_run_rc_dram(unsigned int cpu, int state_id)
{
unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
unsigned int allows = CONSTRAINT_DRAM_ALLOW;
(void)cpu;
if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
#ifdef MT_SPM_USING_SRCLKEN_RC
ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
#else
allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
#endif
}
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
(IS_PLAT_SUSPEND_ID(state_id) ?
MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
#else
(void)allows;
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_enter(state_id,
(MT_SPM_EX_OP_SET_WDT |
MT_SPM_EX_OP_HW_S1_DETECT),
CONSTRAINT_DRAM_RESOURCE_REQ);
} else {
mt_spm_idle_generic_enter(state_id, ext_op, spm_dram_conduct);
}
return 0;
}
int spm_reset_rc_dram(unsigned int cpu, int state_id)
{
unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
unsigned int allows = CONSTRAINT_DRAM_ALLOW;
(void)cpu;
if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
#ifdef MT_SPM_USING_SRCLKEN_RC
ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
#else
allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
#endif
}
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
#else
(void)allows;
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_resume(state_id,
(MT_SPM_EX_OP_SET_WDT |
MT_SPM_EX_OP_HW_S1_DETECT),
NULL);
} else {
mt_spm_idle_generic_resume(state_id, ext_op, NULL);
status.enter_cnt++;
}
return 0;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_RC_INTERNAL_H
#define MT_SPM_RC_INTERNAL_H
#include <stdbool.h>
#define SPM_FLAG_SRAM_SLEEP_CTRL \
(SPM_FLAG_DISABLE_SSPM_SRAM_SLEEP | \
SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
SPM_FLAG_DISABLE_SYSRAM_SLEEP | \
SPM_FLAG_DISABLE_MCUPM_SRAM_SLEEP | \
SPM_FLAG_DISABLE_SRAM_EVENT)
/* cpu buck/ldo constraint function */
bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
unsigned int spm_allow_rc_cpu_buck_ldo(int state_id);
int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id);
/* spm resource dram constraint function */
bool spm_is_valid_rc_dram(unsigned int cpu, int state_id);
int spm_update_rc_dram(int state_id, int type, const void *val);
unsigned int spm_allow_rc_dram(int state_id);
int spm_run_rc_dram(unsigned int cpu, int state_id);
int spm_reset_rc_dram(unsigned int cpu, int state_id);
/* spm resource syspll constraint function */
bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id);
int spm_update_rc_syspll(int state_id, int type, const void *val);
unsigned int spm_allow_rc_syspll(int state_id);
int spm_run_rc_syspll(unsigned int cpu, int state_id);
int spm_reset_rc_syspll(unsigned int cpu, int state_id);
/* spm resource bus26m constraint function */
bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id);
int spm_update_rc_bus26m(int state_id, int type, const void *val);
unsigned int spm_allow_rc_bus26m(int state_id);
int spm_run_rc_bus26m(unsigned int cpu, int state_id);
int spm_reset_rc_bus26m(unsigned int cpu, int state_id);
#endif /* MT_SPM_RC_INTERNAL_H */
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <mt_lp_rm.h>
#include <mt_spm.h>
#include <mt_spm_cond.h>
#include <mt_spm_constraint.h>
#include <mt_spm_conservation.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_notifier.h>
#include <mt_spm_rc_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_resource_req.h>
#include <mt_spm_suspend.h>
#include <plat_pm.h>
#include <plat_mtk_lpm.h>
#define CONSTRAINT_SYSPLL_ALLOW \
(MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
MT_RM_CONSTRAINT_ALLOW_VCORE_LP)
#define CONSTRAINT_SYSPLL_PCM_FLAG \
(SPM_FLAG_DISABLE_INFRA_PDN | \
SPM_FLAG_DISABLE_VCORE_DVS | \
SPM_FLAG_DISABLE_VCORE_DFS | \
SPM_FLAG_SRAM_SLEEP_CTRL | \
SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
SPM_FLAG_ENABLE_6315_CTRL | \
SPM_FLAG_USE_SRCCLKENO2)
#define CONSTRAINT_SYSPLL_PCM_FLAG1 0U
#define CONSTRAINT_SYSPLL_RESOURCE_REQ \
(MT_SPM_26M)
static struct mt_spm_cond_tables cond_syspll = {
.name = "syspll",
.table_cg = {
0x078BF1FC, /* MTCMOS1 */
0x080D8856, /* INFRA0 */
0x03AF9A00, /* INFRA1 */
0x86000640, /* INFRA2 */
0xC800C000, /* INFRA3 */
0x00000000, /* INFRA4 */
0x0000007C, /* INFRA5 */
0x280E0800, /* MMSYS0 */
0x00000001, /* MMSYS1 */
0x00000000, /* MMSYS2 */
},
.table_pll = 0U,
};
static struct mt_spm_cond_tables cond_syspll_res = {
.table_cg = { 0U },
.table_pll = 0U,
};
static struct constraint_status status = {
.id = MT_RM_CONSTRAINT_ID_SYSPLL,
.valid = (MT_SPM_RC_VALID_SW |
MT_SPM_RC_VALID_COND_LATCH |
MT_SPM_RC_VALID_XSOC_BBLPM),
.cond_block = 0U,
.enter_cnt = 0U,
.cond_res = &cond_syspll_res,
};
static void spm_syspll_conduct(struct spm_lp_scen *spm_lp,
unsigned int *resource_req)
{
spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG;
spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_SYSPLL_PCM_FLAG1;
*resource_req |= CONSTRAINT_SYSPLL_RESOURCE_REQ;
}
bool spm_is_valid_rc_syspll(unsigned int cpu, int state_id)
{
(void)cpu;
(void)state_id;
return (status.cond_block == 0U) && IS_MT_RM_RC_READY(status.valid);
}
int spm_update_rc_syspll(int state_id, int type, const void *val)
{
const struct mt_spm_cond_tables *tlb;
const struct mt_spm_cond_tables *tlb_check;
int res = MT_RM_STATUS_OK;
if (val == NULL) {
return MT_RM_STATUS_BAD;
}
if (type == PLAT_RC_UPDATE_CONDITION) {
tlb = (const struct mt_spm_cond_tables *)val;
tlb_check = (const struct mt_spm_cond_tables *)&cond_syspll;
status.cond_block =
mt_spm_cond_check(state_id, tlb, tlb_check,
((status.valid &
MT_SPM_RC_VALID_COND_LATCH) != 0U) ?
&cond_syspll_res : NULL);
} else {
res = MT_RM_STATUS_BAD;
}
return res;
}
unsigned int spm_allow_rc_syspll(int state_id)
{
(void)state_id;
return CONSTRAINT_SYSPLL_ALLOW;
}
int spm_run_rc_syspll(unsigned int cpu, int state_id)
{
unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
(void)cpu;
if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
#ifdef MT_SPM_USING_SRCLKEN_RC
ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
#else
allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
#endif
}
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, allows |
(IS_PLAT_SUSPEND_ID(state_id) ?
MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0U));
#else
(void)allows;
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_enter(state_id,
(MT_SPM_EX_OP_SET_WDT |
MT_SPM_EX_OP_HW_S1_DETECT |
MT_SPM_EX_OP_SET_SUSPEND_MODE),
CONSTRAINT_SYSPLL_RESOURCE_REQ);
} else {
mt_spm_idle_generic_enter(state_id, ext_op, spm_syspll_conduct);
}
return 0;
}
int spm_reset_rc_syspll(unsigned int cpu, int state_id)
{
unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
unsigned int allows = CONSTRAINT_SYSPLL_ALLOW;
(void)cpu;
if (IS_MT_SPM_RC_BBLPM_MODE(status.valid)) {
#ifdef MT_SPM_USING_SRCLKEN_RC
ext_op |= MT_SPM_EX_OP_SRCLKEN_RC_BBLPM;
#else
allows |= MT_RM_CONSTRAINT_ALLOW_BBLPM;
#endif
}
#ifndef ATF_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, allows);
#else
(void)allows;
#endif
if (IS_PLAT_SUSPEND_ID(state_id)) {
mt_spm_suspend_resume(state_id,
(MT_SPM_EX_OP_SET_SUSPEND_MODE |
MT_SPM_EX_OP_SET_WDT |
MT_SPM_EX_OP_HW_S1_DETECT),
NULL);
} else {
mt_spm_idle_generic_resume(state_id, ext_op, NULL);
status.enter_cnt++;
}
return 0;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <string.h>
#include <common/debug.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
#include <mt_lp_rm.h>
#include <mt_spm.h>
#include <mt_spm_cond.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <mt_spm_idle.h>
#include <mt_spm_internal.h>
#include <mt_spm_pmic_wrap.h>
#include <mt_spm_rc_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_resource_req.h>
#include <mt_spm_suspend.h>
#include <mtk_plat_common.h>
#include <plat_mtk_lpm.h>
#include <plat_pm.h>
#include <platform_def.h>
#include <sleep_def.h>
#ifdef MT_SPM_USING_BAKERY_LOCK
DEFINE_BAKERY_LOCK(spm_lock);
#define plat_spm_lock_init() bakery_lock_init(&spm_lock)
#else
spinlock_t spm_lock;
#define plat_spm_lock_init()
#endif
/* CLK_SCP_CFG_0 */
#define CLK_SCP_CFG_0 (TOPCKGEN_BASE + 0x200)
#define SPM_CK_CONTROL_EN 0x3FF
/* CLK_SCP_CFG_1 */
#define CLK_SCP_CFG_1 (TOPCKGEN_BASE + 0x210)
#define CLK_SCP_CFG_1_MASK 0x100C
#define CLK_SCP_CFG_1_SPM 0x3
struct mt_resource_constraint plat_constraint_bus26m = {
.is_valid = spm_is_valid_rc_bus26m,
.update = spm_update_rc_bus26m,
.allow = spm_allow_rc_bus26m,
.run = spm_run_rc_bus26m,
.reset = spm_reset_rc_bus26m,
};
struct mt_resource_constraint plat_constraint_syspll = {
.is_valid = spm_is_valid_rc_syspll,
.update = spm_update_rc_syspll,
.allow = spm_allow_rc_syspll,
.run = spm_run_rc_syspll,
.reset = spm_reset_rc_syspll,
};
struct mt_resource_constraint plat_constraint_dram = {
.is_valid = spm_is_valid_rc_dram,
.update = spm_update_rc_dram,
.allow = spm_allow_rc_dram,
.run = spm_run_rc_dram,
.reset = spm_reset_rc_dram,
};
struct mt_resource_constraint plat_constraint_cpu = {
.is_valid = spm_is_valid_rc_cpu_buck_ldo,
.update = NULL,
.allow = spm_allow_rc_cpu_buck_ldo,
.run = spm_run_rc_cpu_buck_ldo,
.reset = spm_reset_rc_cpu_buck_ldo,
};
struct mt_resource_constraint *plat_constraints[] = {
&plat_constraint_bus26m,
&plat_constraint_syspll,
&plat_constraint_dram,
&plat_constraint_cpu,
NULL,
};
struct mt_resource_manager plat_mt8192_rm = {
.update = mt_spm_cond_update,
.consts = plat_constraints,
};
void spm_boot_init(void)
{
/* switch ck_off/axi_26m control to SPM */
mmio_setbits_32(CLK_SCP_CFG_0, SPM_CK_CONTROL_EN);
mmio_clrsetbits_32(CLK_SCP_CFG_1, CLK_SCP_CFG_1_MASK,
CLK_SCP_CFG_1_SPM);
plat_spm_lock_init();
mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE);
mt_lp_rm_register(&plat_mt8192_rm);
mt_spm_idle_generic_init();
mt_spm_suspend_init();
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_H
#define MT_SPM_H
#include <lib/bakery_lock.h>
#include <lib/spinlock.h>
#include <plat_mtk_lpm.h>
/*
* ARM v8.2, the cache will turn off automatically when cpu
* power down. So, there is no doubt to use the spin_lock here
*/
#if !HW_ASSISTED_COHERENCY
#define MT_SPM_USING_BAKERY_LOCK
#endif
#ifdef MT_SPM_USING_BAKERY_LOCK
DECLARE_BAKERY_LOCK(spm_lock);
#define plat_spm_lock() bakery_lock_get(&spm_lock)
#define plat_spm_unlock() bakery_lock_release(&spm_lock)
#else
extern spinlock_t spm_lock;
#define plat_spm_lock() spin_lock(&spm_lock)
#define plat_spm_unlock() spin_unlock(&spm_lock)
#endif
#define MT_SPM_USING_SRCLKEN_RC
/* spm extern operand definition */
#define MT_SPM_EX_OP_CLR_26M_RECORD (1U << 0)
#define MT_SPM_EX_OP_SET_WDT (1U << 1)
#define MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ (1U << 2)
#define MT_SPM_EX_OP_SET_SUSPEND_MODE (1U << 3)
#define MT_SPM_EX_OP_SET_IS_ADSP (1U << 4)
#define MT_SPM_EX_OP_SRCLKEN_RC_BBLPM (1U << 5)
#define MT_SPM_EX_OP_HW_S1_DETECT (1U << 6)
typedef enum {
WR_NONE = 0,
WR_UART_BUSY = 1,
WR_ABORT = 2,
WR_PCM_TIMER = 3,
WR_WAKE_SRC = 4,
WR_DVFSRC = 5,
WR_TWAM = 6,
WR_PMSR = 7,
WR_SPM_ACK_CHK = 8,
WR_UNKNOWN = 9,
} wake_reason_t;
static inline void spm_lock_get(void)
{
plat_spm_lock();
}
static inline void spm_lock_release(void)
{
plat_spm_unlock();
}
extern void spm_boot_init(void);
#endif /* MT_SPM_H */
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <mt_spm_cond.h>
#include <mt_spm_conservation.h>
#include <mt_spm_constraint.h>
#include <plat_mtk_lpm.h>
#include <plat_pm.h>
#include <platform_def.h>
#define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs)
#define MT_LP_TZ_MM_REG(ofs) (MMSYS_BASE + ofs)
#define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs)
#define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs)
#define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs)
#define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C)
#define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170)
#define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0094)
#define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0090)
#define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC)
#define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8)
#define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00D8)
#define INFRA_SW_CG5 MT_LP_TZ_INFRA_REG(0x00E8)
#define MMSYS_CG_CON0 MT_LP_TZ_MM_REG(0x100)
#define MMSYS_CG_CON1 MT_LP_TZ_MM_REG(0x110)
#define MMSYS_CG_CON2 MT_LP_TZ_MM_REG(0x1A0)
/***********************************************************
* Check clkmux registers
***********************************************************/
#define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0x20 + id * 0x10)
#define PDN_CHECK BIT(7)
#define CLK_CHECK BIT(31)
enum {
CLKMUX_DISP = 0,
CLKMUX_MDP = 1,
CLKMUX_IMG1 = 2,
CLKMUX_IMG2 = 3,
NF_CLKMUX,
};
static bool is_clkmux_pdn(unsigned int clkmux_id)
{
unsigned int reg, val, idx;
if ((clkmux_id & CLK_CHECK) != 0U) {
clkmux_id = (clkmux_id & ~CLK_CHECK);
reg = clkmux_id / 4U;
val = mmio_read_32(CLK_CFG(reg));
idx = clkmux_id % 4U;
val = (val >> (idx * 8U)) & PDN_CHECK;
return (val != 0U);
}
return false;
}
static struct mt_spm_cond_tables spm_cond_t;
struct idle_cond_info {
unsigned int subsys_mask;
uintptr_t addr;
bool bBitflip;
unsigned int clkmux_id;
};
#define IDLE_CG(mask, addr, bitflip, clkmux) \
{mask, (uintptr_t)addr, bitflip, clkmux}
static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = {
IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U),
IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U),
IDLE_CG(0x00100000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)),
IDLE_CG(0x00100000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)),
IDLE_CG(0x00100000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)),
};
/***********************************************************
* Check pll idle condition
***********************************************************/
#define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x268)
#define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x360)
#define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x308)
#define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x350)
#define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x380)
unsigned int mt_spm_cond_check(int state_id,
const struct mt_spm_cond_tables *src,
const struct mt_spm_cond_tables *dest,
struct mt_spm_cond_tables *res)
{
unsigned int blocked = 0U, i;
bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
if ((src == NULL) || (dest == NULL)) {
return SPM_COND_CHECK_FAIL;
}
for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
if (res != NULL) {
res->table_cg[i] =
(src->table_cg[i] & dest->table_cg[i]);
if (is_system_suspend && (res->table_cg[i] != 0U)) {
INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n",
dest->name, i, idle_cg_info[i].addr,
res->table_cg[i]);
}
if (res->table_cg[i] != 0U) {
blocked |= (1U << i);
}
} else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
blocked |= (1U << i);
break;
}
}
if (res != NULL) {
res->table_pll = (src->table_pll & dest->table_pll);
if (res->table_pll != 0U) {
blocked |=
(res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
SPM_COND_CHECK_BLOCKED_PLL;
}
} else if ((src->table_pll & dest->table_pll) != 0U) {
blocked |= SPM_COND_CHECK_BLOCKED_PLL;
}
return blocked;
}
#define IS_MT_SPM_PWR_OFF(mask) \
(((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \
((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U))
int mt_spm_cond_update(struct mt_resource_constraint **con,
int stateid, void *priv)
{
int res;
uint32_t i;
struct mt_resource_constraint *const *rc;
/* read all cg state */
for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
spm_cond_t.table_cg[i] = 0U;
/* check mtcmos, if off set idle_value and clk to 0 disable */
if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
continue;
}
/* check clkmux */
if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
continue;
}
spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ?
~mmio_read_32(idle_cg_info[i].addr) :
mmio_read_32(idle_cg_info[i].addr);
}
spm_cond_t.table_pll = 0U;
if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) {
spm_cond_t.table_pll |= PLL_BIT_MFGPLL;
}
if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) {
spm_cond_t.table_pll |= PLL_BIT_MMPLL;
}
if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) {
spm_cond_t.table_pll |= PLL_BIT_UNIVPLL;
}
if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) {
spm_cond_t.table_pll |= PLL_BIT_MSDCPLL;
}
if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) {
spm_cond_t.table_pll |= PLL_BIT_TVDPLL;
}
spm_cond_t.priv = priv;
for (rc = con; *rc != NULL; rc++) {
if (((*rc)->update) == NULL) {
continue;
}
res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION,
(void const *)&spm_cond_t);
if (res != MT_RM_STATUS_OK) {
break;
}
}
return 0;
}
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MT_SPM_CONDIT_H
#define MT_SPM_CONDIT_H
#include <mt_lp_rm.h>
enum PLAT_SPM_COND {
PLAT_SPM_COND_MTCMOS1 = 0,
PLAT_SPM_COND_CG_INFRA_0,
PLAT_SPM_COND_CG_INFRA_1,
PLAT_SPM_COND_CG_INFRA_2,
PLAT_SPM_COND_CG_INFRA_3,
PLAT_SPM_COND_CG_INFRA_4,
PLAT_SPM_COND_CG_INFRA_5,
PLAT_SPM_COND_CG_MMSYS_0,
PLAT_SPM_COND_CG_MMSYS_1,
PLAT_SPM_COND_CG_MMSYS_2,
PLAT_SPM_COND_MAX,
};
enum PLAT_SPM_COND_PLL {
PLAT_SPM_COND_PLL_UNIVPLL = 0,
PLAT_SPM_COND_PLL_MFGPLL,
PLAT_SPM_COND_PLL_MSDCPLL,
PLAT_SPM_COND_PLL_TVDPLL,
PLAT_SPM_COND_PLL_MMPLL,
PLAT_SPM_COND_PLL_MAX,
};
#define PLL_BIT_MFGPLL (PLAT_SPM_COND_PLL_MFGPLL)
#define PLL_BIT_MMPLL (PLAT_SPM_COND_PLL_MMPLL)
#define PLL_BIT_UNIVPLL (PLAT_SPM_COND_PLL_UNIVPLL)
#define PLL_BIT_MSDCPLL (PLAT_SPM_COND_PLL_MSDCPLL)
#define PLL_BIT_TVDPLL (PLAT_SPM_COND_PLL_TVDPLL)
/* Definition about SPM_COND_CHECK_BLOCKED
* bit [00 ~ 15]: cg blocking index
* bit [16 ~ 29]: pll blocking index
* bit [30] : pll blocking information
* bit [31] : idle condition check fail
*/
#define SPM_COND_BLOCKED_CG_IDX U(0)
#define SPM_COND_BLOCKED_PLL_IDX U(16)
#define SPM_COND_CHECK_BLOCKED_PLL BIT(30)
#define SPM_COND_CHECK_FAIL BIT(31)
struct mt_spm_cond_tables {
char *name;
unsigned int table_cg[PLAT_SPM_COND_MAX];
unsigned int table_pll;
void *priv;
};
extern unsigned int mt_spm_cond_check(int state_id,
const struct mt_spm_cond_tables *src,
const struct mt_spm_cond_tables *dest,
struct mt_spm_cond_tables *res);
extern int mt_spm_cond_update(struct mt_resource_constraint **con,
int stateid, void *priv);
#endif /* MT_SPM_CONDIT_H */
/*
* Copyright (c) 2020, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <mt_spm.h>
#include <mt_spm_conservation.h>
#include <mt_spm_internal.h>
#include <mt_spm_reg.h>
#include <mt_spm_vcorefs.h>
#include <plat_mtk_lpm.h>
#include <plat_pm.h>
#include <plat/common/platform.h>
#include <platform_def.h>
struct wake_status spm_wakesta; /* record last wakesta */
static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
struct spm_lp_scen *spm_lp,
unsigned int resource_req)
{
int ret = 0;
struct pwr_ctrl *pwrctrl;
uint32_t cpu = plat_my_core_pos();
pwrctrl = spm_lp->pwrctrl;
__spm_set_cpu_status(cpu);
__spm_set_power_control(pwrctrl);
__spm_set_wakeup_event(pwrctrl);
__spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
__spm_set_pcm_flags(pwrctrl);
__spm_src_req_update(pwrctrl, resource_req);
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
__spm_set_pcm_wdt(1);
}
if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
__spm_xo_soc_bblpm(1);
}
if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
spm_hw_s1_state_monitor_resume();
}
/* Disable auto resume by PCM in system suspend stage */
if (IS_PLAT_SUSPEND_ID(state_id)) {
__spm_disable_pcm_timer();
__spm_set_pcm_wdt(0);
}
__spm_send_cpu_wakeup_event();
INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
mmio_read_32(PCM_TIMER_VAL) / 32768);
INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
mmio_read_32(PWR_STATUS_2ND));
return ret;
}
static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
struct spm_lp_scen *spm_lp,
struct wake_status **status)
{
unsigned int ext_status = 0U;
/* system watchdog will be resumed at kernel stage */
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
__spm_set_pcm_wdt(0);
}
if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
__spm_xo_soc_bblpm(0);
}
if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
spm_hw_s1_state_monitor_pause(&ext_status);
}
__spm_ext_int_wakeup_req_clr();
__spm_get_wakeup_status(&spm_wakesta, ext_status);
if (status != NULL) {
*status = &spm_wakesta;
}
__spm_clean_after_wakeup();
if (IS_PLAT_SUSPEND_ID(state_id)) {
__spm_output_wake_reason(state_id, &spm_wakesta);
}
}
int spm_conservation(int state_id, unsigned int ext_opand,
struct spm_lp_scen *spm_lp, unsigned int resource_req)
{
if (spm_lp == NULL) {
return -1;
}
spm_lock_get();
go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
spm_lock_release();
return 0;
}
void spm_conservation_finish(int state_id, unsigned int ext_opand,
struct spm_lp_scen *spm_lp,
struct wake_status **status)
{
spm_lock_get();
go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
spm_lock_release();
}
int spm_conservation_get_result(struct wake_status **res)
{
if (res == NULL) {
return -1;
}
*res = &spm_wakesta;
return 0;
}
#define GPIO_BANK (GPIO_BASE + 0x6F0)
#define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
{
if (pwrctrl == NULL) {
return;
}
/* For ufs, emmc storage type */
if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
/* If eMMC is used, mask UFS req */
pwrctrl->reg_ufs_srcclkena_mask_b = 0;
pwrctrl->reg_ufs_infra_req_mask_b = 0;
pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
pwrctrl->reg_ufs_ddr_en_mask_b = 0;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment