]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/drivers/zynq_remoteproc_a9.c
Zynq remoteproc: update to use libmetal APIs
[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 "openamp/hil.h"
44 #include "openamp/remoteproc_plat.h"
45 #include "metal/alloc.h"
46 #include "metal/irq.h"
47 #include "metal/atomic.h"
49 /* ------------------------- Macros --------------------------*/
50 #define ESAL_DP_SLCR_BASE                  0xF8000000
51 #define PERIPH_BASE                        0xF8F00000
52 #define GIC_DIST_BASE                      (PERIPH_BASE + 0x00001000)
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)
66 /* L2Cpl310 L2 cache controller base address. */
67 #define         HIL_PL130_BASE              0xF8F02000
69 /********************/
70 /* Register offsets */
71 /********************/
73 #define         HIL_PL130_INVALLINE         0x770
74 #define         HIL_PL130_CLEANINVLINE      0x7F0
77 #define         HIL_PA_SBZ_MASK             ~(HIL_CACHE_LINE_SIZE - 1UL)
78 #define         HIL_CACHE_LINE_SIZE         32
79 #define         HIL_CACHE_INV_ALL_WAYS      0xFF
80 #define         HIL_CACHE_UNLOCK_ALL_WAYS   0xFFFF0000
81 #define         HIL_CACHE_CLEAR_INT         0x1FF
83 #define _rproc_wait() asm volatile("wfi")
85 /*--------------------------- Declare Functions ------------------------ */
86 static int _enable_interrupt(struct proc_vring *vring_hw);
87 static void _notify(int cpu_id, struct proc_intr *intr_info);
88 static int _boot_cpu(int cpu_id, unsigned int load_addr);
89 static void _shutdown_cpu(int cpu_id);
90 static int _poll(struct hil_proc *proc, int nonblock);
91 static struct hil_proc * _initialize(void *pdata, int cpu_id);
92 static void _release(struct hil_proc *proc);
93 static int _ipi_handler(int vect_id, void *data);
95 /*--------------------------- Globals ---------------------------------- */
96 struct hil_platform_ops zynq_a9_proc_ops = {
97         .enable_interrupt = _enable_interrupt,
98         .notify           = _notify,
99         .boot_cpu         = _boot_cpu,
100         .shutdown_cpu     = _shutdown_cpu,
101         .poll             = _poll,
102         .initialize = _initialize,
103         .release = _release,
104 };
106 int _ipi_handler(int vect_id, void *data)
108         (void) vect_id;
109         struct proc_vring *vring_hw = (struct proc_vring *)(data);
110         struct proc_intr *intr_info;
112         intr_info = &(vring_hw->intr_info);
113         atomic_flag_clear(&(intr_info->data));
114         return 0;
117 static int _enable_interrupt(struct proc_vring *vring_hw)
120         /* Register ISR */
121         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
122                                 vring_hw->intr_info.dev, vring_hw);
124         /* Enable the interrupts */
125         metal_irq_enable(vring_hw->intr_info.vect_id);
126         return 0;
129 static void _notify(int cpu_id, struct proc_intr *intr_info)
132         unsigned long mask = 0;
134         mask = ((1 << (GIC_CPU_ID_BASE + cpu_id)) | (intr_info->vect_id))
135             & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
137         /* Trigger IPI */
138         metal_io_write32(intr_info->io, GIC_DIST_SOFTINT, mask);
141 static int _poll(struct hil_proc *proc, int nonblock)
143         struct proc_vring *vring;
144         unsigned int flags;
145         struct proc_intr *intr_info;
146         int i = 0;
147         int kicked = 0;
149         while(1) {
150                 vring = &proc->vdev.vring_info[i];
151                 intr_info = &(vring->intr_info);
152                 flags = metal_irq_save_disable();
153                 if (!(atomic_flag_test_and_set(&intr_info->data))) {
154                         metal_irq_restore_enable(flags);
155                         virtqueue_notification(vring->vq);
156                         kicked = 1;
157                         if (i)
158                                 return 0;
159                         i++;
160                 } else if (!i) {
161                         metal_irq_restore_enable(flags);
162                         i++;
163                 } else {
164                         if (kicked) {
165                                 metal_irq_restore_enable(flags);
166                                 return 0;
167                         } else if (nonblock) {
168                                 metal_irq_restore_enable(flags);
169                                 return -EAGAIN;
170                         } else {
171                                 _rproc_wait();
172                                 metal_irq_restore_enable(flags);
173                                 i--;
174                                 continue;
175                         }
176                 }
177         }
180 extern char zynq_trampoline;
181 extern char zynq_trampoline_jump;
182 extern char zynq_trampoline_end;
184 static int _boot_cpu(int cpu_id, unsigned int load_addr)
186         /* FIXME: Will need to add the boot_cpu implementation back */
187 #if 0
188         unsigned int reg;
189         unsigned int tramp_size;
190         unsigned int tramp_addr = 0;
192         if (load_addr) {
193                 tramp_size = zynq_trampoline_end - zynq_trampoline;
194                 if ((load_addr < tramp_size) || (load_addr & 0x3)) {
195                         return -1;
196                 }
198                 tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
200                 /*
201                  * Trampoline code is copied to address 0 from where remote core is expected to
202                  * fetch first instruction after reset.If master is using the address 0 then
203                  * this mem copy will screwed the system. It is user responsibility to not
204                  * copy trampoline code in such cases.
205                  *
206                  */
207                 memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
208                 /* Write image address at the word reserved at the trampoline end */
209                 HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
210         }
212         unlock_slcr();
214         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
215         reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
216         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
217         /* De-assert reset signal and start clock to start the core */
218         reg &= ~(A9_CPU_SLCR_RST << cpu_id);
219         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
221         lock_slcr();
223 #else
224         (void)cpu_id;
225         (void)load_addr;
226 #endif
227         return 0;
230 static void _shutdown_cpu(int cpu_id)
232         /* FIXME: Will need to add the shutdown CPU implementation back */
233 #if 0
234         unsigned int reg;
236         unlock_slcr();
238         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
239         /* Assert reset signal and stop clock to halt the core */
240         reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
241         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
243         lock_slcr();
244 #else
245         (void)cpu_id;
246 #endif
249 static struct hil_proc * _initialize(void *pdata, int cpu_id)
251         (void) cpu_id;
252         int ret;
253         int i;
254         struct proc_intr *intr_info;
256         struct hil_proc *proc;
257         /* Allocate memory for proc instance */
258         proc = metal_allocate_memory(sizeof(struct hil_proc));
259         if (!proc) {
260                 return NULL;
261         }
262         memset(proc, 0, sizeof(struct hil_proc));
264         ret = rproc_init_plat_data(pdata, proc);
265         if (ret)
266                 goto error;
268         for (i = 0; i < 2; i++) {
269                 intr_info = &(proc->vdev.vring_info[i].intr_info);
270                 atomic_store(&(intr_info->data), 1);
271         }
273         return proc;
274 error:
275         if (proc) {
276                 rproc_close_plat(proc);
277                 metal_free_memory(proc);
278         }
279         return NULL;
282 static void _release(struct hil_proc *proc)
284         if (proc) {
285                 rproc_close_plat(proc);
286                 metal_free_memory(proc);
287         }