1 /***************************************************************************//**
2 * \file ppu_v1.c
3 * \version 1.0
4 *
5 * This file provides the source code for ARM PPU driver
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright (c) (2020-2022), Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation.
11 *
12 * SPDX-License-Identifier: BSD-3-Clause
13 *
14 * Arm SCP/MCP Software
15 * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
16 *
17 * SPDX-License-Identifier: BSD-3-Clause
18 *******************************************************************************/
19 
20 #include "cy_device.h"
21 
22 #if defined (CY_IP_MXS28SRSS) || defined(CY_IP_MXS40SSRSS) || defined(CY_IP_MXS22SRSS)
23 
24 #include <stddef.h>
25 #include <ppu_v1.h>
26 
ppu_v1_init(struct ppu_v1_reg * ppu)27 void ppu_v1_init(struct ppu_v1_reg *ppu)
28 {
29     fwk_assert(ppu != NULL);
30 
31     /* Set edge sensitivity to masked for all input edges */
32     ppu->IESR = 0;
33 
34     /* Mask all interrupts */
35     ppu->IMR = PPU_V1_IMR_MASK;
36 
37     /* Acknowledge any interrupt left pending */
38     ppu->ISR = PPU_V1_ISR_MASK;
39 }
40 
41 /*
42  * PWPR and PWSR registers
43  */
ppu_v1_request_power_mode(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)44 int ppu_v1_request_power_mode(struct ppu_v1_reg *ppu, enum ppu_v1_mode ppu_mode)
45 {
46     uint32_t power_policy;
47     fwk_assert(ppu != NULL);
48     fwk_assert(ppu_mode < PPU_V1_MODE_COUNT);
49 
50     power_policy = ppu->PWPR & ~(PPU_V1_PWPR_POLICY | PPU_V1_PWPR_DYNAMIC_EN);
51     ppu->PWPR = power_policy | ppu_mode;
52 
53     return FWK_SUCCESS;
54 }
55 
ppu_v1_set_power_mode(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)56 int ppu_v1_set_power_mode(struct ppu_v1_reg *ppu, enum ppu_v1_mode ppu_mode)
57 {
58     int status;
59 
60     status = ppu_v1_request_power_mode(ppu, ppu_mode);
61     if (status != FWK_SUCCESS)
62         return status;
63 
64     while ((ppu->PWSR & (PPU_V1_PWSR_PWR_STATUS | PPU_V1_PWSR_PWR_DYN_STATUS))
65             != ppu_mode)
66         continue;
67 
68     return FWK_SUCCESS;
69 }
70 
ppu_v1_request_operating_mode(struct ppu_v1_reg * ppu,enum ppu_v1_opmode op_mode)71 int ppu_v1_request_operating_mode(struct ppu_v1_reg *ppu,
72                                   enum ppu_v1_opmode op_mode)
73 {
74     uint32_t power_policy;
75     fwk_assert(ppu != NULL);
76     fwk_assert(op_mode < PPU_V1_OPMODE_COUNT);
77 
78     power_policy = ppu->PWPR & ~(PPU_V1_PWPR_OP_POLICY | PPU_V1_PWPR_OP_DYN_EN);
79     ppu->PWPR = power_policy | (op_mode << PPU_V1_PWPR_OP_POLICY_POS);
80 
81     return FWK_SUCCESS;
82 }
83 
ppu_v1_opmode_dynamic_enable(struct ppu_v1_reg * ppu,enum ppu_v1_opmode min_dyn_mode)84 void ppu_v1_opmode_dynamic_enable(struct ppu_v1_reg *ppu,
85                                   enum ppu_v1_opmode min_dyn_mode)
86 {
87     uint32_t power_policy;
88 
89     fwk_assert(ppu != NULL);
90     fwk_assert(min_dyn_mode < PPU_V1_OPMODE_COUNT);
91 
92     power_policy = ppu->PWPR & ~PPU_V1_PWPR_OP_POLICY;
93     ppu->PWPR = power_policy |
94                 PPU_V1_PWPR_OP_DYN_EN |
95                 (min_dyn_mode << PPU_V1_PWPR_OP_POLICY_POS);
96     while ((ppu->PWSR & PPU_V1_PWSR_OP_DYN_STATUS) == 0)
97         continue;
98 }
99 
ppu_v1_dynamic_enable(struct ppu_v1_reg * ppu,enum ppu_v1_mode min_dyn_state)100 void ppu_v1_dynamic_enable(struct ppu_v1_reg *ppu,
101                            enum ppu_v1_mode min_dyn_state)
102 {
103     uint32_t power_policy;
104 
105     fwk_assert(ppu != NULL);
106     fwk_assert(min_dyn_state < PPU_V1_MODE_COUNT);
107 
108     power_policy = ppu->PWPR & ~PPU_V1_PWPR_POLICY;
109     ppu->PWPR = power_policy | PPU_V1_PWPR_DYNAMIC_EN | min_dyn_state;
110     while ((ppu->PWSR & PPU_V1_PWSR_PWR_DYN_STATUS) == 0)
111         continue;
112 }
113 
ppu_v1_lock_off_enable(struct ppu_v1_reg * ppu)114 void ppu_v1_lock_off_enable(struct ppu_v1_reg *ppu)
115 {
116     fwk_assert(ppu != NULL);
117 
118     ppu->PWPR |= PPU_V1_PWPR_OFF_LOCK_EN;
119 }
120 
ppu_v1_lock_off_disable(struct ppu_v1_reg * ppu)121 void ppu_v1_lock_off_disable(struct ppu_v1_reg *ppu)
122 {
123     fwk_assert(ppu != NULL);
124 
125     ppu->PWPR &= ~PPU_V1_PWPR_OFF_LOCK_EN;
126 }
127 
ppu_v1_get_power_mode(struct ppu_v1_reg * ppu)128 enum ppu_v1_mode ppu_v1_get_power_mode(struct ppu_v1_reg *ppu)
129 {
130     fwk_assert(ppu != NULL);
131 
132     return (enum ppu_v1_mode)(ppu->PWSR & PPU_V1_PWSR_PWR_STATUS);
133 }
134 
ppu_v1_get_programmed_power_mode(struct ppu_v1_reg * ppu)135 enum ppu_v1_mode ppu_v1_get_programmed_power_mode(struct ppu_v1_reg *ppu)
136 {
137     fwk_assert(ppu != NULL);
138 
139     return (enum ppu_v1_mode)(ppu->PWPR & PPU_V1_PWPR_POLICY);
140 }
141 
ppu_v1_get_operating_mode(struct ppu_v1_reg * ppu)142 enum ppu_v1_opmode ppu_v1_get_operating_mode(struct ppu_v1_reg *ppu)
143 {
144     fwk_assert(ppu != NULL);
145 
146     return (enum ppu_v1_opmode)
147         ((ppu->PWSR & PPU_V1_PWSR_OP_STATUS) >> PPU_V1_PWSR_OP_STATUS_POS);
148 }
149 
ppu_v1_get_programmed_operating_mode(struct ppu_v1_reg * ppu)150 enum ppu_v1_opmode ppu_v1_get_programmed_operating_mode(struct ppu_v1_reg *ppu)
151 {
152     fwk_assert(ppu != NULL);
153 
154     return (enum ppu_v1_opmode)
155         ((ppu->PWPR & PPU_V1_PWPR_OP_POLICY) >> PPU_V1_PWPR_OP_POLICY_POS);
156 }
157 
ppu_v1_is_dynamic_enabled(struct ppu_v1_reg * ppu)158 bool ppu_v1_is_dynamic_enabled(struct ppu_v1_reg *ppu)
159 {
160     fwk_assert(ppu != NULL);
161 
162     return ((ppu->PWSR & PPU_V1_PWSR_PWR_DYN_STATUS) != 0);
163 }
164 
ppu_v1_is_locked(struct ppu_v1_reg * ppu)165 bool ppu_v1_is_locked(struct ppu_v1_reg *ppu)
166 {
167     fwk_assert(ppu != NULL);
168 
169     return ((ppu->PWSR & PPU_V1_PWSR_OFF_LOCK_STATUS) != 0);
170 }
171 
172 /*
173  * DISR register
174  */
ppu_v1_is_power_devactive_high(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)175 bool ppu_v1_is_power_devactive_high(struct ppu_v1_reg *ppu,
176                                     enum ppu_v1_mode ppu_mode)
177 {
178     fwk_assert(ppu != NULL);
179 
180     return (ppu->DISR &
181             (1 << (ppu_mode + PPU_V1_DISR_PWR_DEVACTIVE_STATUS_POS))) != 0;
182 }
183 
ppu_v1_is_op_devactive_high(struct ppu_v1_reg * ppu,enum ppu_v1_op_devactive op_devactive)184 bool ppu_v1_is_op_devactive_high(struct ppu_v1_reg *ppu,
185                                  enum ppu_v1_op_devactive op_devactive)
186 {
187     fwk_assert(ppu != NULL);
188 
189     return (ppu->DISR &
190             (1 << (op_devactive + PPU_V1_DISR_OP_DEVACTIVE_STATUS_POS))) != 0;
191 }
192 
193 /*
194  * UNLK register
195  */
ppu_v1_off_unlock(struct ppu_v1_reg * ppu)196 void ppu_v1_off_unlock(struct ppu_v1_reg *ppu)
197 {
198     fwk_assert(ppu != NULL);
199 
200     ppu->UNLK = PPU_V1_UNLK_OFF_UNLOCK;
201 }
202 
203 /*
204  * PWCR register
205  */
ppu_v1_disable_devactive(struct ppu_v1_reg * ppu)206 void ppu_v1_disable_devactive(struct ppu_v1_reg *ppu)
207 {
208     fwk_assert(ppu != NULL);
209 
210     ppu->PWCR &= ~PPU_V1_PWCR_DEV_ACTIVE_EN;
211 }
212 
ppu_v1_disable_handshake(struct ppu_v1_reg * ppu)213 void ppu_v1_disable_handshake(struct ppu_v1_reg *ppu)
214 {
215     fwk_assert(ppu != NULL);
216 
217     ppu->PWCR &= ~PPU_V1_PWCR_DEV_REQ_EN;
218 }
219 
220 /*
221  * Interrupt registers: IMR, AIMR, ISR, AISR, IESR, OPSR
222  */
ppu_v1_interrupt_mask(struct ppu_v1_reg * ppu,unsigned int mask)223 void ppu_v1_interrupt_mask(struct ppu_v1_reg *ppu, unsigned int mask)
224 {
225     fwk_assert(ppu != NULL);
226 
227     ppu->IMR |= mask & PPU_V1_IMR_MASK;
228 }
229 
ppu_v1_additional_interrupt_mask(struct ppu_v1_reg * ppu,unsigned int mask)230 void ppu_v1_additional_interrupt_mask(struct ppu_v1_reg *ppu, unsigned int mask)
231 {
232     fwk_assert(ppu != NULL);
233 
234     ppu->AIMR |= mask & PPU_V1_AIMR_MASK;
235 }
236 
ppu_v1_interrupt_unmask(struct ppu_v1_reg * ppu,unsigned int mask)237 void ppu_v1_interrupt_unmask(struct ppu_v1_reg *ppu, unsigned int mask)
238 {
239     fwk_assert(ppu != NULL);
240 
241     ppu->IMR &= ~(mask & PPU_V1_IMR_MASK);
242 }
243 
ppu_v1_additional_interrupt_unmask(struct ppu_v1_reg * ppu,unsigned int mask)244 void ppu_v1_additional_interrupt_unmask(struct ppu_v1_reg *ppu,
245     unsigned int mask)
246 {
247     fwk_assert(ppu != NULL);
248 
249     ppu->AIMR &= ~(mask & PPU_V1_AIMR_MASK);
250 }
251 
ppu_v1_is_additional_interrupt_pending(struct ppu_v1_reg * ppu,unsigned int mask)252 bool ppu_v1_is_additional_interrupt_pending(struct ppu_v1_reg *ppu,
253     unsigned int mask)
254 {
255     return (ppu->AISR & (mask & PPU_V1_AISR_MASK)) != 0;
256 }
257 
ppu_v1_ack_interrupt(struct ppu_v1_reg * ppu,unsigned int mask)258 void ppu_v1_ack_interrupt(struct ppu_v1_reg *ppu, unsigned int mask)
259 {
260     fwk_assert(ppu != NULL);
261 
262     ppu->ISR &= mask & PPU_V1_IMR_MASK;
263 }
264 
ppu_v1_ack_additional_interrupt(struct ppu_v1_reg * ppu,unsigned int mask)265 void ppu_v1_ack_additional_interrupt(struct ppu_v1_reg *ppu, unsigned int mask)
266 {
267     fwk_assert(ppu != NULL);
268 
269     ppu->AISR &= mask & PPU_V1_AIMR_MASK;
270 }
271 
ppu_v1_set_input_edge_sensitivity(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode,enum ppu_v1_edge_sensitivity edge_sensitivity)272 void ppu_v1_set_input_edge_sensitivity(struct ppu_v1_reg *ppu,
273     enum ppu_v1_mode ppu_mode, enum ppu_v1_edge_sensitivity edge_sensitivity)
274 {
275     fwk_assert(ppu != NULL);
276     fwk_assert(ppu_mode < PPU_V1_MODE_COUNT);
277     fwk_assert((edge_sensitivity & ~PPU_V1_EDGE_SENSITIVITY_MASK) == 0);
278 
279     /* Clear current settings */
280     ppu->IESR &= ~(PPU_V1_EDGE_SENSITIVITY_MASK <<
281                    (ppu_mode * PPU_V1_BITS_PER_EDGE_SENSITIVITY));
282 
283     /* Update settings */
284     ppu->IESR |= edge_sensitivity <<
285                  (ppu_mode * PPU_V1_BITS_PER_EDGE_SENSITIVITY);
286 }
287 
ppu_v1_get_input_edge_sensitivity(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)288 enum ppu_v1_edge_sensitivity ppu_v1_get_input_edge_sensitivity(
289     struct ppu_v1_reg *ppu, enum ppu_v1_mode ppu_mode)
290 {
291     fwk_assert(ppu != NULL);
292     fwk_assert(ppu_mode < PPU_V1_MODE_COUNT);
293 
294     return (enum ppu_v1_edge_sensitivity)(
295             (ppu->IESR >> (ppu_mode * PPU_V1_BITS_PER_EDGE_SENSITIVITY)) &
296             PPU_V1_EDGE_SENSITIVITY_MASK);
297 }
298 
ppu_v1_ack_power_active_edge_interrupt(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)299 void ppu_v1_ack_power_active_edge_interrupt(struct ppu_v1_reg *ppu,
300     enum ppu_v1_mode ppu_mode)
301 {
302     ppu->ISR = 1 << (ppu_mode + PPU_V1_ISR_ACTIVE_EDGE_POS);
303 }
304 
ppu_v1_is_power_active_edge_interrupt(struct ppu_v1_reg * ppu,enum ppu_v1_mode ppu_mode)305 bool ppu_v1_is_power_active_edge_interrupt(struct ppu_v1_reg *ppu,
306     enum ppu_v1_mode ppu_mode)
307 {
308     return ppu->ISR & (1 << (ppu_mode + PPU_V1_ISR_ACTIVE_EDGE_POS));
309 }
310 
ppu_v1_set_op_active_edge_sensitivity(struct ppu_v1_reg * ppu,enum ppu_v1_op_devactive op_devactive,enum ppu_v1_edge_sensitivity edge_sensitivity)311 void ppu_v1_set_op_active_edge_sensitivity(struct ppu_v1_reg *ppu,
312     enum ppu_v1_op_devactive op_devactive,
313     enum ppu_v1_edge_sensitivity edge_sensitivity)
314 {
315     fwk_assert(ppu != NULL);
316     fwk_assert(op_devactive < PPU_V1_OP_DEVACTIVE_COUNT);
317     fwk_assert((edge_sensitivity & ~PPU_V1_EDGE_SENSITIVITY_MASK) == 0);
318 
319     /* Clear current settings */
320     ppu->OPSR &= ~(PPU_V1_EDGE_SENSITIVITY_MASK <<
321                    (op_devactive * PPU_V1_BITS_PER_EDGE_SENSITIVITY));
322 
323     /* Update settings */
324     ppu->OPSR |= edge_sensitivity <<
325                  (op_devactive * PPU_V1_BITS_PER_EDGE_SENSITIVITY);
326 }
327 
ppu_v1_get_op_active_edge_sensitivity(struct ppu_v1_reg * ppu,enum ppu_v1_op_devactive op_devactive)328 enum ppu_v1_edge_sensitivity ppu_v1_get_op_active_edge_sensitivity(
329     struct ppu_v1_reg *ppu, enum ppu_v1_op_devactive op_devactive)
330 {
331     fwk_assert(ppu != NULL);
332     fwk_assert(op_devactive < PPU_V1_OP_DEVACTIVE_COUNT);
333 
334     return (enum ppu_v1_edge_sensitivity)(
335             (ppu->OPSR >> (op_devactive * PPU_V1_BITS_PER_EDGE_SENSITIVITY)) &
336             PPU_V1_EDGE_SENSITIVITY_MASK);
337 }
338 
ppu_v1_ack_op_active_edge_interrupt(struct ppu_v1_reg * ppu,enum ppu_v1_op_devactive op_devactive)339 void ppu_v1_ack_op_active_edge_interrupt(struct ppu_v1_reg *ppu,
340     enum ppu_v1_op_devactive op_devactive)
341 {
342     ppu->ISR = 1 << (op_devactive + PPU_V1_ISR_OP_ACTIVE_EDGE_POS);
343 }
344 
ppu_v1_is_op_active_edge_interrupt(struct ppu_v1_reg * ppu,enum ppu_v1_op_devactive op_devactive)345 bool ppu_v1_is_op_active_edge_interrupt(struct ppu_v1_reg *ppu,
346     enum ppu_v1_op_devactive op_devactive)
347 {
348     return ppu->ISR & (1 << (op_devactive + PPU_V1_ISR_OP_ACTIVE_EDGE_POS));
349 }
350 
ppu_v1_is_dyn_policy_min_interrupt(struct ppu_v1_reg * ppu)351 bool ppu_v1_is_dyn_policy_min_interrupt(struct ppu_v1_reg *ppu)
352 {
353     return ppu->ISR & PPU_V1_ISR_DYN_POLICY_MIN_IRQ;
354 }
355 
356 /*
357  * IDR0 register
358  */
ppu_v1_get_num_opmode(struct ppu_v1_reg * ppu)359 unsigned int ppu_v1_get_num_opmode(struct ppu_v1_reg *ppu)
360 {
361     return ((ppu->IDR0 & PPU_V1_IDR0_NUM_OPMODE)
362             >> PPU_V1_IDR0_NUM_OPMODE_POS) + 1;
363 }
364 
365 /*
366  * AIDR register
367  */
ppu_v1_get_arch_id(struct ppu_v1_reg * ppu)368 unsigned int ppu_v1_get_arch_id(struct ppu_v1_reg *ppu)
369 {
370     fwk_assert(ppu != NULL);
371 
372     return (ppu->AIDR & (PPU_V1_AIDR_ARCH_REV_MINOR |
373                          PPU_V1_AIDR_ARCH_REV_MAJOR));
374 }
375 
376 /*
377  * MISR register
378  */
ppu_v1_get_failure_device_id(struct ppu_v1_reg * ppu)379 unsigned int ppu_v1_get_failure_device_id(struct ppu_v1_reg *ppu)
380 {
381     fwk_assert(ppu != NULL);
382 
383     return (enum ppu_v1_mode)((ppu->MISR & PPU_V1_MISR_DEVDENY_STATUS_MASK) >> PPU_V1_MISR_DEVDENY_STATUS_POS);
384 }
385 
386 #endif /* CY_IP_MXS28SRSS */
387