blob: 9148f90942dfc20ef4878f4ecb20f8e9cb837437 [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
2 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <bakery_lock.h>
32#include <mmio.h>
33#include <platform.h>
34#include <arch_helpers.h>
35#include "pm_ipi.h"
36#include "../zynqmp_private.h"
37
38/* IPI message buffers */
39#define IPI_BUFFER_BASEADDR 0xFF990000U
40
41#define IPI_BUFFER_RPU_0_BASE (IPI_BUFFER_BASEADDR + 0x0U)
42#define IPI_BUFFER_RPU_1_BASE (IPI_BUFFER_BASEADDR + 0x200U)
43#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
44#define IPI_BUFFER_PL_0_BASE (IPI_BUFFER_BASEADDR + 0x600U)
45#define IPI_BUFFER_PL_1_BASE (IPI_BUFFER_BASEADDR + 0x800U)
46#define IPI_BUFFER_PL_2_BASE (IPI_BUFFER_BASEADDR + 0xA00U)
47#define IPI_BUFFER_PL_3_BASE (IPI_BUFFER_BASEADDR + 0xC00U)
48#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
49
50#define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U
51#define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U
52#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
53#define IPI_BUFFER_TARGET_PL_0_OFFSET 0xC0U
54#define IPI_BUFFER_TARGET_PL_1_OFFSET 0x100U
55#define IPI_BUFFER_TARGET_PL_2_OFFSET 0x140U
56#define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U
57#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U
58
Soren Brinkmann84f0af42016-09-30 14:24:25 -070059#define IPI_BUFFER_MAX_WORDS 8
60
Soren Brinkmann76fcae32016-03-06 20:16:27 -080061#define IPI_BUFFER_REQ_OFFSET 0x0U
62#define IPI_BUFFER_RESP_OFFSET 0x20U
63
64/* IPI Base Address */
65#define IPI_BASEADDR 0XFF300000
66
67/* APU's IPI registers */
68#define IPI_APU_ISR (IPI_BASEADDR + 0X00000010)
69#define IPI_APU_IER (IPI_BASEADDR + 0X00000018)
70#define IPI_APU_IDR (IPI_BASEADDR + 0X0000001C)
Soren Brinkmannacff8a42016-04-11 15:30:56 -070071#define IPI_APU_IXR_PMU_0_MASK (1 << 16)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080072
73#define IPI_TRIG_OFFSET 0
74#define IPI_OBS_OFFSET 4
75
76/* Power Management IPI interrupt number */
77#define PM_INT_NUM 0
78#define IPI_PMU_PM_INT_BASE (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000))
Soren Brinkmannacff8a42016-04-11 15:30:56 -070079#define IPI_PMU_PM_INT_MASK (IPI_APU_IXR_PMU_0_MASK << PM_INT_NUM)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080080#if (PM_INT_NUM < 0 || PM_INT_NUM > 3)
81 #error PM_INT_NUM value out of range
82#endif
83
84#define IPI_APU_MASK 1U
85
Stefan Krsmanovicc5e9f662016-05-20 15:51:08 +020086DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080087
88const struct pm_ipi apu_ipi = {
89 .mask = IPI_APU_MASK,
90 .base = IPI_BASEADDR,
91 .buffer_base = IPI_BUFFER_APU_BASE,
92};
93
94/**
95 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
96 *
97 * @return On success, the initialization function must return 0.
98 * Any other return value will cause the framework to ignore
99 * the service
100 *
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800101 * Called from pm_setup initialization function
102 */
103int pm_ipi_init(void)
104{
105 bakery_lock_init(&pm_secure_lock);
106
107 /* IPI Interrupts Clear & Disable */
108 mmio_write_32(IPI_APU_ISR, 0xffffffff);
109 mmio_write_32(IPI_APU_IDR, 0xffffffff);
110
111 return 0;
112}
113
114/**
115 * pm_ipi_wait() - wait for pmu to handle request
116 * @proc proc which is waiting for PMU to handle request
117 */
118static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc)
119{
120 int status;
121
122 /* Wait until previous interrupt is handled by PMU */
123 do {
124 status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) &
125 IPI_PMU_PM_INT_MASK;
126 /* TODO: 1) Use timer to add delay between read attempts */
127 /* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */
128 } while (status);
129
130 return PM_RET_SUCCESS;
131}
132
133/**
134 * pm_ipi_send_common() - Sends IPI request to the PMU
135 * @proc Pointer to the processor who is initiating request
136 * @payload API id and call arguments to be written in IPI buffer
137 *
138 * Send an IPI request to the power controller. Caller needs to hold
139 * the 'pm_secure_lock' lock.
140 *
141 * @return Returns status, either success or error+reason
142 */
143static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
144 uint32_t payload[PAYLOAD_ARG_CNT])
145{
146 unsigned int offset = 0;
147 uintptr_t buffer_base = proc->ipi->buffer_base +
148 IPI_BUFFER_TARGET_PMU_OFFSET +
149 IPI_BUFFER_REQ_OFFSET;
150
151 /* Wait until previous interrupt is handled by PMU */
152 pm_ipi_wait(proc);
153
154 /* Write payload into IPI buffer */
155 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
156 mmio_write_32(buffer_base + offset, payload[i]);
157 offset += PAYLOAD_ARG_SIZE;
158 }
159 /* Generate IPI to PMU */
160 mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK);
161
162 return PM_RET_SUCCESS;
163}
164
165/**
166 * pm_ipi_send() - Sends IPI request to the PMU
167 * @proc Pointer to the processor who is initiating request
168 * @payload API id and call arguments to be written in IPI buffer
169 *
170 * Send an IPI request to the power controller.
171 *
172 * @return Returns status, either success or error+reason
173 */
174enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
175 uint32_t payload[PAYLOAD_ARG_CNT])
176{
177 enum pm_ret_status ret;
178
179 bakery_lock_get(&pm_secure_lock);
180
181 ret = pm_ipi_send_common(proc, payload);
182
183 bakery_lock_release(&pm_secure_lock);
184
185 return ret;
186}
187
188
189/**
190 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
191 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700192 * @value Used to return value from IPI buffer element (optional)
193 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800194 *
195 * @return Returns status, either success or error+reason
196 */
197static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700198 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800199{
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700200 size_t i;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800201 uintptr_t buffer_base = proc->ipi->buffer_base +
202 IPI_BUFFER_TARGET_PMU_OFFSET +
203 IPI_BUFFER_RESP_OFFSET;
204
205 pm_ipi_wait(proc);
206
207 /*
208 * Read response from IPI buffer
209 * buf-0: success or error+reason
210 * buf-1: value
211 * buf-2: unused
212 * buf-3: unused
213 */
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700214 for (i = 1; i <= count; i++) {
215 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
216 value++;
217 }
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800218
219 return mmio_read_32(buffer_base);
220}
221
222/**
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700223 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt
224 * @value Used to return value from IPI buffer element (optional)
225 * @count Number of values to return in @value
226 *
227 * @return Returns status, either success or error+reason
228 */
229void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
230{
231 size_t i;
232 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE +
233 IPI_BUFFER_TARGET_APU_OFFSET +
234 IPI_BUFFER_REQ_OFFSET;
235
236 if (count > IPI_BUFFER_MAX_WORDS)
237 count = IPI_BUFFER_MAX_WORDS;
238
239 for (i = 0; i <= count; i++) {
240 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
241 value++;
242 }
243}
244
245/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800246 * pm_ipi_send_sync() - Sends IPI request to the PMU
247 * @proc Pointer to the processor who is initiating request
248 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700249 * @value Used to return value from IPI buffer element (optional)
250 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800251 *
252 * Send an IPI request to the power controller and wait for it to be handled.
253 *
254 * @return Returns status, either success or error+reason and, optionally,
255 * @value
256 */
257enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
258 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700259 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800260{
261 enum pm_ret_status ret;
262
263 bakery_lock_get(&pm_secure_lock);
264
265 ret = pm_ipi_send_common(proc, payload);
266 if (ret != PM_RET_SUCCESS)
267 goto unlock;
268
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700269 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800270
271unlock:
272 bakery_lock_release(&pm_secure_lock);
273
274 return ret;
275}
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700276
277void pm_ipi_irq_enable(void)
278{
279 mmio_write_32(IPI_APU_IER, IPI_APU_IXR_PMU_0_MASK);
280}
281
282void pm_ipi_irq_disable(void)
283{
284 mmio_write_32(IPI_APU_IDR, IPI_APU_IXR_PMU_0_MASK);
285}
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700286
287void pm_ipi_irq_clear(void)
288{
289 mmio_write_32(IPI_APU_ISR, IPI_APU_IXR_PMU_0_MASK);
290}