Remove remoteproc_plat from ZynqMP R5 rproc driver
[processor-sdk/open-amp.git] / lib / remoteproc / drivers / zynqmp_remoteproc_a53.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  *       platform.c
35  *
36  * DESCRIPTION
37  *
38  *       This file is the Implementation of IPC hardware layer interface
39  *       for Xilinx Zynq ZC702EVK platform.
40  *
41  **************************************************************************/
43 #include <errno.h>
44 #include <string.h>
45 #include "metal/io.h"
46 #include "metal/device.h"
47 #include "metal/utilities.h"
48 #include "metal/atomic.h"
49 #include "metal/irq.h"
50 #include "metal/alloc.h"
51 #include "openamp/hil.h"
52 #include "openamp/virtqueue.h"
54 /* IPI REGs OFFSET */
55 #define IPI_TRIG_OFFSET          0x00000000    /* IPI trigger register offset */
56 #define IPI_OBS_OFFSET           0x00000004    /* IPI observation register offset */
57 #define IPI_ISR_OFFSET           0x00000010    /* IPI interrupt status register offset */
58 #define IPI_IMR_OFFSET           0x00000014    /* IPI interrupt mask register offset */
59 #define IPI_IER_OFFSET           0x00000018    /* IPI interrupt enable register offset */
60 #define IPI_IDR_OFFSET           0x0000001C    /* IPI interrupt disable register offset */
62 #define _rproc_wait() asm volatile("wfi")
64 /* -- FIX ME: ipi info is to be defined -- */
65 struct ipi_info {
66         const char *name;
67         const char *bus_name;
68         struct metal_device *dev;
69         struct metal_io_region *io;
70         metal_phys_addr_t paddr;
71         uint32_t ipi_chn_mask;
72         int need_reg;
73         atomic_int sync;
74 };
76 /*--------------------------- Declare Functions ------------------------ */
77 static int _enable_interrupt(struct proc_vring *vring_hw);
78 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
79 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
80 static void _shutdown_cpu(struct hil_proc *proc);
81 static int _poll(struct hil_proc *proc, int nonblock);
82 static int _initialize(struct hil_proc *proc);
83 static void _release(struct hil_proc *proc);
85 static int _ipi_handler(int vect_id, void *data);
87 /*--------------------------- Globals ---------------------------------- */
88 struct hil_platform_ops zynqmp_r5_a53_proc_ops = {
89         .enable_interrupt     = _enable_interrupt,
90         .notify               = _notify,
91         .boot_cpu             = _boot_cpu,
92         .shutdown_cpu         = _shutdown_cpu,
93         .poll                 = _poll,
94         .initialize    = _initialize,
95         .release    = _release,
96 };
98 int _ipi_handler(int vect_id, void *data)
99 {
100         (void) vect_id;
101         struct proc_vring *vring_hw = (struct proc_vring *)(data);
102         struct ipi_info *ipi =
103                 (struct ipi_info *)(vring_hw->intr_info.data);
104         struct metal_io_region *io = ipi->io;
105         unsigned int ipi_intr_status =
106             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
107         if (ipi_intr_status & ipi->ipi_chn_mask) {
108                 atomic_flag_clear(&ipi->sync);
109                 metal_io_write32(io, IPI_ISR_OFFSET,
110                                 ipi->ipi_chn_mask);
111                 return 0;
112         }
113         return -1;
116 static int _enable_interrupt(struct proc_vring *vring_hw)
118         struct ipi_info *ipi =
119             (struct ipi_info *)(vring_hw->intr_info.data);
120         struct metal_io_region *io = ipi->io;
122         if (!ipi->need_reg) {
123                 return 0;
124         }
126         /* Register ISR */
127         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
128                                 vring_hw->intr_info.dev, vring_hw);
129         /* Enable IPI interrupt */
130         metal_irq_enable(vring_hw->intr_info.vect_id);
131         metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask);
132         return 0;
135 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
138         (void)proc;
139         struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
140         if (ipi == NULL)
141                 return;
143         /* Trigger IPI */
144         metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
147 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
149         (void)proc;
150         (void)load_addr;
151         return -1;
154 static void _shutdown_cpu(struct hil_proc *proc)
156         (void)proc;
157         return;
160 static int _poll(struct hil_proc *proc, int nonblock)
162         struct proc_vring *vring;
163         struct ipi_info *ipi;
164         unsigned int flags;
166         vring = &proc->vdev.vring_info[1];
167         ipi = (struct ipi_info *)(vring->intr_info.data);
168         while(1) {
169                 flags = metal_irq_save_disable();
170                 if (!(atomic_flag_test_and_set(&ipi->sync))) {
171                         metal_irq_restore_enable(flags);
172                         virtqueue_notification(vring->vq);
173                         return 0;
174                 }
175                 if (nonblock) {
176                         metal_irq_restore_enable(flags);
177                         return -EAGAIN;
178                 }
179                 _rproc_wait();
180                 metal_irq_restore_enable(flags);
181         }
184 static int _initialize(struct hil_proc *proc)
186         int ret;
187         struct proc_intr *intr_info;
188         struct ipi_info *ipi;
189         unsigned int ipi_intr_status;
190         int i;
192         if (!proc)
193                 return -1;
195         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
196                 intr_info = &(proc->vdev.vring_info[i].intr_info);
197                 ipi = intr_info->data;
199                 if (ipi && ipi->name && ipi->bus_name) {
200                         ret = metal_device_open(ipi->bus_name, ipi->name,
201                                                      &ipi->dev);
202                         if (ret)
203                                 return -ENODEV;
204                         ipi->io = metal_device_io_region(ipi->dev, 0);
205                 } else if (ipi->paddr) {
206                         ipi->io = metal_allocate_memory(
207                                 sizeof(struct metal_io_region));
208                         if (!ipi->io)
209                                 goto error;
210                         metal_io_init(ipi->io, (void *)ipi->paddr,
211                                 &ipi->paddr, 0x1000,
212                                 (unsigned)(-1),
213                                 METAL_UNCACHED | METAL_IO_MAPPED,
214                                 NULL);
215                 }
217                 if (ipi->io) {
218                         ipi_intr_status = (unsigned int)metal_io_read32(
219                                 ipi->io, IPI_ISR_OFFSET);
220                         if (ipi_intr_status & ipi->ipi_chn_mask)
221                                 metal_io_write32(ipi->io, IPI_ISR_OFFSET,
222                                         ipi->ipi_chn_mask);
223                         metal_io_write32(ipi->io, IPI_IDR_OFFSET,
224                                 ipi->ipi_chn_mask);
225                         atomic_store(&ipi->sync, 1);
226                 }
227         }
228         return 0;
230 error:
231         _release(proc);
232         return -1;
235 static void _release(struct hil_proc *proc)
237         int i;
238         struct proc_intr *intr_info;
239         struct ipi_info *ipi;
241         if (!proc)
242                 return;
243         for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) {
244                 intr_info = &(proc->vdev.vring_info[1].intr_info);
245                 ipi = (struct ipi_info *)(intr_info->data);
246                 if (ipi) {
247                         if (ipi->io) {
248                                 metal_io_write32(ipi->io, IPI_IDR_OFFSET,
249                                         ipi->ipi_chn_mask);
250                                 if (ipi->dev) {
251                                         metal_device_close(ipi->dev);
252                                         ipi->dev = NULL;
253                                 } else {
254                                         metal_free_memory(ipi->io);
255                                 }
256                                 ipi->io = NULL;
257                         }
258                 }
260         }