]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/drivers/zynq_remoteproc_a9.c
b94eb28785622f0b0c5dcc370d5180f246cefd48
[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_vring *vring_hw);
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         (void) vect_id;
122         struct proc_vring *vring_hw = (struct proc_vring *)(data);
123         struct proc_intr *intr_info;
125         intr_info = &(vring_hw->intr_info);
126         atomic_flag_clear((atomic_uint *)&(intr_info->data));
128         //ipi_counter++;
129         return 0;
132 static int _enable_interrupt(struct proc_vring *vring_hw)
134         //enableirq_counter++;
135         /* Register ISR */
136         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
137                                 vring_hw->intr_info.dev, vring_hw);
139         /* Enable the interrupts */
140         metal_irq_enable(vring_hw->intr_info.vect_id);
142         return 0;
145 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
147         unsigned long mask = 0;
149         mask = ((1 << (GIC_CPU_ID_BASE + proc->cpu_id)) | (intr_info->vect_id))
150             & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
152         /* Trigger IPI */
153         metal_io_write32(&gic_dist_io, GIC_DIST_SOFTINT, mask);
156 static int _poll(struct hil_proc *proc, int nonblock)
158         struct proc_vring *vring;
159         unsigned int flags;
160         struct proc_intr *intr_info;
161         int i = 0;
162         int kicked = 0;
164         while(1) {
165                 vring = &proc->vdev.vring_info[i];
166                 intr_info = &(vring->intr_info);
167                 flags = metal_irq_save_disable();
168                 if (!(atomic_flag_test_and_set(
169                         (atomic_uint *)&(intr_info->data)))) {
170                         metal_irq_restore_enable(flags);
171                         virtqueue_notification(vring->vq);
172                         kicked = 1;
173                         if (i)
174                                 return 0;
175                         i++;
176                 } else if (!i) {
177                         metal_irq_restore_enable(flags);
178                         i++;
179                 } else {
180                         if (kicked) {
181                                 metal_irq_restore_enable(flags);
182                                 return 0;
183                         } else if (nonblock) {
184                                 metal_irq_restore_enable(flags);
185                                 return -EAGAIN;
186                         } else {
187                                 _rproc_wait();
188                                 metal_irq_restore_enable(flags);
189                                 i--;
190                                 continue;
191                         }
192                 }
193         }
196 extern char zynq_trampoline;
197 extern char zynq_trampoline_jump;
198 extern char zynq_trampoline_end;
200 static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
202         /* FIXME: Will need to add the boot_cpu implementation back */
203 #if 0
204         unsigned int reg;
205         unsigned int tramp_size;
206         unsigned int tramp_addr = 0;
208         if (load_addr) {
209                 tramp_size = zynq_trampoline_end - zynq_trampoline;
210                 if ((load_addr < tramp_size) || (load_addr & 0x3)) {
211                         return -1;
212                 }
214                 tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
216                 /*
217                  * Trampoline code is copied to address 0 from where remote core is expected to
218                  * fetch first instruction after reset.If master is using the address 0 then
219                  * this mem copy will screwed the system. It is user responsibility to not
220                  * copy trampoline code in such cases.
221                  *
222                  */
223                 memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
224                 /* Write image address at the word reserved at the trampoline end */
225                 HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
226         }
228         unlock_slcr();
230         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
231         reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
232         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
233         /* De-assert reset signal and start clock to start the core */
234         reg &= ~(A9_CPU_SLCR_RST << cpu_id);
235         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
237         lock_slcr();
239 #else
240         (void)proc;
241         (void)load_addr;
242 #endif
243         return 0;
246 static void _shutdown_cpu(struct hil_proc *proc)
248         /* FIXME: Will need to add the shutdown CPU implementation back */
249 #if 0
250         unsigned int reg;
252         unlock_slcr();
254         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
255         /* Assert reset signal and stop clock to halt the core */
256         reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
257         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
259         lock_slcr();
260 #else
261         (void)proc;
262 #endif
265 static int _initialize(struct hil_proc *proc)
267         int i;
268         struct proc_intr *intr_info;
270         for (i = 0; i < 2; i++) {
271                 intr_info = &(proc->vdev.vring_info[i].intr_info);
272                 atomic_store((atomic_uint *)&(intr_info->data), 1);
273         }
275         return 0;
278 static void _release(struct hil_proc *proc)
280         return;