blob: 58faf0e706d3a9fb2cf10c6704c32fda0d6fb1cd [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
Stefan Krsmanovicc5e9f662016-05-20 15:51:08 +020029DEFINE_BAKERY_LOCK(pm_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080030
31const struct pm_ipi apu_ipi = {
Wendy Liang328105c2017-10-03 23:21:11 -070032 .apu_ipi_id = IPI_ID_APU,
33 .pmu_ipi_id = IPI_ID_PMU0,
Soren Brinkmann76fcae32016-03-06 20:16:27 -080034 .buffer_base = IPI_BUFFER_APU_BASE,
35};
36
37/**
38 * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
39 *
Wendy Liang328105c2017-10-03 23:21:11 -070040 * @proc Pointer to the processor who is initiating request
Soren Brinkmann76fcae32016-03-06 20:16:27 -080041 * @return On success, the initialization function must return 0.
42 * Any other return value will cause the framework to ignore
43 * the service
44 *
Soren Brinkmann76fcae32016-03-06 20:16:27 -080045 * Called from pm_setup initialization function
46 */
Wendy Liang328105c2017-10-03 23:21:11 -070047int pm_ipi_init(const struct pm_proc *proc)
Soren Brinkmann76fcae32016-03-06 20:16:27 -080048{
49 bakery_lock_init(&pm_secure_lock);
Wendy Liang328105c2017-10-03 23:21:11 -070050 ipi_mb_open(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080051
52 return 0;
53}
54
55/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -080056 * pm_ipi_send_common() - Sends IPI request to the PMU
57 * @proc Pointer to the processor who is initiating request
58 * @payload API id and call arguments to be written in IPI buffer
59 *
60 * Send an IPI request to the power controller. Caller needs to hold
61 * the 'pm_secure_lock' lock.
62 *
63 * @return Returns status, either success or error+reason
64 */
65static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
66 uint32_t payload[PAYLOAD_ARG_CNT])
67{
68 unsigned int offset = 0;
69 uintptr_t buffer_base = proc->ipi->buffer_base +
70 IPI_BUFFER_TARGET_PMU_OFFSET +
71 IPI_BUFFER_REQ_OFFSET;
72
Soren Brinkmann76fcae32016-03-06 20:16:27 -080073 /* Write payload into IPI buffer */
74 for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
75 mmio_write_32(buffer_base + offset, payload[i]);
76 offset += PAYLOAD_ARG_SIZE;
77 }
78 /* Generate IPI to PMU */
Wendy Liang328105c2017-10-03 23:21:11 -070079 ipi_mb_notify(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id, 1);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080080
81 return PM_RET_SUCCESS;
82}
83
84/**
85 * pm_ipi_send() - Sends IPI request to the PMU
86 * @proc Pointer to the processor who is initiating request
87 * @payload API id and call arguments to be written in IPI buffer
88 *
89 * Send an IPI request to the power controller.
90 *
91 * @return Returns status, either success or error+reason
92 */
93enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
94 uint32_t payload[PAYLOAD_ARG_CNT])
95{
96 enum pm_ret_status ret;
97
98 bakery_lock_get(&pm_secure_lock);
99
100 ret = pm_ipi_send_common(proc, payload);
101
102 bakery_lock_release(&pm_secure_lock);
103
104 return ret;
105}
106
107
108/**
109 * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
110 * @proc Pointer to the processor who is waiting and reading response
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700111 * @value Used to return value from IPI buffer element (optional)
112 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800113 *
114 * @return Returns status, either success or error+reason
115 */
116static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700117 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800118{
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700119 size_t i;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800120 uintptr_t buffer_base = proc->ipi->buffer_base +
121 IPI_BUFFER_TARGET_PMU_OFFSET +
122 IPI_BUFFER_RESP_OFFSET;
123
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800124 /*
125 * Read response from IPI buffer
126 * buf-0: success or error+reason
127 * buf-1: value
128 * buf-2: unused
129 * buf-3: unused
130 */
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700131 for (i = 1; i <= count; i++) {
132 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
133 value++;
134 }
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800135
136 return mmio_read_32(buffer_base);
137}
138
139/**
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700140 * pm_ipi_buff_read_callb() - Reads IPI response after PMU has handled interrupt
141 * @value Used to return value from IPI buffer element (optional)
142 * @count Number of values to return in @value
143 *
144 * @return Returns status, either success or error+reason
145 */
146void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
147{
148 size_t i;
149 uintptr_t buffer_base = IPI_BUFFER_PMU_BASE +
150 IPI_BUFFER_TARGET_APU_OFFSET +
151 IPI_BUFFER_REQ_OFFSET;
152
153 if (count > IPI_BUFFER_MAX_WORDS)
154 count = IPI_BUFFER_MAX_WORDS;
155
156 for (i = 0; i <= count; i++) {
157 *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
158 value++;
159 }
160}
161
162/**
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800163 * pm_ipi_send_sync() - Sends IPI request to the PMU
164 * @proc Pointer to the processor who is initiating request
165 * @payload API id and call arguments to be written in IPI buffer
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700166 * @value Used to return value from IPI buffer element (optional)
167 * @count Number of values to return in @value
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800168 *
169 * Send an IPI request to the power controller and wait for it to be handled.
170 *
171 * @return Returns status, either success or error+reason and, optionally,
172 * @value
173 */
174enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
175 uint32_t payload[PAYLOAD_ARG_CNT],
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700176 unsigned int *value, size_t count)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800177{
178 enum pm_ret_status ret;
179
180 bakery_lock_get(&pm_secure_lock);
181
182 ret = pm_ipi_send_common(proc, payload);
183 if (ret != PM_RET_SUCCESS)
184 goto unlock;
185
Soren Brinkmannd6c9e032016-09-22 11:35:47 -0700186 ret = pm_ipi_buff_read(proc, value, count);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800187
188unlock:
189 bakery_lock_release(&pm_secure_lock);
190
191 return ret;
192}
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700193
Wendy Liang328105c2017-10-03 23:21:11 -0700194void pm_ipi_irq_enable(const struct pm_proc *proc)
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700195{
Wendy Liang328105c2017-10-03 23:21:11 -0700196 ipi_mb_enable_irq(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmanna1b0a902016-09-30 11:30:21 -0700197}
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700198
Wendy Liang328105c2017-10-03 23:21:11 -0700199void pm_ipi_irq_clear(const struct pm_proc *proc)
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700200{
Wendy Liang328105c2017-10-03 23:21:11 -0700201 ipi_mb_ack(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id);
Soren Brinkmann84f0af42016-09-30 14:24:25 -0700202}