remoteproc: drivers: update enable_interrupt()
[processor-sdk/open-amp.git] / lib / remoteproc / drivers / zynq_remoteproc_a9.c
1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. Neither the name of Mentor Graphics Corporation nor the names of its
14  *    contributors may be used to endorse or promote products derived from this
15  *    software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
30 /**************************************************************************
31  * FILE NAME
32  *
33  *       platform.c
34  *
35  * DESCRIPTION
36  *
37  *       This file is the Implementation of IPC hardware layer interface
38  *       for Xilinx Zynq ZC702EVK platform.
39  *
40  **************************************************************************/
42 #include <string.h>
43 #include <errno.h>
44 #include "openamp/hil.h"
45 #include "metal/alloc.h"
46 #include "metal/irq.h"
47 #include "metal/atomic.h"
49 /* ------------------------- Macros --------------------------*/
50 #define SCUGIC_PERIPH_BASE                 0xF8F00000
51 #define SCUGIC_DIST_BASE                   (SCUGIC_PERIPH_BASE + 0x00001000)
52 #define ESAL_DP_SLCR_BASE                  0xF8000000
53 #define GIC_DIST_SOFTINT                   0xF00
54 #define GIC_SFI_TRIG_CPU_MASK              0x00FF0000
55 #define GIC_SFI_TRIG_SATT_MASK             0x00008000
56 #define GIC_SFI_TRIG_INTID_MASK            0x0000000F
57 #define GIC_CPU_ID_BASE                    (1 << 4)
58 #define A9_CPU_SLCR_RESET_CTRL             0x244
59 #define A9_CPU_SLCR_CLK_STOP               (1 << 4)
60 #define A9_CPU_SLCR_RST                    (1 << 0)
62 #define unlock_slcr()                       HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x08, 0xDF0DDF0D)
63 #define lock_slcr()                         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x04, 0x767B767B)
65 /* L2Cpl310 L2 cache controller base address. */
66 #define         HIL_PL130_BASE              0xF8F02000
68 /********************/
69 /* Register offsets */
70 /********************/
72 #define         HIL_PL130_INVALLINE         0x770
73 #define         HIL_PL130_CLEANINVLINE      0x7F0
76 #define         HIL_PA_SBZ_MASK             ~(HIL_CACHE_LINE_SIZE - 1UL)
77 #define         HIL_CACHE_LINE_SIZE         32
78 #define         HIL_CACHE_INV_ALL_WAYS      0xFF
79 #define         HIL_CACHE_UNLOCK_ALL_WAYS   0xFFFF0000
80 #define         HIL_CACHE_CLEAR_INT         0x1FF
82 #define _rproc_wait() asm volatile("wfi")
84 /*--------------------------- Declare Functions ------------------------ */
85 static int _enable_interrupt(struct proc_intr *intr);
86 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
87 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
88 static void _shutdown_cpu(struct hil_proc *proc);
89 static int _poll(struct hil_proc *proc, int nonblock);
90 static int _initialize(struct hil_proc *proc);
91 static void _release(struct hil_proc *proc);
92 static int _ipi_handler(int vect_id, void *data);
94 /*--------------------------- Globals ---------------------------------- */
95 struct hil_platform_ops zynq_a9_proc_ops = {
96         .enable_interrupt = _enable_interrupt,
97         .notify           = _notify,
98         .boot_cpu         = _boot_cpu,
99         .shutdown_cpu     = _shutdown_cpu,
100         .poll             = _poll,
101         .initialize = _initialize,
102         .release = _release,
103 };
105 static metal_phys_addr_t git_dist_base_addr = SCUGIC_DIST_BASE;
106 static struct metal_io_region gic_dist_io = {
107         (void *)SCUGIC_DIST_BASE,
108         &git_dist_base_addr,
109         0x1000,
110         (sizeof(metal_phys_addr_t) << 3),
111         (metal_phys_addr_t)(-1),
112         METAL_UNCACHED,
113         {NULL},
114 };
116 //volatile unsigned int ipi_counter = 0;
117 //volatile unsigned int enableirq_counter = 0;
119 int _ipi_handler(int vect_id, void *data)
121         struct proc_intr *intr_info = data;
123         (void) vect_id;
125         atomic_flag_clear((atomic_uint *)&(intr_info->data));
127         //ipi_counter++;
128         return 0;
131 static int _enable_interrupt(struct proc_intr *intr)
133         //enableirq_counter++;
134         /* Register ISR */
135         metal_irq_register(intr->vect_id, _ipi_handler,
136                         intr->dev, intr);
138         /* Enable the interrupts */
139         metal_irq_enable(intr->vect_id);
141         return 0;
144 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
146         unsigned long mask = 0;
148         mask = ((1 << (GIC_CPU_ID_BASE + proc->cpu_id)) | (intr_info->vect_id))
149             & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
151         /* Trigger IPI */
152         metal_io_write32(&gic_dist_io, GIC_DIST_SOFTINT, mask);
155 static int _poll(struct hil_proc *proc, int nonblock)
157         struct proc_vring *vring;
158         unsigned int flags;
159         struct proc_intr *intr_info;
160         int i = 0;
161         int kicked = 0;
163         while(1) {
164                 vring = &proc->vdev.vring_info[i];
165                 intr_info = &(vring->intr_info);
166                 flags = metal_irq_save_disable();
167                 if (!(atomic_flag_test_and_set(
168                         (atomic_uint *)&(intr_info->data)))) {
169                         metal_irq_restore_enable(flags);
170                         virtqueue_notification(vring->vq);
171                         kicked = 1;
172                         if (i)
173                                 return 0;
174                         i++;
175                 } else if (!i) {
176                         metal_irq_restore_enable(flags);
177                         i++;
178                 } else {
179                         if (kicked) {
180                                 metal_irq_restore_enable(flags);
181                                 return 0;
182                         } else if (nonblock) {
183                                 metal_irq_restore_enable(flags);
184                                 return -EAGAIN;
185                         } else {
186                                 _rproc_wait();
187                                 metal_irq_restore_enable(flags);
188                                 i--;
189                                 continue;
190                         }
191                 }
192         }
195 extern char zynq_trampoline;
196 extern char zynq_trampoline_jump;
197 extern char zynq_trampoline_end;
199 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
201         /* FIXME: Will need to add the boot_cpu implementation back */
202 #if 0
203         unsigned int reg;
204         unsigned int tramp_size;
205         unsigned int tramp_addr = 0;
207         if (load_addr) {
208                 tramp_size = zynq_trampoline_end - zynq_trampoline;
209                 if ((load_addr < tramp_size) || (load_addr & 0x3)) {
210                         return -1;
211                 }
213                 tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
215                 /*
216                  * Trampoline code is copied to address 0 from where remote core is expected to
217                  * fetch first instruction after reset.If master is using the address 0 then
218                  * this mem copy will screwed the system. It is user responsibility to not
219                  * copy trampoline code in such cases.
220                  *
221                  */
222                 memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
223                 /* Write image address at the word reserved at the trampoline end */
224                 HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
225         }
227         unlock_slcr();
229         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
230         reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
231         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
232         /* De-assert reset signal and start clock to start the core */
233         reg &= ~(A9_CPU_SLCR_RST << cpu_id);
234         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
236         lock_slcr();
238 #else
239         (void)proc;
240         (void)load_addr;
241 #endif
242         return 0;
245 static void _shutdown_cpu(struct hil_proc *proc)
247         /* FIXME: Will need to add the shutdown CPU implementation back */
248 #if 0
249         unsigned int reg;
251         unlock_slcr();
253         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
254         /* Assert reset signal and stop clock to halt the core */
255         reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
256         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
258         lock_slcr();
259 #else
260         (void)proc;
261 #endif
264 static int _initialize(struct hil_proc *proc)
266         int i;
267         struct proc_intr *intr_info;
269         for (i = 0; i < 2; i++) {
270                 intr_info = &(proc->vdev.vring_info[i].intr_info);
271                 atomic_store((atomic_uint *)&(intr_info->data), 1);
272         }
274         return 0;
277 static void _release(struct hil_proc *proc)
279         (void)proc;
280         return;