xref: /rk3399_ARM-atf/plat/mediatek/drivers/apusys/mt8196/apusys_rv_pwr_ctrl.c (revision 05d22c3045e2e972c2262b9ccd6c82cb7545bf83)
1 /*
2  * Copyright (c) 2024, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 
9 #include <common/debug.h>
10 #include <drivers/delay_timer.h>
11 #include <lib/mmio.h>
12 
13 #include "apusys_power.h"
14 #include "apusys_rv.h"
15 #include "apusys_rv_pwr_ctrl.h"
16 
17 #define RPC_POWER_OFF_TIMEOUT_CNT	(100000) /* 100ms */
18 
19 static int wait_for_state_ready(uint32_t reg, uint32_t mask, uint32_t expect,
20 				uint32_t retry_times, uint32_t set_reg, uint32_t set_val)
21 {
22 	uint32_t count = 0;
23 
24 	while ((mmio_read_32(reg) & mask) != expect) {
25 		/*
26 		 * If retry_times == HW_SEM_NO_WAIT, it is just for checking if the hardware
27 		 * semaphore can be locked or not. The purpose is for SMMU to check NPU power
28 		 * status. Hence, just returning -EBUSY is okay. There is no need to show any
29 		 * ERROR message here.
30 		 */
31 		if (retry_times == HW_SEM_NO_WAIT) {
32 			return -EBUSY;
33 		} else if (count > retry_times) {
34 			ERROR("%s: timed out, reg = %x, mask = %x, expect = %x\n",
35 			       __func__, reg, mask, expect);
36 			return -EBUSY;
37 		}
38 		count += 1;
39 
40 		if (set_reg)
41 			mmio_write_32(set_reg, set_val);
42 		udelay(1);
43 	}
44 
45 	return 0;
46 }
47 
48 int apu_hw_sema_ctl_per_mbox(uint32_t sem_ctrl_addr, uint32_t sem_sta_addr,
49 			     uint8_t usr_bit, enum apu_hw_sem_op ctl, uint32_t timeout,
50 			     uint8_t bypass)
51 {
52 	int ret;
53 	uint8_t ctl_bit = 0;
54 
55 	if (ctl == HW_SEM_GET)
56 		ctl_bit = 0x1;
57 	else if (ctl == HW_SEM_PUT)
58 		ctl_bit = 0x2;
59 	else
60 		return -EINVAL;
61 
62 	/* return fail if semaphore is currently not held by this user */
63 	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_sta_addr) & BIT(usr_bit)) == 0)
64 	    && !bypass) {
65 		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
66 		       __func__, usr_bit, ctl, sem_sta_addr, mmio_read_32(sem_sta_addr));
67 		return -EINVAL;
68 	}
69 
70 	mmio_write_32(sem_ctrl_addr, ctl_bit);
71 
72 	if (ctl == HW_SEM_PUT)
73 		return 0;
74 
75 	ret = wait_for_state_ready(sem_sta_addr, BIT(usr_bit), BIT(usr_bit), timeout,
76 				   sem_ctrl_addr, ctl_bit);
77 	if (ret)
78 		return ret;
79 
80 	return 0;
81 }
82 
83 int apusys_rv_pwr_ctrl(enum APU_PWR_OP op)
84 {
85 	int ret;
86 	uint32_t global_ref_cnt;
87 
88 	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
89 				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
90 				       APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_TIMEOUT, 0);
91 
92 	if (ret) {
93 		ERROR("%s(%d): sem acquire timeout\n", __func__, op);
94 		return ret;
95 	}
96 
97 	global_ref_cnt = mmio_read_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY);
98 
99 	if (global_ref_cnt > 2) {
100 		ERROR("%s: global_ref_cnt(%d) > 2\n", __func__, global_ref_cnt);
101 	} else if (op == APU_PWR_OFF) {
102 		global_ref_cnt--;
103 		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
104 		if (global_ref_cnt == 0)
105 			mmio_write_32(APU_MBOX_WKUP_CFG(11), 0);
106 	} else if (op == APU_PWR_ON) {
107 		global_ref_cnt++;
108 		mmio_write_32(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_DUMMY, global_ref_cnt);
109 		if (global_ref_cnt == 1)
110 			mmio_write_32(APU_MBOX_WKUP_CFG(11), 1);
111 	}
112 
113 	ret = apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_CTRL,
114 				       APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA0_STA,
115 				       APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_TIMEOUT, 0);
116 
117 	if (ret)
118 		ERROR("%s(%d): sem release timeout\n", __func__, op);
119 
120 	return ret;
121 }
122 
123 int rv_iommu_hw_sem_trylock(void)
124 {
125 	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
126 					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
127 					APU_HW_SEM_SYS_APMCU, HW_SEM_GET, HW_SEM_NO_WAIT, 0);
128 }
129 
130 int rv_iommu_hw_sem_unlock(void)
131 {
132 	return apu_hw_sema_ctl_per_mbox(APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_CTRL,
133 					APU_MBOX(APU_HW_SEM_SYS_APMCU) + APU_MBOX_SEMA1_STA,
134 					APU_HW_SEM_SYS_APMCU, HW_SEM_PUT, HW_SEM_NO_WAIT, 0);
135 }
136 
137 int apu_hw_sema_ctl(uint32_t sem_addr, uint8_t usr_bit, uint8_t ctl, uint32_t timeout,
138 		    uint8_t bypass)
139 {
140 	int ret;
141 	uint8_t ctl_bit = 0;
142 
143 	if (ctl == HW_SEM_GET)
144 		ctl_bit = usr_bit;
145 	else if (ctl == HW_SEM_PUT)
146 		ctl_bit = usr_bit + HW_SEM_PUT_BIT_SHIFT;
147 	else
148 		return -EINVAL;
149 
150 	if (ctl == HW_SEM_PUT && ((mmio_read_32(sem_addr) & BIT(ctl_bit)) == 0) && !bypass) {
151 		ERROR("%s release error: usr_bit:%d ctl:%d (sem_addr(0x%08x) = 0x%08x)\n",
152 		       __func__, usr_bit, ctl, sem_addr, mmio_read_32(sem_addr));
153 		return -EINVAL;
154 	}
155 
156 	mmio_write_32(sem_addr, BIT(ctl_bit));
157 
158 	if (ctl == HW_SEM_PUT)
159 		goto end;
160 
161 	ret = wait_for_state_ready(sem_addr, BIT(ctl_bit), BIT(ctl_bit), timeout,
162 				   sem_addr, BIT(ctl_bit));
163 	if (ret)
164 		return ret;
165 
166 end:
167 	VERBOSE("%s: sem_addr = 0x%x, usr_bit: %d, ctl: %d, sem_addr = 0x%08x\n",
168 		 __func__, sem_addr, usr_bit, ctl, mmio_read_32(sem_addr));
169 
170 	return 0;
171 }
172 
173 int apusys_infra_dcm_setup(void)
174 {
175 	mmio_write_32(APU_REG_AO_GLUE_CONFG,
176 		      mmio_read_32(APU_REG_AO_GLUE_CONFG) | BIT(24) | BIT(26));
177 
178 	return 0;
179 }
180