xref: /rk3399_ARM-atf/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.c (revision 7d196ded502d49a2c170fc0f30c8f4b94584d5fe)
13ee4b2deSKarl Li /*
23ee4b2deSKarl Li  * Copyright (c) 2024, MediaTek Inc. All rights reserved.
33ee4b2deSKarl Li  *
43ee4b2deSKarl Li  * SPDX-License-Identifier: BSD-3-Clause
53ee4b2deSKarl Li  */
63ee4b2deSKarl Li 
73ee4b2deSKarl Li #include <errno.h>
83ee4b2deSKarl Li 
93ee4b2deSKarl Li #include <common/debug.h>
103ee4b2deSKarl Li #include <drivers/delay_timer.h>
113ee4b2deSKarl Li #include <lib/mmio.h>
123ee4b2deSKarl Li 
133ee4b2deSKarl Li #include "apusys_power.h"
143ee4b2deSKarl Li #include "apusys_rv.h"
153ee4b2deSKarl Li #include "apusys_rv_pwr_ctrl.h"
163ee4b2deSKarl Li 
173ee4b2deSKarl Li #define RPC_POWER_OFF_TIMEOUT_CNT	(100000) /* 100ms */
183ee4b2deSKarl Li 
wait_for_state_ready(uint32_t reg,uint32_t mask,uint32_t expect,uint32_t retry_times,uint32_t set_reg,uint32_t set_val)193ee4b2deSKarl Li static int wait_for_state_ready(uint32_t reg, uint32_t mask, uint32_t expect,
203ee4b2deSKarl Li 				uint32_t retry_times, uint32_t set_reg, uint32_t set_val)
213ee4b2deSKarl Li {
223ee4b2deSKarl Li 	uint32_t count = 0;
233ee4b2deSKarl Li 
243ee4b2deSKarl Li 	while ((mmio_read_32(reg) & mask) != expect) {
25*1ba50c33SChungying Lu 		/*
26*1ba50c33SChungying Lu 		 * If retry_times == HW_SEM_NO_WAIT, it is just for checking if the hardware
27*1ba50c33SChungying Lu 		 * semaphore can be locked or not. The purpose is for SMMU to check NPU power
28*1ba50c33SChungying Lu 		 * status. Hence, just returning -EBUSY is okay. There is no need to show any
29*1ba50c33SChungying Lu 		 * ERROR message here.
30*1ba50c33SChungying Lu 		 */
31*1ba50c33SChungying Lu 		if (retry_times == HW_SEM_NO_WAIT) {
32*1ba50c33SChungying Lu 			return -EBUSY;
33*1ba50c33SChungying Lu 		} else if (count > retry_times) {
343ee4b2deSKarl Li 			ERROR("%s: timed out, reg = %x, mask = %x, expect = %x\n",
353ee4b2deSKarl Li 			       __func__, reg, mask, expect);
363ee4b2deSKarl Li 			return -EBUSY;
373ee4b2deSKarl Li 		}
383ee4b2deSKarl Li 		count += 1;
393ee4b2deSKarl Li 
403ee4b2deSKarl Li 		if (set_reg)
413ee4b2deSKarl Li 			mmio_write_32(set_reg, set_val);
423ee4b2deSKarl Li 		udelay(1);
433ee4b2deSKarl Li 	}
443ee4b2deSKarl Li 
453ee4b2deSKarl Li 	return 0;
463ee4b2deSKarl Li }
473ee4b2deSKarl Li 
apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr,uint32_t sem_sta_addr,uint8_t usr_bit,enum apu_hw_sem_op ctl,uint32_t timeout,uint8_t bypass)483ee4b2deSKarl Li int apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr, uint32_t sem_sta_addr,
493ee4b2deSKarl Li 			     uint8_t usr_bit, enum apu_hw_sem_op ctl, uint32_t timeout,
503ee4b2deSKarl Li 			     uint8_t bypass)
513ee4b2deSKarl Li {
523ee4b2deSKarl Li 	int ret;
533ee4b2deSKarl Li 	uint8_t ctl_bit = 0;
543ee4b2deSKarl Li 
553ee4b2deSKarl Li 	if (ctl == HW_SEM_GET)
563ee4b2deSKarl Li 		ctl_bit = 0x1;
573ee4b2deSKarl Li 	else if (ctl == HW_SEM_PUT)
583ee4b2deSKarl Li 		ctl_bit = 0x2;
593ee4b2deSKarl Li 	else
603ee4b2deSKarl Li 		return -EINVAL;
613ee4b2deSKarl Li 
623ee4b2deSKarl Li 	/* return fail if semaphore is currently not held by this user */
633ee4b2deSKarl Li 	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_sta_addr) & BIT(usr_bit)) == 0)
643ee4b2deSKarl Li 	    && !bypass) {
653ee4b2deSKarl Li 		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
663ee4b2deSKarl Li 		       __func__, usr_bit, ctl, sem_sta_addr, mmio_read_32(sem_sta_addr));
673ee4b2deSKarl Li 		return -EINVAL;
683ee4b2deSKarl Li 	}
693ee4b2deSKarl Li 
703ee4b2deSKarl Li 	mmio_write_32(sem_ctrl_addr, ctl_bit);
713ee4b2deSKarl Li 
723ee4b2deSKarl Li 	if (ctl == HW_SEM_PUT)
733ee4b2deSKarl Li 		return 0;
743ee4b2deSKarl Li 
753ee4b2deSKarl Li 	ret = wait_for_state_ready(sem_sta_addr, BIT(usr_bit), BIT(usr_bit), timeout,
763ee4b2deSKarl Li 				   sem_ctrl_addr, ctl_bit);
773ee4b2deSKarl Li 	if (ret)
783ee4b2deSKarl Li 		return ret;
793ee4b2deSKarl Li 
803ee4b2deSKarl Li 	return 0;
813ee4b2deSKarl Li }
823ee4b2deSKarl Li 
apusys_rv_pwr_ctrl(enum APU_PWR_OP op)833ee4b2deSKarl Li int apusys_rv_pwr_ctrl(enum APU_PWR_OP op)
843ee4b2deSKarl Li {
853ee4b2deSKarl Li 	int ret;
863ee4b2deSKarl Li 	uint32_t global_ref_cnt;
873ee4b2deSKarl Li 
883ee4b2deSKarl Li 	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
893ee4b2deSKarl Li 				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
903ee4b2deSKarl Li 				       APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_TIMEOUT, 0);
913ee4b2deSKarl Li 
923ee4b2deSKarl Li 	if (ret) {
933ee4b2deSKarl Li 		ERROR("%s(%d): sem acquire timeout\n", __func__, op);
943ee4b2deSKarl Li 		return ret;
953ee4b2deSKarl Li 	}
963ee4b2deSKarl Li 
973ee4b2deSKarl Li 	global_ref_cnt = mmio_read_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY);
983ee4b2deSKarl Li 
993ee4b2deSKarl Li 	if (global_ref_cnt > 2) {
1003ee4b2deSKarl Li 		ERROR("%s: global_ref_cnt(%d) > 2\n", __func__, global_ref_cnt);
1013ee4b2deSKarl Li 	} else if (op == APU_PWR_OFF) {
1023ee4b2deSKarl Li 		global_ref_cnt--;
1033ee4b2deSKarl Li 		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
1043ee4b2deSKarl Li 		if (global_ref_cnt == 0)
1053ee4b2deSKarl Li 			mmio_write_32(APU_MBOX_WKUP_CFG(11), 0);
1063ee4b2deSKarl Li 	} else if (op == APU_PWR_ON) {
1073ee4b2deSKarl Li 		global_ref_cnt++;
1083ee4b2deSKarl Li 		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
1093ee4b2deSKarl Li 		if (global_ref_cnt == 1)
1103ee4b2deSKarl Li 			mmio_write_32(APU_MBOX_WKUP_CFG(11), 1);
1113ee4b2deSKarl Li 	}
1123ee4b2deSKarl Li 
1133ee4b2deSKarl Li 	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
1143ee4b2deSKarl Li 				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
1153ee4b2deSKarl Li 				       APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_TIMEOUT, 0);
1163ee4b2deSKarl Li 
1173ee4b2deSKarl Li 	if (ret)
1183ee4b2deSKarl Li 		ERROR("%s(%d): sem release timeout\n", __func__, op);
1193ee4b2deSKarl Li 
1203ee4b2deSKarl Li 	return ret;
1213ee4b2deSKarl Li }
1223ee4b2deSKarl Li 
rv_iommu_hw_sem_trylock(void)1233ee4b2deSKarl Li int rv_iommu_hw_sem_trylock(void)
1243ee4b2deSKarl Li {
1253ee4b2deSKarl Li 	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
1263ee4b2deSKarl Li 					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
127*1ba50c33SChungying Lu 					APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_NO_WAIT, 0);
1283ee4b2deSKarl Li }
1293ee4b2deSKarl Li 
rv_iommu_hw_sem_unlock(void)1303ee4b2deSKarl Li int rv_iommu_hw_sem_unlock(void)
1313ee4b2deSKarl Li {
1323ee4b2deSKarl Li 	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
1333ee4b2deSKarl Li 					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
134*1ba50c33SChungying Lu 					APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_NO_WAIT, 0);
1353ee4b2deSKarl Li }
1363ee4b2deSKarl Li 
apu_hw_sema_ctl(uint32_t sem_addr,uint8_t usr_bit,uint8_t ctl,uint32_t timeout,uint8_t bypass)1373ee4b2deSKarl Li int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout,
1383ee4b2deSKarl Li 		    uint8_t bypass)
1393ee4b2deSKarl Li {
1403ee4b2deSKarl Li 	int ret;
1413ee4b2deSKarl Li 	uint8_t ctl_bit = 0;
1423ee4b2deSKarl Li 
1433ee4b2deSKarl Li 	if (ctl == HW_SEM_GET)
1443ee4b2deSKarl Li 		ctl_bit = usr_bit;
1453ee4b2deSKarl Li 	else if (ctl == HW_SEM_PUT)
1463ee4b2deSKarl Li 		ctl_bit = usr_bit + HW_SEM_PUT_BIT_SHIFT;
1473ee4b2deSKarl Li 	else
1483ee4b2deSKarl Li 		return -EINVAL;
1493ee4b2deSKarl Li 
1503ee4b2deSKarl Li 	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_addr) & BIT(ctl_bit)) == 0) && !bypass) {
1513ee4b2deSKarl Li 		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
1523ee4b2deSKarl Li 		       __func__, usr_bit, ctl, sem_addr, mmio_read_32(sem_addr));
1533ee4b2deSKarl Li 		return -EINVAL;
1543ee4b2deSKarl Li 	}
1553ee4b2deSKarl Li 
1563ee4b2deSKarl Li 	mmio_write_32(sem_addr, BIT(ctl_bit));
1573ee4b2deSKarl Li 
1583ee4b2deSKarl Li 	if (ctl == HW_SEM_PUT)
1593ee4b2deSKarl Li 		goto end;
1603ee4b2deSKarl Li 
1613ee4b2deSKarl Li 	ret = wait_for_state_ready(sem_addr, BIT(ctl_bit), BIT(ctl_bit), timeout,
1623ee4b2deSKarl Li 				   sem_addr, BIT(ctl_bit));
1633ee4b2deSKarl Li 	if (ret)
1643ee4b2deSKarl Li 		return ret;
1653ee4b2deSKarl Li 
1663ee4b2deSKarl Li end:
1673ee4b2deSKarl Li 	VERBOSE("%s: sem_addr = 0x%x, usr_bit: %d, ctl: %d, sem_addr = 0x%08x\n",
1683ee4b2deSKarl Li 		 __func__, sem_addr, usr_bit, ctl, mmio_read_32(sem_addr));
1693ee4b2deSKarl Li 
1703ee4b2deSKarl Li 	return 0;
1713ee4b2deSKarl Li }
1723ee4b2deSKarl Li 
apusys_infra_dcm_setup(void)1733ee4b2deSKarl Li int apusys_infra_dcm_setup(void)
1743ee4b2deSKarl Li {
1753ee4b2deSKarl Li 	mmio_write_32(APU_REG_AO_GLUE_CONFG,
1763ee4b2deSKarl Li 		      mmio_read_32(APU_REG_AO_GLUE_CONFG) | BIT(24) | BIT(26));
1773ee4b2deSKarl Li 
1783ee4b2deSKarl Li 	return 0;
1793ee4b2deSKarl Li }
180