]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/drivers/zynqmp_remoteproc_a53.c
5f67bf5bfb1f09a3459016f8a340706c215e8d21
[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 "openamp/hil.h"
51 #include "openamp/remoteproc_plat.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         uint32_t ipi_chn_mask;
67         int need_reg;
68         atomic_int sync;
69 };
71 /*--------------------------- Declare Functions ------------------------ */
72 static int _enable_interrupt(struct proc_vring *vring_hw);
73 static void _notify(int cpu_id, struct proc_intr *intr_info);
74 static int _boot_cpu(int cpu_id, unsigned int load_addr);
75 static void _shutdown_cpu(int cpu_id);
76 static int _poll(struct hil_proc *proc, int nonblock);
77 static struct hil_proc *_initialize(void *pdata, int cpu_id);
78 static void _release(struct hil_proc *proc);
80 static int _ipi_handler(int vect_id, void *data);
82 /*--------------------------- Globals ---------------------------------- */
83 struct hil_platform_ops zynqmp_r5_a53_proc_ops = {
84         .enable_interrupt     = _enable_interrupt,
85         .notify               = _notify,
86         .boot_cpu             = _boot_cpu,
87         .shutdown_cpu         = _shutdown_cpu,
88         .poll                 = _poll,
89         .initialize    = _initialize,
90         .release    = _release,
91 };
93 int _ipi_handler(int vect_id, void *data)
94 {
95         (void) vect_id;
96         struct proc_vring *vring_hw = (struct proc_vring *)(data);
97         struct ipi_info *ipi =
98                 (struct ipi_info *)(vring_hw->intr_info.data);
99         struct metal_io_region *io = vring_hw->intr_info.io;
100         unsigned int ipi_intr_status =
101             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
102         if (ipi_intr_status & ipi->ipi_chn_mask) {
103                 atomic_flag_clear(&ipi->sync);
104                 metal_io_write32(io, IPI_ISR_OFFSET,
105                                 ipi->ipi_chn_mask);
106                 return 0;
107         }
108         return -1;
111 static int _enable_interrupt(struct proc_vring *vring_hw)
113         struct ipi_info *ipi =
114             (struct ipi_info *)(vring_hw->intr_info.data);
115         struct metal_io_region *io = vring_hw->intr_info.io;
117         if (!ipi->need_reg) {
118                 return 0;
119         }
121         /* Register ISR */
122         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
123                                 vring_hw->intr_info.dev, vring_hw);
124         /* Enable IPI interrupt */
125 #if 0
126         env_enable_interrupt(vring_hw->intr_info.vect_id,
127                              vring_hw->intr_info.priority,
128                              vring_hw->intr_info.trigger_type);
129 #endif
130         metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask);
131         return 0;
134 static void _notify(int cpu_id, struct proc_intr *intr_info)
137         (void)cpu_id;
138         struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
139         if (ipi == NULL)
140                 return;
142         /* Trigger IPI */
143         metal_io_write32(intr_info->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
146 static int _boot_cpu(int cpu_id, unsigned int load_addr)
148         (void)cpu_id;
149         (void)load_addr;
150         return -1;
153 static void _shutdown_cpu(int cpu_id)
155         (void)cpu_id;
156         return;
159 static int _poll(struct hil_proc *proc, int nonblock)
161         struct proc_vring *vring;
162         struct ipi_info *ipi;
163         unsigned int flags;
165         vring = &proc->vdev.vring_info[1];
166         ipi = (struct ipi_info *)(vring->intr_info.data);
167         while(1) {
168                 flags = metal_irq_save_disable();
169                 if (!(atomic_flag_test_and_set(&ipi->sync))) {
170                         metal_irq_restore_enable(flags);
171                         virtqueue_notification(vring->vq);
172                         return 0;
173                 }
174                 if (nonblock) {
175                         metal_irq_restore_enable(flags);
176                         return -EAGAIN;
177                 }
178                 _rproc_wait();
179                 metal_irq_restore_enable(flags);
180         }
183 static struct hil_proc * _initialize(void *pdata, int cpu_id)
185         (void) cpu_id;
187         struct hil_proc *proc;
188         int ret;
189         struct metal_io_region *io;
190         struct proc_intr *intr_info;
191         struct ipi_info *ipi;
192         unsigned int ipi_intr_status;
194         /* Allocate memory for proc instance */
195         proc = env_allocate_memory(sizeof(struct hil_proc));
196         if (!proc) {
197                 return NULL;
198         }
199         memset(proc, 0, sizeof(struct hil_proc));
201         ret = rproc_init_plat_data(pdata, proc);
202         if (ret)
203                 goto error;
204         intr_info = &(proc->vdev.vring_info[1].intr_info);
205         io = intr_info->io;
206         ipi = (struct ipi_info *)(intr_info->data);
207         ipi_intr_status =
208             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
209         if (ipi_intr_status & ipi->ipi_chn_mask) {
210                 metal_io_write32(io, IPI_ISR_OFFSET, ipi->ipi_chn_mask);
211         }
212         metal_io_write32(io, IPI_IDR_OFFSET, ipi->ipi_chn_mask);
213         atomic_store(&ipi->sync, 1);
214         /* Enable mapping for the shared memory region */
215         if (proc->sh_buff.size)
216                 metal_io_mem_map((metal_phys_addr_t)proc->sh_buff.start_addr,
217                         proc->sh_buff.io,
218                         proc->sh_buff.size);
219         return proc;
220 error:
221         if (proc) {
222                 rproc_close_plat(proc);
223                 env_free_memory(proc);
224         }
225         return NULL;
228 static void _release(struct hil_proc *proc)
230         if (proc) {
231                 struct proc_intr *intr_info =
232                         &(proc->vdev.vring_info[1].intr_info);
233                 struct metal_io_region *io = intr_info->io;
234                 struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
235                 metal_io_write32(io, IPI_IDR_OFFSET, ipi->ipi_chn_mask);
237                 rproc_close_plat(proc);
238                 env_free_memory(proc);
239         }