1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4 */
5
6 #include "hal_base.h"
7
8 #ifdef HAL_PMU_MODULE_ENABLED
9
10 /** @addtogroup RK_HAL_Driver
11 * @{
12 */
13
14 /** @addtogroup PD
15 * @{
16 */
17
18 /** @defgroup PD_How_To_Use How To Use
19 * @{
20
21 The PD driver can be used as follows:
22
23 - Invoke HAL_PD_Setting in each device power on/off its own Pd.
24 - The order of setting power domain.
25
26 power on:
27 set power domain on
28 leave idle
29 power off:
30 request ilde
31 set power domain off
32
33 - The PD ID is include shift information:
34
35 [3:0]: power on shift
36 [7:4]: power on status shift
37 [11:8]: idle request shift
38 [15:12]: idle status shift
39 [19:16]: ack status shift
40
41 - PD driver is just responsible for passing simple command data, And
42 the usecount is the user's responsibility. Protection the usecount at the driver layer.
43 - More details refer to APIs' descriptions as below.
44
45 @} */
46
47 /** @defgroup PD_Private_Definition Private Definition
48 * @{
49 */
50 /********************* Private MACRO Definition ******************************/
51 #define PD_PWR_SHIFT 0U
52 #define PD_PWR_MASK 0x0000000FU
53 #define PD_ST_SHIFT 4U
54 #define PD_ST_MASK 0x000000F0U
55 #define PD_REQ_SHIFT 8U
56 #define PD_REQ_MASK 0x00000F00U
57 #define PD_IDLE_SHIFT 12U
58 #define PD_IDLE_MASK 0x0000F000U
59 #define PD_ACK_SHIFT 16U
60 #define PD_ACK_MASK 0x000F0000U
61 #define PD_VALID_SHIFT 31U
62 #define PD_VALID_MASK 0x80000000U
63
64 #define PD_GET_PWR_SHIFT(x) (((uint32_t)(x)&PD_PWR_MASK) >> PD_PWR_SHIFT)
65 #define PD_GET_ST_SHIFT(x) (((uint32_t)(x)&PD_ST_MASK) >> PD_ST_SHIFT)
66 #define PD_GET_REQ_SHIFT(x) (((uint32_t)(x)&PD_REQ_MASK) >> PD_REQ_SHIFT)
67 #if defined(SOC_RK1808)
68 #define PD_GET_IDLE_SHIFT(x) ((((uint32_t)(x)&PD_IDLE_MASK) >> PD_IDLE_SHIFT) + 16)
69 #else
70 #define PD_GET_IDLE_SHIFT(x) (((uint32_t)(x)&PD_IDLE_MASK) >> PD_IDLE_SHIFT)
71 #endif
72 #define PD_GET_ACK_SHIFT(x) (((uint32_t)(x)&PD_ACK_MASK) >> PD_ACK_SHIFT)
73
74 #define PD_IS_INVALID(x) (!(((uint32_t)(x)&PD_VALID_MASK) >> PD_VALID_SHIFT))
75
76 /********************* Private Structure Definition **************************/
77
78 /********************* Private Variable Definition ***************************/
79
80 /********************* Private Function Definition ***************************/
81
PD_IsIdle(ePD_Id pd)82 static HAL_Check PD_IsIdle(ePD_Id pd)
83 {
84 uint32_t idleShift = PD_GET_IDLE_SHIFT(pd);
85
86 return (HAL_Check)((PMU->BUS_IDLE_ST & (1 << idleShift)) >> idleShift);
87 }
88
89 #if defined(SOC_RK1808)
PD_ReadAck(ePD_Id pd)90 static HAL_Check PD_ReadAck(ePD_Id pd)
91 {
92 uint32_t ackShift = PD_GET_ACK_SHIFT(pd);
93
94 return (HAL_Check)((PMU->BUS_IDLE_ST & (1 << ackShift)) >> ackShift);
95 }
96 #else
PD_ReadAck(ePD_Id pd)97 static HAL_Check PD_ReadAck(ePD_Id pd)
98 {
99 uint32_t ackShift = PD_GET_ACK_SHIFT(pd);
100
101 return (HAL_Check)((PMU->BUS_IDLE_ACK & (1 << ackShift)) >> ackShift);
102 }
103 #endif
104
PD_IsOn(ePD_Id pd)105 static HAL_Check PD_IsOn(ePD_Id pd)
106 {
107 uint32_t stShift = PD_GET_ST_SHIFT(pd);
108
109 /* check idle status for idle-only domains */
110
111 if (stShift > 16) {
112 return PD_IsIdle(pd) ? HAL_FALSE : HAL_TRUE;
113 }
114
115 return (HAL_Check)(!((PMU->PWRDN_ST & (1 << stShift)) >> stShift));
116 }
117
PD_IdleRequest(ePD_Id pd,HAL_Check idle)118 static HAL_Status PD_IdleRequest(ePD_Id pd, HAL_Check idle)
119 {
120 uint32_t reqShift = PD_GET_REQ_SHIFT(pd);
121 uint32_t start, timeoutMs = 1000;
122
123 if (reqShift > 16) {
124 return HAL_INVAL;
125 }
126
127 PMU->BUS_IDLE_REQ = VAL_MASK_WE(1U << reqShift, (idle ? 1U : 0U) << reqShift);
128
129 /* Wait util idle_ack = 1 */
130 start = HAL_GetTick();
131
132 while (PD_ReadAck(pd) != idle) {
133 if ((HAL_GetTick() - start) > timeoutMs) {
134 return HAL_TIMEOUT;
135 }
136 }
137
138 start = HAL_GetTick();
139 while (PD_IsIdle(pd) != idle) {
140 if ((HAL_GetTick() - start) > timeoutMs) {
141 return HAL_TIMEOUT;
142 }
143 }
144
145 return HAL_OK;
146 }
147
PD_PowerOn(ePD_Id pd,HAL_Check on)148 static HAL_Status PD_PowerOn(ePD_Id pd, HAL_Check on)
149 {
150 uint32_t pwrShift = PD_GET_PWR_SHIFT(pd);
151 uint32_t start, timeoutMs = 1000;
152
153 if (pwrShift > 16) {
154 return HAL_INVAL;
155 }
156
157 PMU->PWRDN_CON = VAL_MASK_WE(1U << pwrShift, (on ? 0U : 1U) << pwrShift);
158
159 start = HAL_GetTick();
160
161 while (PD_IsOn(pd) != on) {
162 if ((HAL_GetTick() - start) > timeoutMs) {
163 return HAL_TIMEOUT;
164 }
165 }
166
167 return HAL_OK;
168 }
169
170 /** @} */
171 /********************* Public Function Definition ****************************/
172
173 /** @defgroup PD_Exported_Functions_Group5 Other Functions
174 * @attention these APIs allow direct use in the HAL layer.
175 * @{
176 */
177
178 /**
179 * @brief Pd setting on
180 * @param pd: pd id
181 * @return HAL_Status
182 */
HAL_PD_On(ePD_Id pd)183 HAL_Status HAL_PD_On(ePD_Id pd)
184 {
185 HAL_Status error;
186
187 if (PD_IS_INVALID(pd)) {
188 return HAL_INVAL;
189 }
190
191 if (PD_IsOn(pd)) {
192 return HAL_OK;
193 }
194
195 error = PD_PowerOn(pd, HAL_TRUE);
196 if (error) {
197 return error;
198 }
199
200 /* if powering up, leave idle mode */
201 error = PD_IdleRequest(pd, HAL_FALSE);
202
203 return error;
204 }
205
206 /**
207 * @brief Pd setting off
208 * @param pd: pd id
209 * @return HAL_Status
210 */
HAL_PD_Off(ePD_Id pd)211 HAL_Status HAL_PD_Off(ePD_Id pd)
212 {
213 HAL_Status error;
214
215 if (PD_IS_INVALID(pd)) {
216 return HAL_INVAL;
217 }
218
219 if (!PD_IsOn(pd)) {
220 return HAL_OK;
221 }
222
223 /* if powering down, idle request to NIU first */
224 error = PD_IdleRequest(pd, HAL_TRUE);
225 if (error) {
226 return error;
227 }
228
229 error = PD_PowerOn(pd, HAL_FALSE);
230
231 return error;
232 }
233
234 /** @} */
235
236 /** @} */
237
238 /** @} */
239
240 #endif /* HAL_PMU_MODULE_ENABLED */
241