1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "ppu_v0.h"
9 
10 #include <fwk_assert.h>
11 #include <fwk_status.h>
12 
13 #include <stddef.h>
14 
15 struct set_power_status_check_params_v0 {
16     enum ppu_v0_mode mode;
17     struct ppu_v0_reg *reg;
18 };
19 
ppu_v0_set_power_status_check(void * data)20 static bool ppu_v0_set_power_status_check(void *data)
21 {
22     struct set_power_status_check_params_v0 *params;
23 
24     fwk_assert(data != NULL);
25     params = (struct set_power_status_check_params_v0 *)data;
26 
27     return (
28         (params->reg->POWER_STATUS &
29          (PPU_V0_PSR_POWSTAT | PPU_V0_PSR_DYNAMIC)) == params->mode);
30 }
31 
ppu_v0_init(struct ppu_v0_reg * ppu)32 void ppu_v0_init(struct ppu_v0_reg *ppu)
33 {
34     fwk_assert(ppu != NULL);
35 
36     /* Set mode as masked to all input edge interrupts */
37     ppu->IESR = 0;
38 
39     /* Mask all interrupts */
40     ppu->IMR = PPU_V0_IMR_MASK;
41 
42     /* Acknowledge any interrupt left pending */
43     ppu->ISR = PPU_V0_ISR_MASK;
44 }
45 
ppu_v0_request_power_mode(struct ppu_v0_reg * ppu,enum ppu_v0_mode mode)46 int ppu_v0_request_power_mode(struct ppu_v0_reg *ppu, enum ppu_v0_mode mode)
47 {
48     uint32_t power_policy;
49     fwk_assert(ppu != NULL);
50     fwk_assert(mode < PPU_V0_MODE_COUNT);
51 
52     power_policy = ppu->POWER_POLICY &
53         ~(PPU_V0_PPR_POLICY | PPU_V0_PPR_DYNAMIC_EN);
54     ppu->POWER_POLICY = power_policy | mode;
55 
56     return FWK_SUCCESS;
57 }
58 
ppu_v0_set_power_mode(struct ppu_v0_reg * ppu,enum ppu_v0_mode mode,struct ppu_v0_timer_ctx * timer_ctx)59 int ppu_v0_set_power_mode(
60     struct ppu_v0_reg *ppu,
61     enum ppu_v0_mode mode,
62     struct ppu_v0_timer_ctx *timer_ctx)
63 {
64     int status;
65     fwk_assert(ppu != NULL);
66     struct set_power_status_check_params_v0 params;
67 
68     status = ppu_v0_request_power_mode(ppu, mode);
69     if (status != FWK_SUCCESS)
70         return status;
71     if (timer_ctx == NULL) {
72         while ((ppu->POWER_STATUS &
73                 (PPU_V0_PSR_POWSTAT | PPU_V0_PSR_DYNAMIC)) != mode)
74             continue;
75     } else {
76         params.mode = mode;
77         params.reg = ppu;
78         return timer_ctx->timer_api->wait(
79             timer_ctx->timer_id,
80             timer_ctx->delay_us,
81             ppu_v0_set_power_status_check,
82             &params);
83     }
84 
85     return FWK_SUCCESS;
86 }
87 
ppu_v0_get_power_mode(struct ppu_v0_reg * ppu,enum ppu_v0_mode * mode)88 int ppu_v0_get_power_mode(struct ppu_v0_reg *ppu, enum ppu_v0_mode *mode)
89 {
90     fwk_assert(ppu != NULL);
91     fwk_assert(mode != NULL);
92 
93     *mode = (enum ppu_v0_mode)(ppu->POWER_STATUS & PPU_V0_PSR_POWSTAT);
94 
95     return FWK_SUCCESS;
96 }
97