blob: b3d833dfe294b215a030242aea5988d7121c38ce [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
Wendy Liang328105c2017-10-03 23:21:11 -07002 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
Soren Brinkmann76fcae32016-03-06 20:16:27 -08003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soren Brinkmann76fcae32016-03-06 20:16:27 -08005 */
6
Isla Mitchelle3631462017-07-14 10:46:32 +01007#include <arch_helpers.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008#include <lib/bakery_lock.h>
9#include <lib/mmio.h>
10#include <plat/common/platform.h>
11
Wendy Liang328105c2017-10-03 23:21:11 -070012#include "../zynqmp_ipi.h"
Soren Brinkmann76fcae32016-03-06 20:16:27 -080013#include "../zynqmp_private.h"
Isla Mitchelle3631462017-07-14 10:46:32 +010014#include "pm_ipi.h"
Soren Brinkmann76fcae32016-03-06 20:16:27 -080015
16/* IPI message buffers */
17#define IPI_BUFFER_BASEADDR 0xFF990000U
18
Soren Brinkmann76fcae32016-03-06 20:16:27 -080019#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080020#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
21
Soren Brinkmann76fcae32016-03-06 20:16:27 -080022#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
Soren Brinkmann76fcae32016-03-06 20:16:27 -080023#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U
24
Soren Brinkmann84f0af42016-09-30 14:24:25 -070025#define IPI_BUFFER_MAX_WORDS 8
26
Soren Brinkmann76fcae32016-03-06 20:16:27 -080027#define IPI_BUFFER_REQ_OFFSET 0x0U
28#define IPI_BUFFER_RESP_OFFSET 0x20U
29
Tejas Patelaf4b10e2018-02-09 02:42:59 -080030#define IPI_BLOCKING 1
31#define IPI_NON_BLOCKING 0
32
Stefan Krsmanovicc5e9f662016-05-20 15:51:08 +020033DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080034
35const struct pm_ipi apu_ipi = {
Wendy Liang328105c2017-10-03 23:21:11 -070036 .apu_ipi_id = IPI_ID_APU,
37 .pmu_ipi_id = IPI_ID_PMU0,
Soren Brinkmann76fcae32016-03-06 20:16:27 -080038 .buffer_base = IPI_BUFFER_APU_BASE,
39};
40
41/**
42 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
43 *
Wendy Liang328105c2017-10-03 23:21:11 -070044 * @proc Pointer to the processor who is initiating request
Soren Brinkmann76fcae32016-03-06 20:16:27 -080045 * @return On success, the initialization function must return 0.
46 * Any other return value will cause the framework to ignore
47 * the service
48 *
Soren Brinkmann76fcae32016-03-06 20:16:27 -080049 * Called from pm_setup initialization function
50 */
Wendy Liang328105c2017-10-03 23:21:11 -070051int pm_ipi_init(const struct pm_proc *proc)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080052{
53 bakery_lock_init(&pm_secure_lock);
Wendy Liang328105c2017-10-03 23:21:11 -070054 ipi_mb_open(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080055
56 return 0;
57}
58
59/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -080060 * pm_ipi_send_common() - Sends IPI request to the PMU
61 * @proc Pointer to the processor who is initiating request
62 * @payload API id and call arguments to be written in IPI buffer
63 *
64 * Send an IPI request to the power controller. Caller needs to hold
65 * the 'pm_secure_lock' lock.
66 *
67 * @return Returns status, either success or error+reason
68 */
69static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
Tejas Patelaf4b10e2018-02-09 02:42:59 -080070 uint32_t payload[PAYLOAD_ARG_CNT],
71 uint32_t is_blocking)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080072{
73 unsigned int offset = 0;
74 uintptr_t buffer_base = proc->ipi->buffer_base +
75 IPI_BUFFER_TARGET_PMU_OFFSET +
76 IPI_BUFFER_REQ_OFFSET;
77
Soren Brinkmann76fcae32016-03-06 20:16:27 -080078 /* Write payload into IPI buffer */
79 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
80 mmio_write_32(buffer_base + offset, payload[i]);
81 offset += PAYLOAD_ARG_SIZE;
82 }
Tejas Patelaf4b10e2018-02-09 02:42:59 -080083
Soren Brinkmann76fcae32016-03-06 20:16:27 -080084 /* Generate IPI to PMU */
Tejas Patelaf4b10e2018-02-09 02:42:59 -080085 ipi_mb_notify(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id,
86 is_blocking);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080087
88 return PM_RET_SUCCESS;
89}
90
91/**
Tejas Patelaf4b10e2018-02-09 02:42:59 -080092 * pm_ipi_send_non_blocking() - Sends IPI request to the PMU without blocking
93 * notification
94 * @proc Pointer to the processor who is initiating request
95 * @payload API id and call arguments to be written in IPI buffer
96 *
97 * Send an IPI request to the power controller.
98 *
99 * @return Returns status, either success or error+reason
100 */
101enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
102 uint32_t payload[PAYLOAD_ARG_CNT])
103{
104 enum pm_ret_status ret;
105
106 bakery_lock_get(&pm_secure_lock);
107
108 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
109
110 bakery_lock_release(&pm_secure_lock);
111
112 return ret;
113}
114
115/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800116 * pm_ipi_send() - Sends IPI request to the PMU
117 * @proc Pointer to the processor who is initiating request
118 * @payload API id and call arguments to be written in IPI buffer
119 *
120 * Send an IPI request to the power controller.
121 *
122 * @return Returns status, either success or error+reason
123 */
124enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
125 uint32_t payload[PAYLOAD_ARG_CNT])
126{
127 enum pm_ret_status ret;
128
129 bakery_lock_get(&pm_secure_lock);
130
Tejas Patelaf4b10e2018-02-09 02:42:59 -0800131 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800132
133 bakery_lock_release(&pm_secure_lock);
134
135 return ret;
136}
137
138
139/**
140 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
141 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700142 * @value Used to return value from IPI buffer element (optional)
143 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800144 *
145 * @return Returns status, either success or error+reason
146 */
147static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700148 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800149{
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700150 size_t i;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800151 uintptr_t buffer_base = proc->ipi->buffer_base +
152 IPI_BUFFER_TARGET_PMU_OFFSET +
153 IPI_BUFFER_RESP_OFFSET;
154
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800155 /*
156 * Read response from IPI buffer
157 * buf-0: success or error+reason
158 * buf-1: value
159 * buf-2: unused
160 * buf-3: unused
161 */
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700162 for (i = 1; i <= count; i++) {
163 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
164 value++;
165 }
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800166
167 return mmio_read_32(buffer_base);
168}
169
170/**
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700171 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt
172 * @value Used to return value from IPI buffer element (optional)
173 * @count Number of values to return in @value
174 *
175 * @return Returns status, either success or error+reason
176 */
177void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
178{
179 size_t i;
180 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE +
181 IPI_BUFFER_TARGET_APU_OFFSET +
182 IPI_BUFFER_REQ_OFFSET;
183
184 if (count > IPI_BUFFER_MAX_WORDS)
185 count = IPI_BUFFER_MAX_WORDS;
186
187 for (i = 0; i <= count; i++) {
188 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
189 value++;
190 }
191}
192
193/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800194 * pm_ipi_send_sync() - Sends IPI request to the PMU
195 * @proc Pointer to the processor who is initiating request
196 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700197 * @value Used to return value from IPI buffer element (optional)
198 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800199 *
200 * Send an IPI request to the power controller and wait for it to be handled.
201 *
202 * @return Returns status, either success or error+reason and, optionally,
203 * @value
204 */
205enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
206 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700207 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800208{
209 enum pm_ret_status ret;
210
211 bakery_lock_get(&pm_secure_lock);
212
Tejas Patelaf4b10e2018-02-09 02:42:59 -0800213 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800214 if (ret != PM_RET_SUCCESS)
215 goto unlock;
216
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700217 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800218
219unlock:
220 bakery_lock_release(&pm_secure_lock);
221
222 return ret;
223}
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700224
Wendy Liang328105c2017-10-03 23:21:11 -0700225void pm_ipi_irq_enable(const struct pm_proc *proc)
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700226{
Wendy Liang328105c2017-10-03 23:21:11 -0700227 ipi_mb_enable_irq(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700228}
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700229
Wendy Liang328105c2017-10-03 23:21:11 -0700230void pm_ipi_irq_clear(const struct pm_proc *proc)
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700231{
Wendy Liang328105c2017-10-03 23:21:11 -0700232 ipi_mb_ack(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700233}