blob: a9f0d755328b7f67caa146301bd16b725825a8e0 [file] [log] [blame]
Soren Brinkmannc8284402016-03-06 20:16:27 -08001/*
Jolly Shah31c38422019-01-08 11:10:47 -08002 * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
Soren Brinkmannc8284402016-03-06 20:16:27 -08003 *
dp-arm82cb2c12017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soren Brinkmannc8284402016-03-06 20:16:27 -08005 */
6
Isla Mitchellee1ebbd2017-07-14 10:46:32 +01007#include <arch_helpers.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +00008#include <lib/bakery_lock.h>
9#include <lib/mmio.h>
Jolly Shah63436bd2019-01-08 11:31:49 -080010
11#include <ipi.h>
Jolly Shah1611ef22019-01-08 11:21:29 -080012#include <plat_ipi.h>
Jolly Shah31c38422019-01-08 11:10:47 -080013#include <plat_private.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000014#include <plat/common/platform.h>
15
Isla Mitchellee1ebbd2017-07-14 10:46:32 +010016#include "pm_ipi.h"
Soren Brinkmannc8284402016-03-06 20:16:27 -080017
18/* IPI message buffers */
19#define IPI_BUFFER_BASEADDR 0xFF990000U
20
Soren Brinkmannc8284402016-03-06 20:16:27 -080021#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
Soren Brinkmannc8284402016-03-06 20:16:27 -080022#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
23
Soren Brinkmannc8284402016-03-06 20:16:27 -080024#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
Soren Brinkmannc8284402016-03-06 20:16:27 -080025#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U
26
Soren Brinkmann300cbb02016-09-30 14:24:25 -070027#define IPI_BUFFER_MAX_WORDS 8
28
Soren Brinkmannc8284402016-03-06 20:16:27 -080029#define IPI_BUFFER_REQ_OFFSET 0x0U
30#define IPI_BUFFER_RESP_OFFSET 0x20U
31
Tejas Patel7dae6132018-02-09 02:42:59 -080032#define IPI_BLOCKING 1
33#define IPI_NON_BLOCKING 0
34
Stefan Krsmanovic8212f1f2016-05-20 15:51:08 +020035DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmannc8284402016-03-06 20:16:27 -080036
37const struct pm_ipi apu_ipi = {
Wendy Liangebc05162017-10-03 23:21:11 -070038 .apu_ipi_id = IPI_ID_APU,
39 .pmu_ipi_id = IPI_ID_PMU0,
Soren Brinkmannc8284402016-03-06 20:16:27 -080040 .buffer_base = IPI_BUFFER_APU_BASE,
41};
42
43/**
44 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
45 *
Wendy Liangebc05162017-10-03 23:21:11 -070046 * @proc Pointer to the processor who is initiating request
Soren Brinkmannc8284402016-03-06 20:16:27 -080047 * @return On success, the initialization function must return 0.
48 * Any other return value will cause the framework to ignore
49 * the service
50 *
Soren Brinkmannc8284402016-03-06 20:16:27 -080051 * Called from pm_setup initialization function
52 */
Wendy Liangebc05162017-10-03 23:21:11 -070053int pm_ipi_init(const struct pm_proc *proc)
Soren Brinkmannc8284402016-03-06 20:16:27 -080054{
55 bakery_lock_init(&pm_secure_lock);
Wendy Liangebc05162017-10-03 23:21:11 -070056 ipi_mb_open(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmannc8284402016-03-06 20:16:27 -080057
58 return 0;
59}
60
61/**
Soren Brinkmannc8284402016-03-06 20:16:27 -080062 * pm_ipi_send_common() - Sends IPI request to the PMU
63 * @proc Pointer to the processor who is initiating request
64 * @payload API id and call arguments to be written in IPI buffer
65 *
66 * Send an IPI request to the power controller. Caller needs to hold
67 * the 'pm_secure_lock' lock.
68 *
69 * @return Returns status, either success or error+reason
70 */
71static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
Tejas Patel7dae6132018-02-09 02:42:59 -080072 uint32_t payload[PAYLOAD_ARG_CNT],
73 uint32_t is_blocking)
Soren Brinkmannc8284402016-03-06 20:16:27 -080074{
75 unsigned int offset = 0;
76 uintptr_t buffer_base = proc->ipi->buffer_base +
77 IPI_BUFFER_TARGET_PMU_OFFSET +
78 IPI_BUFFER_REQ_OFFSET;
79
Soren Brinkmannc8284402016-03-06 20:16:27 -080080 /* Write payload into IPI buffer */
81 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
82 mmio_write_32(buffer_base + offset, payload[i]);
83 offset += PAYLOAD_ARG_SIZE;
84 }
Tejas Patel7dae6132018-02-09 02:42:59 -080085
Soren Brinkmannc8284402016-03-06 20:16:27 -080086 /* Generate IPI to PMU */
Tejas Patel7dae6132018-02-09 02:42:59 -080087 ipi_mb_notify(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id,
88 is_blocking);
Soren Brinkmannc8284402016-03-06 20:16:27 -080089
90 return PM_RET_SUCCESS;
91}
92
93/**
Tejas Patel7dae6132018-02-09 02:42:59 -080094 * pm_ipi_send_non_blocking() - Sends IPI request to the PMU without blocking
95 * notification
96 * @proc Pointer to the processor who is initiating request
97 * @payload API id and call arguments to be written in IPI buffer
98 *
99 * Send an IPI request to the power controller.
100 *
101 * @return Returns status, either success or error+reason
102 */
103enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
104 uint32_t payload[PAYLOAD_ARG_CNT])
105{
106 enum pm_ret_status ret;
107
108 bakery_lock_get(&pm_secure_lock);
109
110 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
111
112 bakery_lock_release(&pm_secure_lock);
113
114 return ret;
115}
116
117/**
Soren Brinkmannc8284402016-03-06 20:16:27 -0800118 * pm_ipi_send() - Sends IPI request to the PMU
119 * @proc Pointer to the processor who is initiating request
120 * @payload API id and call arguments to be written in IPI buffer
121 *
122 * Send an IPI request to the power controller.
123 *
124 * @return Returns status, either success or error+reason
125 */
126enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
127 uint32_t payload[PAYLOAD_ARG_CNT])
128{
129 enum pm_ret_status ret;
130
131 bakery_lock_get(&pm_secure_lock);
132
Tejas Patel7dae6132018-02-09 02:42:59 -0800133 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800134
135 bakery_lock_release(&pm_secure_lock);
136
137 return ret;
138}
139
140
141/**
142 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
143 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700144 * @value Used to return value from IPI buffer element (optional)
145 * @count Number of values to return in @value
Soren Brinkmannc8284402016-03-06 20:16:27 -0800146 *
147 * @return Returns status, either success or error+reason
148 */
149static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700150 unsigned int *value, size_t count)
Soren Brinkmannc8284402016-03-06 20:16:27 -0800151{
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700152 size_t i;
Soren Brinkmannc8284402016-03-06 20:16:27 -0800153 uintptr_t buffer_base = proc->ipi->buffer_base +
154 IPI_BUFFER_TARGET_PMU_OFFSET +
155 IPI_BUFFER_RESP_OFFSET;
156
Soren Brinkmannc8284402016-03-06 20:16:27 -0800157 /*
158 * Read response from IPI buffer
159 * buf-0: success or error+reason
160 * buf-1: value
161 * buf-2: unused
162 * buf-3: unused
163 */
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700164 for (i = 1; i <= count; i++) {
165 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
166 value++;
167 }
Soren Brinkmannc8284402016-03-06 20:16:27 -0800168
169 return mmio_read_32(buffer_base);
170}
171
172/**
Soren Brinkmann300cbb02016-09-30 14:24:25 -0700173 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt
174 * @value Used to return value from IPI buffer element (optional)
175 * @count Number of values to return in @value
176 *
177 * @return Returns status, either success or error+reason
178 */
179void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
180{
181 size_t i;
182 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE +
183 IPI_BUFFER_TARGET_APU_OFFSET +
184 IPI_BUFFER_REQ_OFFSET;
185
186 if (count > IPI_BUFFER_MAX_WORDS)
187 count = IPI_BUFFER_MAX_WORDS;
188
189 for (i = 0; i <= count; i++) {
190 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
191 value++;
192 }
193}
194
195/**
Soren Brinkmannc8284402016-03-06 20:16:27 -0800196 * pm_ipi_send_sync() - Sends IPI request to the PMU
197 * @proc Pointer to the processor who is initiating request
198 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700199 * @value Used to return value from IPI buffer element (optional)
200 * @count Number of values to return in @value
Soren Brinkmannc8284402016-03-06 20:16:27 -0800201 *
202 * Send an IPI request to the power controller and wait for it to be handled.
203 *
204 * @return Returns status, either success or error+reason and, optionally,
205 * @value
206 */
207enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
208 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700209 unsigned int *value, size_t count)
Soren Brinkmannc8284402016-03-06 20:16:27 -0800210{
211 enum pm_ret_status ret;
212
213 bakery_lock_get(&pm_secure_lock);
214
Tejas Patel7dae6132018-02-09 02:42:59 -0800215 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800216 if (ret != PM_RET_SUCCESS)
217 goto unlock;
218
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700219 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800220
221unlock:
222 bakery_lock_release(&pm_secure_lock);
223
224 return ret;
225}
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700226
Wendy Liangebc05162017-10-03 23:21:11 -0700227void pm_ipi_irq_enable(const struct pm_proc *proc)
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700228{
Wendy Liangebc05162017-10-03 23:21:11 -0700229 ipi_mb_enable_irq(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700230}
231
Wendy Liangebc05162017-10-03 23:21:11 -0700232void pm_ipi_irq_clear(const struct pm_proc *proc)
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700233{
Wendy Liangebc05162017-10-03 23:21:11 -0700234 ipi_mb_ack(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann300cbb02016-09-30 14:24:25 -0700235}