blob: c73c92fc9540cc7ab4160ef62600a256f9982200 [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
Jolly Shah5bd029b2019-01-07 12:53:32 -080024#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
25#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMU_BASE
26
27#define IPI_BUFFER_TARGET_LOCAL_OFFSET 0x80U
28#define IPI_BUFFER_TARGET_REMOTE_OFFSET 0x1C0U
Soren Brinkmannc8284402016-03-06 20:16:27 -080029
Soren Brinkmann300cbb02016-09-30 14:24:25 -070030#define IPI_BUFFER_MAX_WORDS 8
31
Soren Brinkmannc8284402016-03-06 20:16:27 -080032#define IPI_BUFFER_REQ_OFFSET 0x0U
33#define IPI_BUFFER_RESP_OFFSET 0x20U
34
Tejas Patel7dae6132018-02-09 02:42:59 -080035#define IPI_BLOCKING 1
36#define IPI_NON_BLOCKING 0
37
Stefan Krsmanovic8212f1f2016-05-20 15:51:08 +020038DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmannc8284402016-03-06 20:16:27 -080039
40const struct pm_ipi apu_ipi = {
Jolly Shah28e4d372019-01-07 12:51:40 -080041 .local_ipi_id = IPI_ID_APU,
42 .remote_ipi_id = IPI_ID_PMU0,
Soren Brinkmannc8284402016-03-06 20:16:27 -080043 .buffer_base = IPI_BUFFER_APU_BASE,
44};
45
46/**
Jolly Shah5bd029b2019-01-07 12:53:32 -080047 * pm_ipi_init() - Initialize IPI peripheral for communication with
48 * remote processor
Soren Brinkmannc8284402016-03-06 20:16:27 -080049 *
Wendy Liangebc05162017-10-03 23:21:11 -070050 * @proc Pointer to the processor who is initiating request
Soren Brinkmannc8284402016-03-06 20:16:27 -080051 * @return On success, the initialization function must return 0.
52 * Any other return value will cause the framework to ignore
53 * the service
54 *
Soren Brinkmannc8284402016-03-06 20:16:27 -080055 * Called from pm_setup initialization function
56 */
Wendy Liangebc05162017-10-03 23:21:11 -070057int pm_ipi_init(const struct pm_proc *proc)
Soren Brinkmannc8284402016-03-06 20:16:27 -080058{
59 bakery_lock_init(&pm_secure_lock);
Jolly Shah28e4d372019-01-07 12:51:40 -080060 ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
Soren Brinkmannc8284402016-03-06 20:16:27 -080061
62 return 0;
63}
64
65/**
Jolly Shah5bd029b2019-01-07 12:53:32 -080066 * pm_ipi_send_common() - Sends IPI request to the remote processor
Soren Brinkmannc8284402016-03-06 20:16:27 -080067 * @proc Pointer to the processor who is initiating request
68 * @payload API id and call arguments to be written in IPI buffer
69 *
70 * Send an IPI request to the power controller. Caller needs to hold
71 * the 'pm_secure_lock' lock.
72 *
73 * @return Returns status, either success or error+reason
74 */
75static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
Tejas Patel7dae6132018-02-09 02:42:59 -080076 uint32_t payload[PAYLOAD_ARG_CNT],
77 uint32_t is_blocking)
Soren Brinkmannc8284402016-03-06 20:16:27 -080078{
79 unsigned int offset = 0;
80 uintptr_t buffer_base = proc->ipi->buffer_base +
Jolly Shah5bd029b2019-01-07 12:53:32 -080081 IPI_BUFFER_TARGET_REMOTE_OFFSET +
Soren Brinkmannc8284402016-03-06 20:16:27 -080082 IPI_BUFFER_REQ_OFFSET;
83
Soren Brinkmannc8284402016-03-06 20:16:27 -080084 /* Write payload into IPI buffer */
85 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
86 mmio_write_32(buffer_base + offset, payload[i]);
87 offset += PAYLOAD_ARG_SIZE;
88 }
Tejas Patel7dae6132018-02-09 02:42:59 -080089
Jolly Shah5bd029b2019-01-07 12:53:32 -080090 /* Generate IPI to remote processor */
Jolly Shah28e4d372019-01-07 12:51:40 -080091 ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id,
Tejas Patel7dae6132018-02-09 02:42:59 -080092 is_blocking);
Soren Brinkmannc8284402016-03-06 20:16:27 -080093
94 return PM_RET_SUCCESS;
95}
96
97/**
Jolly Shah5bd029b2019-01-07 12:53:32 -080098 * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor
99 * without blocking notification
Tejas Patel7dae6132018-02-09 02:42:59 -0800100 * @proc Pointer to the processor who is initiating request
101 * @payload API id and call arguments to be written in IPI buffer
102 *
103 * Send an IPI request to the power controller.
104 *
105 * @return Returns status, either success or error+reason
106 */
107enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
108 uint32_t payload[PAYLOAD_ARG_CNT])
109{
110 enum pm_ret_status ret;
111
112 bakery_lock_get(&pm_secure_lock);
113
114 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
115
116 bakery_lock_release(&pm_secure_lock);
117
118 return ret;
119}
120
121/**
Jolly Shah5bd029b2019-01-07 12:53:32 -0800122 * pm_ipi_send() - Sends IPI request to the remote processor
Soren Brinkmannc8284402016-03-06 20:16:27 -0800123 * @proc Pointer to the processor who is initiating request
124 * @payload API id and call arguments to be written in IPI buffer
125 *
126 * Send an IPI request to the power controller.
127 *
128 * @return Returns status, either success or error+reason
129 */
130enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
131 uint32_t payload[PAYLOAD_ARG_CNT])
132{
133 enum pm_ret_status ret;
134
135 bakery_lock_get(&pm_secure_lock);
136
Tejas Patel7dae6132018-02-09 02:42:59 -0800137 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800138
139 bakery_lock_release(&pm_secure_lock);
140
141 return ret;
142}
143
144
145/**
Jolly Shah5bd029b2019-01-07 12:53:32 -0800146 * pm_ipi_buff_read() - Reads IPI response after remote processor has handled
147 * interrupt
Soren Brinkmannc8284402016-03-06 20:16:27 -0800148 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700149 * @value Used to return value from IPI buffer element (optional)
150 * @count Number of values to return in @value
Soren Brinkmannc8284402016-03-06 20:16:27 -0800151 *
152 * @return Returns status, either success or error+reason
153 */
154static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700155 unsigned int *value, size_t count)
Soren Brinkmannc8284402016-03-06 20:16:27 -0800156{
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700157 size_t i;
Soren Brinkmannc8284402016-03-06 20:16:27 -0800158 uintptr_t buffer_base = proc->ipi->buffer_base +
Jolly Shah5bd029b2019-01-07 12:53:32 -0800159 IPI_BUFFER_TARGET_REMOTE_OFFSET +
Soren Brinkmannc8284402016-03-06 20:16:27 -0800160 IPI_BUFFER_RESP_OFFSET;
161
Soren Brinkmannc8284402016-03-06 20:16:27 -0800162 /*
163 * Read response from IPI buffer
164 * buf-0: success or error+reason
165 * buf-1: value
166 * buf-2: unused
167 * buf-3: unused
168 */
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700169 for (i = 1; i <= count; i++) {
170 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
171 value++;
172 }
Soren Brinkmannc8284402016-03-06 20:16:27 -0800173
174 return mmio_read_32(buffer_base);
175}
176
177/**
Jolly Shah5bd029b2019-01-07 12:53:32 -0800178 * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has
179 * handled interrupt
Soren Brinkmann300cbb02016-09-30 14:24:25 -0700180 * @value Used to return value from IPI buffer element (optional)
181 * @count Number of values to return in @value
182 *
183 * @return Returns status, either success or error+reason
184 */
185void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
186{
187 size_t i;
Jolly Shah5bd029b2019-01-07 12:53:32 -0800188 uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
189 IPI_BUFFER_TARGET_LOCAL_OFFSET +
Soren Brinkmann300cbb02016-09-30 14:24:25 -0700190 IPI_BUFFER_REQ_OFFSET;
191
192 if (count > IPI_BUFFER_MAX_WORDS)
193 count = IPI_BUFFER_MAX_WORDS;
194
195 for (i = 0; i <= count; i++) {
196 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
197 value++;
198 }
199}
200
201/**
Jolly Shah5bd029b2019-01-07 12:53:32 -0800202 * pm_ipi_send_sync() - Sends IPI request to the remote processor
Soren Brinkmannc8284402016-03-06 20:16:27 -0800203 * @proc Pointer to the processor who is initiating request
204 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700205 * @value Used to return value from IPI buffer element (optional)
206 * @count Number of values to return in @value
Soren Brinkmannc8284402016-03-06 20:16:27 -0800207 *
208 * Send an IPI request to the power controller and wait for it to be handled.
209 *
210 * @return Returns status, either success or error+reason and, optionally,
211 * @value
212 */
213enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
214 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700215 unsigned int *value, size_t count)
Soren Brinkmannc8284402016-03-06 20:16:27 -0800216{
217 enum pm_ret_status ret;
218
219 bakery_lock_get(&pm_secure_lock);
220
Tejas Patel7dae6132018-02-09 02:42:59 -0800221 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800222 if (ret != PM_RET_SUCCESS)
223 goto unlock;
224
Soren Brinkmanndc0c5a42016-09-22 11:35:47 -0700225 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmannc8284402016-03-06 20:16:27 -0800226
227unlock:
228 bakery_lock_release(&pm_secure_lock);
229
230 return ret;
231}
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700232
Wendy Liangebc05162017-10-03 23:21:11 -0700233void pm_ipi_irq_enable(const struct pm_proc *proc)
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700234{
Jolly Shah28e4d372019-01-07 12:51:40 -0800235 ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700236}
237
Wendy Liangebc05162017-10-03 23:21:11 -0700238void pm_ipi_irq_clear(const struct pm_proc *proc)
Soren Brinkmanna76c3692016-09-30 11:30:21 -0700239{
Jolly Shah28e4d372019-01-07 12:51:40 -0800240 ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
Soren Brinkmann300cbb02016-09-30 14:24:25 -0700241}