zynq_remoteproc: solve the atomic warning
[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/remoteproc_plat.h"
55 #include "openamp/virtqueue.h"
57 /* IPI REGs OFFSET */
58 #define IPI_TRIG_OFFSET  0x00000000 /** IPI trigger register offset */
59 #define IPI_OBS_OFFSET   0x00000004 /** IPI observation register offset */
60 #define IPI_ISR_OFFSET   0x00000010 /* IPI interrupt status register offset */
61 #define IPI_IMR_OFFSET   0x00000014 /* IPI interrupt mask register offset */
62 #define IPI_IER_OFFSET   0x00000018 /* IPI interrupt enable register offset */
63 #define IPI_IDR_OFFSET   0x0000001C /* IPI interrupt disable register offset */
65 #define _rproc_wait() metal_cpu_yield()
67 #define DEBUG 1
69 /* -- FIX ME: ipi info is to be defined -- */
70 struct ipi_info {
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(int cpu_id, struct proc_intr *intr_info);
79 static int _boot_cpu(int cpu_id, unsigned int load_addr);
80 static void _shutdown_cpu(int cpu_id);
81 static int _poll(struct hil_proc *proc, int nonblock);
82 static struct hil_proc *_initialize(void *pdata, int cpu_id);
83 static void _release(struct hil_proc *proc);
85 /*--------------------------- Globals ---------------------------------- */
86 struct hil_platform_ops zynqmp_a53_r5_proc_ops = {
87         .enable_interrupt     = _enable_interrupt,
88         .notify               = _notify,
89         .boot_cpu             = _boot_cpu,
90         .shutdown_cpu         = _shutdown_cpu,
91         .poll                 = _poll,
92         .initialize    = _initialize,
93         .release    = _release,
94 };
96 static int _enable_interrupt(struct proc_vring *vring_hw)
97 {
98         (void)vring_hw;
99         return 0;
102 static void _notify(int cpu_id, struct proc_intr *intr_info)
105         (void)cpu_id;
106         struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
107         if (ipi == NULL)
108                 return;
110         /* Trigger IPI */
111         metal_io_write32(intr_info->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
114 static int _boot_cpu(int cpu_id, unsigned int load_addr)
116         (void)cpu_id;
117         (void)load_addr;
118         return -1;
121 static void _shutdown_cpu(int cpu_id)
123         (void)cpu_id;
124         return;
127 static int _poll(struct hil_proc *proc, int nonblock)
129         struct proc_vring *vring;
130         struct ipi_info *ipi;
131         struct metal_io_region *io;
133         vring = &proc->vdev.vring_info[0];
134         ipi = (struct ipi_info *)(vring->intr_info.data);
135         io = vring->intr_info.io;
136         while(1) {
137                 unsigned int ipi_intr_status =
138                     (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
139                 if (ipi_intr_status & ipi->ipi_chn_mask) {
140                         metal_io_write32(io, IPI_ISR_OFFSET,
141                                         ipi->ipi_chn_mask);
142                         virtqueue_notification(vring->vq);
143                         return 0;
144                 } else if (nonblock) {
145                         return -EAGAIN;
146                 }
147                 _rproc_wait();
148         }
151 static struct hil_proc * _initialize(void *pdata, int cpu_id)
153         (void) cpu_id;
155         struct hil_proc *proc;
156         int ret;
157         struct metal_io_region *io;
158         struct proc_intr *intr_info;
159         struct ipi_info *ipi;
160         unsigned int ipi_intr_status;
162         /* Allocate memory for proc instance */
163         proc = metal_allocate_memory(sizeof(struct hil_proc));
164         if (!proc) {
165                 openamp_dbg("failed to allocate hil_proc mem\n");
166                 return NULL;
167         }
168         memset(proc, 0, sizeof(struct hil_proc));
170         ret = rproc_init_plat_data(pdata, proc);
171         if (ret) {
172                 openamp_dbg("failed to allocate hil_proc mem\n");
173                 goto error;
174         }
175         intr_info = &(proc->vdev.vring_info[0].intr_info);
176         io = intr_info->io;
177         ipi = (struct ipi_info *)(intr_info->data);
178         ipi_intr_status =
179             (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
180         if (ipi_intr_status & ipi->ipi_chn_mask) {
181                 metal_io_write32(io, IPI_ISR_OFFSET, ipi->ipi_chn_mask);
182         }
183         metal_io_write32(io, IPI_IDR_OFFSET, ipi->ipi_chn_mask);
184         atomic_store(&ipi->sync, 1);
185         return proc;
186 error:
187         if (proc) {
188                 rproc_close_plat(proc);
189                 metal_free_memory(proc);
190         }
191         return NULL;
194 static void _release(struct hil_proc *proc)
196         if (proc) {
197                 rproc_close_plat(proc);
198                 metal_free_memory(proc);
199         }