blob: dc1ea4d1229121ee9fca9b7a81592e724484cbd5 [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>
Soren Brinkmann76fcae32016-03-06 20:16:27 -08008#include <bakery_lock.h>
9#include <mmio.h>
10#include <platform.h>
Wendy Liang328105c2017-10-03 23:21:11 -070011#include "../zynqmp_ipi.h"
Soren Brinkmann76fcae32016-03-06 20:16:27 -080012#include "../zynqmp_private.h"
Isla Mitchelle3631462017-07-14 10:46:32 +010013#include "pm_ipi.h"
Soren Brinkmann76fcae32016-03-06 20:16:27 -080014
15/* IPI message buffers */
16#define IPI_BUFFER_BASEADDR 0xFF990000U
17
Soren Brinkmann76fcae32016-03-06 20:16:27 -080018#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080019#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
20
Soren Brinkmann76fcae32016-03-06 20:16:27 -080021#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
Soren Brinkmann76fcae32016-03-06 20:16:27 -080022#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U
23
Soren Brinkmann84f0af42016-09-30 14:24:25 -070024#define IPI_BUFFER_MAX_WORDS 8
25
Soren Brinkmann76fcae32016-03-06 20:16:27 -080026#define IPI_BUFFER_REQ_OFFSET 0x0U
27#define IPI_BUFFER_RESP_OFFSET 0x20U
28
Tejas Patelaf4b10e2018-02-09 02:42:59 -080029#define IPI_BLOCKING 1
30#define IPI_NON_BLOCKING 0
31
Stefan Krsmanovicc5e9f662016-05-20 15:51:08 +020032DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080033
34const struct pm_ipi apu_ipi = {
Wendy Liang328105c2017-10-03 23:21:11 -070035 .apu_ipi_id = IPI_ID_APU,
36 .pmu_ipi_id = IPI_ID_PMU0,
Soren Brinkmann76fcae32016-03-06 20:16:27 -080037 .buffer_base = IPI_BUFFER_APU_BASE,
38};
39
40/**
41 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
42 *
Wendy Liang328105c2017-10-03 23:21:11 -070043 * @proc Pointer to the processor who is initiating request
Soren Brinkmann76fcae32016-03-06 20:16:27 -080044 * @return On success, the initialization function must return 0.
45 * Any other return value will cause the framework to ignore
46 * the service
47 *
Soren Brinkmann76fcae32016-03-06 20:16:27 -080048 * Called from pm_setup initialization function
49 */
Wendy Liang328105c2017-10-03 23:21:11 -070050int pm_ipi_init(const struct pm_proc *proc)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080051{
52 bakery_lock_init(&pm_secure_lock);
Wendy Liang328105c2017-10-03 23:21:11 -070053 ipi_mb_open(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080054
55 return 0;
56}
57
58/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -080059 * pm_ipi_send_common() - Sends IPI request to the PMU
60 * @proc Pointer to the processor who is initiating request
61 * @payload API id and call arguments to be written in IPI buffer
62 *
63 * Send an IPI request to the power controller. Caller needs to hold
64 * the 'pm_secure_lock' lock.
65 *
66 * @return Returns status, either success or error+reason
67 */
68static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
Tejas Patelaf4b10e2018-02-09 02:42:59 -080069 uint32_t payload[PAYLOAD_ARG_CNT],
70 uint32_t is_blocking)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080071{
72 unsigned int offset = 0;
73 uintptr_t buffer_base = proc->ipi->buffer_base +
74 IPI_BUFFER_TARGET_PMU_OFFSET +
75 IPI_BUFFER_REQ_OFFSET;
76
Soren Brinkmann76fcae32016-03-06 20:16:27 -080077 /* Write payload into IPI buffer */
78 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
79 mmio_write_32(buffer_base + offset, payload[i]);
80 offset += PAYLOAD_ARG_SIZE;
81 }
Tejas Patelaf4b10e2018-02-09 02:42:59 -080082
Soren Brinkmann76fcae32016-03-06 20:16:27 -080083 /* Generate IPI to PMU */
Tejas Patelaf4b10e2018-02-09 02:42:59 -080084 ipi_mb_notify(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id,
85 is_blocking);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080086
87 return PM_RET_SUCCESS;
88}
89
90/**
Tejas Patelaf4b10e2018-02-09 02:42:59 -080091 * pm_ipi_send_non_blocking() - Sends IPI request to the PMU without blocking
92 * notification
93 * @proc Pointer to the processor who is initiating request
94 * @payload API id and call arguments to be written in IPI buffer
95 *
96 * Send an IPI request to the power controller.
97 *
98 * @return Returns status, either success or error+reason
99 */
100enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
101 uint32_t payload[PAYLOAD_ARG_CNT])
102{
103 enum pm_ret_status ret;
104
105 bakery_lock_get(&pm_secure_lock);
106
107 ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
108
109 bakery_lock_release(&pm_secure_lock);
110
111 return ret;
112}
113
114/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800115 * pm_ipi_send() - Sends IPI request to the PMU
116 * @proc Pointer to the processor who is initiating request
117 * @payload API id and call arguments to be written in IPI buffer
118 *
119 * Send an IPI request to the power controller.
120 *
121 * @return Returns status, either success or error+reason
122 */
123enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
124 uint32_t payload[PAYLOAD_ARG_CNT])
125{
126 enum pm_ret_status ret;
127
128 bakery_lock_get(&pm_secure_lock);
129
Tejas Patelaf4b10e2018-02-09 02:42:59 -0800130 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800131
132 bakery_lock_release(&pm_secure_lock);
133
134 return ret;
135}
136
137
138/**
139 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
140 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700141 * @value Used to return value from IPI buffer element (optional)
142 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800143 *
144 * @return Returns status, either success or error+reason
145 */
146static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700147 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800148{
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700149 size_t i;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800150 uintptr_t buffer_base = proc->ipi->buffer_base +
151 IPI_BUFFER_TARGET_PMU_OFFSET +
152 IPI_BUFFER_RESP_OFFSET;
153
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800154 /*
155 * Read response from IPI buffer
156 * buf-0: success or error+reason
157 * buf-1: value
158 * buf-2: unused
159 * buf-3: unused
160 */
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700161 for (i = 1; i <= count; i++) {
162 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
163 value++;
164 }
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800165
166 return mmio_read_32(buffer_base);
167}
168
169/**
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700170 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt
171 * @value Used to return value from IPI buffer element (optional)
172 * @count Number of values to return in @value
173 *
174 * @return Returns status, either success or error+reason
175 */
176void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
177{
178 size_t i;
179 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE +
180 IPI_BUFFER_TARGET_APU_OFFSET +
181 IPI_BUFFER_REQ_OFFSET;
182
183 if (count > IPI_BUFFER_MAX_WORDS)
184 count = IPI_BUFFER_MAX_WORDS;
185
186 for (i = 0; i <= count; i++) {
187 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
188 value++;
189 }
190}
191
192/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800193 * pm_ipi_send_sync() - Sends IPI request to the PMU
194 * @proc Pointer to the processor who is initiating request
195 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700196 * @value Used to return value from IPI buffer element (optional)
197 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800198 *
199 * Send an IPI request to the power controller and wait for it to be handled.
200 *
201 * @return Returns status, either success or error+reason and, optionally,
202 * @value
203 */
204enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
205 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700206 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800207{
208 enum pm_ret_status ret;
209
210 bakery_lock_get(&pm_secure_lock);
211
Tejas Patelaf4b10e2018-02-09 02:42:59 -0800212 ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800213 if (ret != PM_RET_SUCCESS)
214 goto unlock;
215
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700216 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800217
218unlock:
219 bakery_lock_release(&pm_secure_lock);
220
221 return ret;
222}
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700223
Wendy Liang328105c2017-10-03 23:21:11 -0700224void pm_ipi_irq_enable(const struct pm_proc *proc)
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700225{
Wendy Liang328105c2017-10-03 23:21:11 -0700226 ipi_mb_enable_irq(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700227}
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700228
Wendy Liang328105c2017-10-03 23:21:11 -0700229void pm_ipi_irq_clear(const struct pm_proc *proc)
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700230{
Wendy Liang328105c2017-10-03 23:21:11 -0700231 ipi_mb_ack(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700232}