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