061baab398cba8e8a9f03cf5be04c2c59908565f
[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/remoteproc_plat.h"
53 #include "openamp/virtqueue.h"
55 /* IPI REGs OFFSET */
56 #define IPI_TRIG_OFFSET          0x00000000    /* IPI trigger register offset */
57 #define IPI_OBS_OFFSET           0x00000004    /* IPI observation register offset */
58 #define IPI_ISR_OFFSET           0x00000010    /* IPI interrupt status register offset */
59 #define IPI_IMR_OFFSET           0x00000014    /* IPI interrupt mask register offset */
60 #define IPI_IER_OFFSET           0x00000018    /* IPI interrupt enable register offset */
61 #define IPI_IDR_OFFSET           0x0000001C    /* IPI interrupt disable register offset */
63 #define _rproc_wait() asm volatile("wfi")
65 /* -- FIX ME: ipi info is to be defined -- */
66 struct ipi_info {
67         uint32_t ipi_chn_mask;
68         int need_reg;
69         atomic_int sync;
70 };
72 /*--------------------------- Declare Functions ------------------------ */
73 static int _enable_interrupt(struct proc_vring *vring_hw);
74 static void _notify(int cpu_id, struct proc_intr *intr_info);
75 static int _boot_cpu(int cpu_id, unsigned int load_addr);
76 static void _shutdown_cpu(int cpu_id);
77 static int _poll(struct hil_proc *proc, int nonblock);
78 static struct hil_proc *_initialize(void *pdata, int cpu_id);
79 static void _release(struct hil_proc *proc);
81 static int _ipi_handler(int vect_id, void *data);
83 /*--------------------------- Globals ---------------------------------- */
84 struct hil_platform_ops zynqmp_r5_a53_proc_ops = {
85         .enable_interrupt     = _enable_interrupt,
86         .notify               = _notify,
87         .boot_cpu             = _boot_cpu,
88         .shutdown_cpu         = _shutdown_cpu,
89         .poll                 = _poll,
90         .initialize    = _initialize,
91         .release    = _release,
92 };
94 int _ipi_handler(int vect_id, void *data)
95 {
96         (void) vect_id;
97         struct proc_vring *vring_hw = (struct proc_vring *)(data);
98         struct ipi_info *ipi =
99                 (struct ipi_info *)(vring_hw->intr_info.data);
100         struct metal_io_region *io = vring_hw->intr_info.io;
101         unsigned int ipi_intr_status =
102             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
103         if (ipi_intr_status & ipi->ipi_chn_mask) {
104                 atomic_flag_clear(&ipi->sync);
105                 metal_io_write32(io, IPI_ISR_OFFSET,
106                                 ipi->ipi_chn_mask);
107                 return 0;
108         }
109         return -1;
112 static int _enable_interrupt(struct proc_vring *vring_hw)
114         struct ipi_info *ipi =
115             (struct ipi_info *)(vring_hw->intr_info.data);
116         struct metal_io_region *io = vring_hw->intr_info.io;
118         if (!ipi->need_reg) {
119                 return 0;
120         }
122         /* Register ISR */
123         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
124                                 vring_hw->intr_info.dev, vring_hw);
125         /* Enable IPI interrupt */
126         metal_irq_enable(vring_hw->intr_info.vect_id);
127         metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask);
128         return 0;
131 static void _notify(int cpu_id, struct proc_intr *intr_info)
134         (void)cpu_id;
135         struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
136         if (ipi == NULL)
137                 return;
139         /* Trigger IPI */
140         metal_io_write32(intr_info->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
143 static int _boot_cpu(int cpu_id, unsigned int load_addr)
145         (void)cpu_id;
146         (void)load_addr;
147         return -1;
150 static void _shutdown_cpu(int cpu_id)
152         (void)cpu_id;
153         return;
156 static int _poll(struct hil_proc *proc, int nonblock)
158         struct proc_vring *vring;
159         struct ipi_info *ipi;
160         unsigned int flags;
162         vring = &proc->vdev.vring_info[1];
163         ipi = (struct ipi_info *)(vring->intr_info.data);
164         while(1) {
165                 flags = metal_irq_save_disable();
166                 if (!(atomic_flag_test_and_set(&ipi->sync))) {
167                         metal_irq_restore_enable(flags);
168                         virtqueue_notification(vring->vq);
169                         return 0;
170                 }
171                 if (nonblock) {
172                         metal_irq_restore_enable(flags);
173                         return -EAGAIN;
174                 }
175                 _rproc_wait();
176                 metal_irq_restore_enable(flags);
177         }
180 static struct hil_proc * _initialize(void *pdata, int cpu_id)
182         (void) cpu_id;
184         struct hil_proc *proc;
185         int ret;
186         struct metal_io_region *io;
187         struct proc_intr *intr_info;
188         struct ipi_info *ipi;
189         unsigned int ipi_intr_status;
191         /* Allocate memory for proc instance */
192         proc = metal_allocate_memory(sizeof(struct hil_proc));
193         if (!proc) {
194                 return NULL;
195         }
196         memset(proc, 0, sizeof(struct hil_proc));
198         ret = rproc_init_plat_data(pdata, proc);
199         if (ret)
200                 goto error;
201         intr_info = &(proc->vdev.vring_info[1].intr_info);
202         io = intr_info->io;
203         ipi = (struct ipi_info *)(intr_info->data);
204         ipi_intr_status =
205             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
206         if (ipi_intr_status & ipi->ipi_chn_mask) {
207                 metal_io_write32(io, IPI_ISR_OFFSET, ipi->ipi_chn_mask);
208         }
209         metal_io_write32(io, IPI_IDR_OFFSET, ipi->ipi_chn_mask);
210         atomic_store(&ipi->sync, 1);
211         return proc;
212 error:
213         if (proc) {
214                 rproc_close_plat(proc);
215                 metal_free_memory(proc);
216         }
217         return NULL;
220 static void _release(struct hil_proc *proc)
222         if (proc) {
223                 struct proc_intr *intr_info =
224                         &(proc->vdev.vring_info[1].intr_info);
225                 struct metal_io_region *io = intr_info->io;
226                 struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
227                 metal_io_write32(io, IPI_IDR_OFFSET, ipi->ipi_chn_mask);
229                 rproc_close_plat(proc);
230                 metal_free_memory(proc);
231         }