xref: /rk3399_ARM-atf/plat/mediatek/mt8186/drivers/spm/mt_spm_cond.c (revision 79c262327aa8ccc1ae5a0ee7f7ead3bf5ce8e022)
17ac6a76cSjason-ch chen /*
2*b0208c73SLiju-Clr Chen  * Copyright (c) 2022-2023, MediaTek Inc. All rights reserved.
37ac6a76cSjason-ch chen  *
47ac6a76cSjason-ch chen  * SPDX-License-Identifier: BSD-3-Clause
57ac6a76cSjason-ch chen  */
67ac6a76cSjason-ch chen 
77ac6a76cSjason-ch chen #include <stdbool.h>
87ac6a76cSjason-ch chen #include <common/debug.h>
97ac6a76cSjason-ch chen #include <lib/mmio.h>
107ac6a76cSjason-ch chen #include <mt_spm_cond.h>
117ac6a76cSjason-ch chen #include <mt_spm_conservation.h>
127ac6a76cSjason-ch chen #include <mt_spm_constraint.h>
137ac6a76cSjason-ch chen #include <plat_mtk_lpm.h>
147ac6a76cSjason-ch chen #include <plat_pm.h>
157ac6a76cSjason-ch chen #include <platform_def.h>
167ac6a76cSjason-ch chen 
177ac6a76cSjason-ch chen #define MT_LP_TZ_INFRA_REG(ofs)		(INFRACFG_AO_BASE + ofs)
187ac6a76cSjason-ch chen #define MT_LP_TZ_MM_REG(ofs)		(MMSYS_BASE + ofs)
197ac6a76cSjason-ch chen #define MT_LP_TZ_MDP_REG(ofs)		(MDPSYS_BASE + ofs)
207ac6a76cSjason-ch chen #define MT_LP_TZ_SPM_REG(ofs)		(SPM_BASE + ofs)
217ac6a76cSjason-ch chen #define MT_LP_TZ_TOPCK_REG(ofs)		(TOPCKGEN_BASE + ofs)
227ac6a76cSjason-ch chen #define MT_LP_TZ_APMIXEDSYS(ofs)	(APMIXEDSYS + ofs)
237ac6a76cSjason-ch chen 
247ac6a76cSjason-ch chen #define SPM_PWR_STATUS			MT_LP_TZ_SPM_REG(0x016C)
257ac6a76cSjason-ch chen #define SPM_PWR_STATUS_2ND		MT_LP_TZ_SPM_REG(0x0170)
267ac6a76cSjason-ch chen #define	INFRA_SW_CG0			MT_LP_TZ_INFRA_REG(0x0090)
277ac6a76cSjason-ch chen #define	INFRA_SW_CG1			MT_LP_TZ_INFRA_REG(0x0094)
287ac6a76cSjason-ch chen #define	INFRA_SW_CG2			MT_LP_TZ_INFRA_REG(0x00AC)
297ac6a76cSjason-ch chen #define	INFRA_SW_CG3			MT_LP_TZ_INFRA_REG(0x00C8)
307ac6a76cSjason-ch chen #define INFRA_SW_CG4                    MT_LP_TZ_INFRA_REG(0x00E8)
317ac6a76cSjason-ch chen #define INFRA_SW_CG5                    MT_LP_TZ_INFRA_REG(0x00D8)
327ac6a76cSjason-ch chen #define MMSYS_CG_CON0			MT_LP_TZ_MM_REG(0x100)
337ac6a76cSjason-ch chen #define MMSYS_CG_CON1			MT_LP_TZ_MM_REG(0x110)
347ac6a76cSjason-ch chen #define MMSYS_CG_CON2                   MT_LP_TZ_MM_REG(0x1A0)
357ac6a76cSjason-ch chen #define MMSYS_CG_CON3			MT_LP_TZ_MDP_REG(0x100)
367ac6a76cSjason-ch chen 
377ac6a76cSjason-ch chen /* Check clkmux registers */
387ac6a76cSjason-ch chen #define CLK_CFG(id)    MT_LP_TZ_TOPCK_REG(0xe0 + id * 0x10)
397ac6a76cSjason-ch chen #define CLK_CHECK      BIT(31)
407ac6a76cSjason-ch chen 
417ac6a76cSjason-ch chen enum {
427ac6a76cSjason-ch chen 	CLKMUX_DISP  = 0,
437ac6a76cSjason-ch chen 	CLKMUX_MDP   = 1,
447ac6a76cSjason-ch chen 	CLKMUX_IMG1  = 2,
457ac6a76cSjason-ch chen 	CLKMUX_IMG2  = 3,
467ac6a76cSjason-ch chen 	NF_CLKMUX    = 4,
477ac6a76cSjason-ch chen };
487ac6a76cSjason-ch chen 
is_clkmux_pdn(unsigned int clkmux_id)497ac6a76cSjason-ch chen static bool is_clkmux_pdn(unsigned int clkmux_id)
507ac6a76cSjason-ch chen {
517ac6a76cSjason-ch chen 	unsigned int reg, val, idx;
527ac6a76cSjason-ch chen 	bool ret = false;
537ac6a76cSjason-ch chen 
547ac6a76cSjason-ch chen 	if (clkmux_id & CLK_CHECK) {
557ac6a76cSjason-ch chen 		clkmux_id = (clkmux_id & ~CLK_CHECK);
567ac6a76cSjason-ch chen 		reg = clkmux_id / 4U;
577ac6a76cSjason-ch chen 		val = mmio_read_32(CLK_CFG(reg));
587ac6a76cSjason-ch chen 		idx = clkmux_id % 4U;
597ac6a76cSjason-ch chen 		ret = (((val >> (idx * 8U)) & 0x80) != 0U);
607ac6a76cSjason-ch chen 	}
617ac6a76cSjason-ch chen 
627ac6a76cSjason-ch chen 	return ret;
637ac6a76cSjason-ch chen }
647ac6a76cSjason-ch chen 
657ac6a76cSjason-ch chen static struct mt_spm_cond_tables spm_cond_t;
667ac6a76cSjason-ch chen 
677ac6a76cSjason-ch chen struct idle_cond_info {
687ac6a76cSjason-ch chen 	unsigned int subsys_mask;
697ac6a76cSjason-ch chen 	uintptr_t addr;
707ac6a76cSjason-ch chen 	bool bit_flip;
717ac6a76cSjason-ch chen 	unsigned int clkmux_id;
727ac6a76cSjason-ch chen };
737ac6a76cSjason-ch chen 
747ac6a76cSjason-ch chen #define IDLE_CG(mask, addr, bitflip, clkmux)	\
757ac6a76cSjason-ch chen 	{mask, (uintptr_t)addr, bitflip, clkmux}
767ac6a76cSjason-ch chen 
777ac6a76cSjason-ch chen static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = {
787ac6a76cSjason-ch chen 	IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U),
797ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U),
807ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U),
817ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U),
827ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U),
837ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U),
847ac6a76cSjason-ch chen 	IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U),
857ac6a76cSjason-ch chen 	IDLE_CG(0x00200000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)),
867ac6a76cSjason-ch chen 	IDLE_CG(0x00200000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)),
877ac6a76cSjason-ch chen 	IDLE_CG(0x00200000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)),
887ac6a76cSjason-ch chen 	IDLE_CG(0x00200000, MMSYS_CG_CON3, true, (CLK_CHECK | CLKMUX_MDP)),
897ac6a76cSjason-ch chen };
907ac6a76cSjason-ch chen 
917ac6a76cSjason-ch chen /* Check pll idle condition */
927ac6a76cSjason-ch chen #define PLL_MFGPLL	MT_LP_TZ_APMIXEDSYS(0x314)
937ac6a76cSjason-ch chen #define PLL_MMPLL	MT_LP_TZ_APMIXEDSYS(0x254)
947ac6a76cSjason-ch chen #define PLL_UNIVPLL	MT_LP_TZ_APMIXEDSYS(0x324)
957ac6a76cSjason-ch chen #define PLL_MSDCPLL	MT_LP_TZ_APMIXEDSYS(0x38c)
967ac6a76cSjason-ch chen #define PLL_TVDPLL	MT_LP_TZ_APMIXEDSYS(0x264)
977ac6a76cSjason-ch chen 
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)987ac6a76cSjason-ch chen unsigned int mt_spm_cond_check(int state_id,
997ac6a76cSjason-ch chen 			       const struct mt_spm_cond_tables *src,
1007ac6a76cSjason-ch chen 			       const struct mt_spm_cond_tables *dest,
1017ac6a76cSjason-ch chen 			       struct mt_spm_cond_tables *res)
1027ac6a76cSjason-ch chen {
1037ac6a76cSjason-ch chen 	unsigned int blocked = 0U;
1047ac6a76cSjason-ch chen 	unsigned int i;
1057ac6a76cSjason-ch chen 	bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
1067ac6a76cSjason-ch chen 
1077ac6a76cSjason-ch chen 	if ((src == NULL) || (dest == NULL)) {
1087ac6a76cSjason-ch chen 		blocked = SPM_COND_CHECK_FAIL;
1097ac6a76cSjason-ch chen 	} else {
1107ac6a76cSjason-ch chen 		for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
1117ac6a76cSjason-ch chen 			if (res != NULL) {
1127ac6a76cSjason-ch chen 				res->table_cg[i] = (src->table_cg[i] & dest->table_cg[i]);
1137ac6a76cSjason-ch chen 				if (is_system_suspend && ((res->table_cg[i]) != 0U)) {
1147ac6a76cSjason-ch chen 					INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n",
1157ac6a76cSjason-ch chen 					     dest->name, i, idle_cg_info[i].addr,
1167ac6a76cSjason-ch chen 					     res->table_cg[i]);
1177ac6a76cSjason-ch chen 				}
1187ac6a76cSjason-ch chen 
1197ac6a76cSjason-ch chen 				if ((res->table_cg[i]) != 0U) {
1207ac6a76cSjason-ch chen 					blocked |= BIT(i);
1217ac6a76cSjason-ch chen 				}
1227ac6a76cSjason-ch chen 			} else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
1237ac6a76cSjason-ch chen 				blocked |= BIT(i);
1247ac6a76cSjason-ch chen 				break;
1257ac6a76cSjason-ch chen 			}
1267ac6a76cSjason-ch chen 		}
1277ac6a76cSjason-ch chen 
1287ac6a76cSjason-ch chen 		if (res != NULL) {
1297ac6a76cSjason-ch chen 			res->table_pll = (src->table_pll & dest->table_pll);
1307ac6a76cSjason-ch chen 
1317ac6a76cSjason-ch chen 			if (res->table_pll != 0U) {
1327ac6a76cSjason-ch chen 				blocked |= (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
1337ac6a76cSjason-ch chen 					    SPM_COND_CHECK_BLOCKED_PLL;
1347ac6a76cSjason-ch chen 			}
1357ac6a76cSjason-ch chen 		} else if ((src->table_pll & dest->table_pll) != 0U) {
1367ac6a76cSjason-ch chen 			blocked |= SPM_COND_CHECK_BLOCKED_PLL;
1377ac6a76cSjason-ch chen 		}
1387ac6a76cSjason-ch chen 
1397ac6a76cSjason-ch chen 		if (is_system_suspend && ((blocked) != 0U)) {
1407ac6a76cSjason-ch chen 			INFO("suspend: %s total blocked = 0x%08x\n", dest->name, blocked);
1417ac6a76cSjason-ch chen 		}
1427ac6a76cSjason-ch chen 	}
1437ac6a76cSjason-ch chen 
1447ac6a76cSjason-ch chen 	return blocked;
1457ac6a76cSjason-ch chen }
1467ac6a76cSjason-ch chen 
1477ac6a76cSjason-ch chen #define IS_MT_SPM_PWR_OFF(mask)					\
1487ac6a76cSjason-ch chen 	(((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) &&	\
1497ac6a76cSjason-ch chen 	 ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U))
1507ac6a76cSjason-ch chen 
mt_spm_cond_update(struct mt_resource_constraint ** con,unsigned int num,int stateid,void * priv)151*b0208c73SLiju-Clr Chen int mt_spm_cond_update(struct mt_resource_constraint **con, unsigned int num,
152*b0208c73SLiju-Clr Chen 		       int stateid, void *priv)
1537ac6a76cSjason-ch chen {
1547ac6a76cSjason-ch chen 	int res;
1557ac6a76cSjason-ch chen 	uint32_t i;
1567ac6a76cSjason-ch chen 	struct mt_resource_constraint *const *rc;
1577ac6a76cSjason-ch chen 
1587ac6a76cSjason-ch chen 	/* read all cg state */
1597ac6a76cSjason-ch chen 	for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
1607ac6a76cSjason-ch chen 		spm_cond_t.table_cg[i] = 0U;
1617ac6a76cSjason-ch chen 
1627ac6a76cSjason-ch chen 		/* check mtcmos, if off set idle_value and clk to 0 disable */
1637ac6a76cSjason-ch chen 		if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
1647ac6a76cSjason-ch chen 			continue;
1657ac6a76cSjason-ch chen 		}
1667ac6a76cSjason-ch chen 
1677ac6a76cSjason-ch chen 		/* check clkmux */
1687ac6a76cSjason-ch chen 		if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
1697ac6a76cSjason-ch chen 			continue;
1707ac6a76cSjason-ch chen 		}
1717ac6a76cSjason-ch chen 
1727ac6a76cSjason-ch chen 		spm_cond_t.table_cg[i] = idle_cg_info[i].bit_flip ?
1737ac6a76cSjason-ch chen 					 ~mmio_read_32(idle_cg_info[i].addr) :
1747ac6a76cSjason-ch chen 					 mmio_read_32(idle_cg_info[i].addr);
1757ac6a76cSjason-ch chen 	}
1767ac6a76cSjason-ch chen 
1777ac6a76cSjason-ch chen 	spm_cond_t.table_pll = 0U;
1787ac6a76cSjason-ch chen 	if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) {
1797ac6a76cSjason-ch chen 		spm_cond_t.table_pll |= PLL_BIT_MFGPLL;
1807ac6a76cSjason-ch chen 	}
1817ac6a76cSjason-ch chen 
1827ac6a76cSjason-ch chen 	if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) {
1837ac6a76cSjason-ch chen 		spm_cond_t.table_pll |= PLL_BIT_MMPLL;
1847ac6a76cSjason-ch chen 	}
1857ac6a76cSjason-ch chen 
1867ac6a76cSjason-ch chen 	if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) {
1877ac6a76cSjason-ch chen 		spm_cond_t.table_pll |= PLL_BIT_UNIVPLL;
1887ac6a76cSjason-ch chen 	}
1897ac6a76cSjason-ch chen 
1907ac6a76cSjason-ch chen 	if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) {
1917ac6a76cSjason-ch chen 		spm_cond_t.table_pll |= PLL_BIT_MSDCPLL;
1927ac6a76cSjason-ch chen 	}
1937ac6a76cSjason-ch chen 
1947ac6a76cSjason-ch chen 	if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) {
1957ac6a76cSjason-ch chen 		spm_cond_t.table_pll |= PLL_BIT_TVDPLL;
1967ac6a76cSjason-ch chen 	}
1977ac6a76cSjason-ch chen 
1987ac6a76cSjason-ch chen 	spm_cond_t.priv = priv;
1997ac6a76cSjason-ch chen 
2007ac6a76cSjason-ch chen 	for (rc = con; *rc != NULL; rc++) {
2017ac6a76cSjason-ch chen 		if (((*rc)->update) == NULL) {
2027ac6a76cSjason-ch chen 			continue;
2037ac6a76cSjason-ch chen 		}
2047ac6a76cSjason-ch chen 
2057ac6a76cSjason-ch chen 		res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION,
2067ac6a76cSjason-ch chen 				    (void const *)&spm_cond_t);
2077ac6a76cSjason-ch chen 		if (res != MT_RM_STATUS_OK) {
2087ac6a76cSjason-ch chen 			break;
2097ac6a76cSjason-ch chen 		}
2107ac6a76cSjason-ch chen 	}
2117ac6a76cSjason-ch chen 
2127ac6a76cSjason-ch chen 	return 0;
2137ac6a76cSjason-ch chen }
214