1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 * Copyright (c) 2015 Xilinx, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of Mentor Graphics Corporation nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific 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 */
31 /**************************************************************************
32 * FILE NAME
33 *
34 * zynqmp_remoteproc_r5.c
35 *
36 * DESCRIPTION
37 *
38 * This file is the Implementation of IPC hardware layer interface
39 * for Xilinx Zynq UltraScale+ MPSoC system.
40 *
41 **************************************************************************/
43 #include <errno.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include "metal/io.h"
47 #include "metal/device.h"
48 #include "metal/utilities.h"
49 #include "metal/atomic.h"
50 #include "metal/irq.h"
51 #include "metal/cpu.h"
52 #include "metal/alloc.h"
53 #include "openamp/hil.h"
54 #include "openamp/virtqueue.h"
56 /* IPI REGs OFFSET */
57 #define IPI_TRIG_OFFSET 0x00000000 /** IPI trigger register offset */
58 #define IPI_OBS_OFFSET 0x00000004 /** IPI observation register offset */
59 #define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
60 #define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
61 #define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
62 #define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
64 #define _rproc_wait() metal_cpu_yield()
66 #define DEBUG 1
68 /* -- FIX ME: ipi info is to be defined -- */
69 struct ipi_info {
70 const char *name;
71 const char *bus_name;
72 struct metal_device *dev;
73 struct metal_io_region *io;
74 metal_phys_addr_t paddr;
75 uint32_t ipi_chn_mask;
76 int need_reg;
77 atomic_int sync;
78 };
80 /*--------------------------- Declare Functions ------------------------ */
81 static int _enable_interrupt(struct proc_intr *intr);
82 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
83 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
84 static void _shutdown_cpu(struct hil_proc *proc);
85 static int _poll(struct hil_proc *proc, int nonblock);
86 static int _initialize(struct hil_proc *proc);
87 static void _release(struct hil_proc *proc);
89 /*--------------------------- Globals ---------------------------------- */
90 struct hil_platform_ops zynqmp_a53_r5_proc_ops = {
91 .enable_interrupt = _enable_interrupt,
92 .notify = _notify,
93 .boot_cpu = _boot_cpu,
94 .shutdown_cpu = _shutdown_cpu,
95 .poll = _poll,
96 .initialize = _initialize,
97 .release = _release,
98 };
100 static int _enable_interrupt(struct proc_intr *intr)
101 {
102 (void)intr;
103 return 0;
104 }
106 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
107 {
109 (void)proc;
110 struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
111 if (ipi == NULL)
112 return;
114 /* Trigger IPI */
115 metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
116 }
118 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
119 {
120 (void)proc;
121 (void)load_addr;
122 return -1;
123 }
125 static void _shutdown_cpu(struct hil_proc *proc)
126 {
127 (void)proc;
128 return;
129 }
131 static int _poll(struct hil_proc *proc, int nonblock)
132 {
133 struct proc_vring *vring;
134 struct ipi_info *ipi;
135 struct metal_io_region *io;
137 vring = &proc->vdev.vring_info[0];
138 ipi = (struct ipi_info *)(vring->intr_info.data);
139 io = ipi->io;
140 while(1) {
141 unsigned int ipi_intr_status =
142 (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
143 if (ipi_intr_status & ipi->ipi_chn_mask) {
144 metal_io_write32(io, IPI_ISR_OFFSET,
145 ipi->ipi_chn_mask);
146 virtqueue_notification(vring->vq);
147 return 0;
148 } else if (nonblock) {
149 return -EAGAIN;
150 }
151 _rproc_wait();
152 }
153 }
155 static int _initialize(struct hil_proc *proc)
156 {
157 int ret;
158 struct proc_intr *intr_info;
159 struct ipi_info *ipi;
160 unsigned int ipi_intr_status;
161 int i;
163 if (!proc)
164 return -1;
166 for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
167 intr_info = &(proc->vdev.vring_info[i].intr_info);
168 ipi = intr_info->data;
170 if (ipi && ipi->name && ipi->bus_name) {
171 ret = metal_device_open(ipi->bus_name, ipi->name,
172 &ipi->dev);
173 if (ret)
174 return -ENODEV;
175 ipi->io = metal_device_io_region(ipi->dev, 0);
176 intr_info->vect_id = (uintptr_t)ipi->dev->irq_info;
177 } else if (ipi->paddr) {
178 ipi->io = metal_allocate_memory(
179 sizeof(struct metal_io_region));
180 if (!ipi->io)
181 goto error;
182 metal_io_init(ipi->io, (void *)ipi->paddr,
183 &ipi->paddr, 0x1000,
184 (unsigned)(-1),
185 METAL_UNCACHED | METAL_IO_MAPPED,
186 NULL);
187 }
189 if (ipi->io) {
190 ipi_intr_status = (unsigned int)metal_io_read32(
191 ipi->io, IPI_ISR_OFFSET);
192 if (ipi_intr_status & ipi->ipi_chn_mask)
193 metal_io_write32(ipi->io, IPI_ISR_OFFSET,
194 ipi->ipi_chn_mask);
195 metal_io_write32(ipi->io, IPI_IDR_OFFSET,
196 ipi->ipi_chn_mask);
197 atomic_store(&ipi->sync, 1);
198 }
199 }
200 return 0;
202 error:
203 _release(proc);
204 return -1;
205 }
207 static void _release(struct hil_proc *proc)
208 {
209 int i;
210 struct proc_intr *intr_info;
211 struct ipi_info *ipi;
213 if (!proc)
214 return;
215 for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
216 intr_info = &(proc->vdev.vring_info[1].intr_info);
217 ipi = (struct ipi_info *)(intr_info->data);
218 if (ipi) {
219 if (ipi->io) {
220 metal_io_write32(ipi->io, IPI_IDR_OFFSET,
221 ipi->ipi_chn_mask);
222 if (ipi->dev) {
223 metal_device_close(ipi->dev);
224 ipi->dev = NULL;
225 } else {
226 metal_free_memory(ipi->io);
227 }
228 ipi->io = NULL;
229 }
230 }
232 }
233 }