remoteproc: drivers: update enable_interrupt()
[processor-sdk/open-amp.git] / lib / remoteproc / drivers / zynqmp_remoteproc_r5.c
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)
102         (void)intr;
103         return 0;
106 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
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);
118 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
120         (void)proc;
121         (void)load_addr;
122         return -1;
125 static void _shutdown_cpu(struct hil_proc *proc)
127         (void)proc;
128         return;
131 static int _poll(struct hil_proc *proc, int nonblock)
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         }
155 static int _initialize(struct hil_proc *proc)
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;
207 static void _release(struct hil_proc *proc)
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         }