49535031f3f193b4e4c64fcfe7d83591a008a301
[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 "openamp/remoteproc_plat.h"
46 #include "metal/alloc.h"
47 #include "metal/irq.h"
48 #include "metal/atomic.h"
50 /* ------------------------- Macros --------------------------*/
51 #define ESAL_DP_SLCR_BASE                  0xF8000000
52 #define PERIPH_BASE                        0xF8F00000
53 #define GIC_DIST_BASE                      (PERIPH_BASE + 0x00001000)
54 #define GIC_DIST_SOFTINT                   0xF00
55 #define GIC_SFI_TRIG_CPU_MASK              0x00FF0000
56 #define GIC_SFI_TRIG_SATT_MASK             0x00008000
57 #define GIC_SFI_TRIG_INTID_MASK            0x0000000F
58 #define GIC_CPU_ID_BASE                    (1 << 4)
59 #define A9_CPU_SLCR_RESET_CTRL             0x244
60 #define A9_CPU_SLCR_CLK_STOP               (1 << 4)
61 #define A9_CPU_SLCR_RST                    (1 << 0)
63 #define unlock_slcr()                       HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x08, 0xDF0DDF0D)
64 #define lock_slcr()                         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x04, 0x767B767B)
67 /* L2Cpl310 L2 cache controller base address. */
68 #define         HIL_PL130_BASE              0xF8F02000
70 /********************/
71 /* Register offsets */
72 /********************/
74 #define         HIL_PL130_INVALLINE         0x770
75 #define         HIL_PL130_CLEANINVLINE      0x7F0
78 #define         HIL_PA_SBZ_MASK             ~(HIL_CACHE_LINE_SIZE - 1UL)
79 #define         HIL_CACHE_LINE_SIZE         32
80 #define         HIL_CACHE_INV_ALL_WAYS      0xFF
81 #define         HIL_CACHE_UNLOCK_ALL_WAYS   0xFFFF0000
82 #define         HIL_CACHE_CLEAR_INT         0x1FF
84 #define _rproc_wait() asm volatile("wfi")
86 /*--------------------------- Declare Functions ------------------------ */
87 static int _enable_interrupt(struct proc_vring *vring_hw);
88 static void _notify(int cpu_id, struct proc_intr *intr_info);
89 static int _boot_cpu(int cpu_id, unsigned int load_addr);
90 static void _shutdown_cpu(int cpu_id);
91 static int _poll(struct hil_proc *proc, int nonblock);
92 static struct hil_proc * _initialize(void *pdata, int cpu_id);
93 static void _release(struct hil_proc *proc);
94 static int _ipi_handler(int vect_id, void *data);
96 /*--------------------------- Globals ---------------------------------- */
97 struct hil_platform_ops zynq_a9_proc_ops = {
98         .enable_interrupt = _enable_interrupt,
99         .notify           = _notify,
100         .boot_cpu         = _boot_cpu,
101         .shutdown_cpu     = _shutdown_cpu,
102         .poll             = _poll,
103         .initialize = _initialize,
104         .release = _release,
105 };
107 int _ipi_handler(int vect_id, void *data)
109         (void) vect_id;
110         struct proc_vring *vring_hw = (struct proc_vring *)(data);
111         struct proc_intr *intr_info;
113         intr_info = &(vring_hw->intr_info);
114         atomic_flag_clear(&(intr_info->data));
115         return 0;
118 static int _enable_interrupt(struct proc_vring *vring_hw)
121         /* Register ISR */
122         metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
123                                 vring_hw->intr_info.dev, vring_hw);
125         /* Enable the interrupts */
126         metal_irq_enable(vring_hw->intr_info.vect_id);
127         return 0;
130 static void _notify(int cpu_id, struct proc_intr *intr_info)
133         unsigned long mask = 0;
135         mask = ((1 << (GIC_CPU_ID_BASE + cpu_id)) | (intr_info->vect_id))
136             & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
138         /* Trigger IPI */
139         metal_io_write32(intr_info->io, GIC_DIST_SOFTINT, mask);
142 static int _poll(struct hil_proc *proc, int nonblock)
144         struct proc_vring *vring;
145         unsigned int flags;
146         struct proc_intr *intr_info;
147         int i = 0;
148         int kicked = 0;
150         while(1) {
151                 vring = &proc->vdev.vring_info[i];
152                 intr_info = &(vring->intr_info);
153                 flags = metal_irq_save_disable();
154                 if (!(atomic_flag_test_and_set(&intr_info->data))) {
155                         metal_irq_restore_enable(flags);
156                         virtqueue_notification(vring->vq);
157                         kicked = 1;
158                         if (i)
159                                 return 0;
160                         i++;
161                 } else if (!i) {
162                         metal_irq_restore_enable(flags);
163                         i++;
164                 } else {
165                         if (kicked) {
166                                 metal_irq_restore_enable(flags);
167                                 return 0;
168                         } else if (nonblock) {
169                                 metal_irq_restore_enable(flags);
170                                 return -EAGAIN;
171                         } else {
172                                 _rproc_wait();
173                                 metal_irq_restore_enable(flags);
174                                 i--;
175                                 continue;
176                         }
177                 }
178         }
181 extern char zynq_trampoline;
182 extern char zynq_trampoline_jump;
183 extern char zynq_trampoline_end;
185 static int _boot_cpu(int cpu_id, unsigned int load_addr)
187         /* FIXME: Will need to add the boot_cpu implementation back */
188 #if 0
189         unsigned int reg;
190         unsigned int tramp_size;
191         unsigned int tramp_addr = 0;
193         if (load_addr) {
194                 tramp_size = zynq_trampoline_end - zynq_trampoline;
195                 if ((load_addr < tramp_size) || (load_addr & 0x3)) {
196                         return -1;
197                 }
199                 tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
201                 /*
202                  * Trampoline code is copied to address 0 from where remote core is expected to
203                  * fetch first instruction after reset.If master is using the address 0 then
204                  * this mem copy will screwed the system. It is user responsibility to not
205                  * copy trampoline code in such cases.
206                  *
207                  */
208                 memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
209                 /* Write image address at the word reserved at the trampoline end */
210                 HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
211         }
213         unlock_slcr();
215         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
216         reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
217         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
218         /* De-assert reset signal and start clock to start the core */
219         reg &= ~(A9_CPU_SLCR_RST << cpu_id);
220         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
222         lock_slcr();
224 #else
225         (void)cpu_id;
226         (void)load_addr;
227 #endif
228         return 0;
231 static void _shutdown_cpu(int cpu_id)
233         /* FIXME: Will need to add the shutdown CPU implementation back */
234 #if 0
235         unsigned int reg;
237         unlock_slcr();
239         reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
240         /* Assert reset signal and stop clock to halt the core */
241         reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
242         HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
244         lock_slcr();
245 #else
246         (void)cpu_id;
247 #endif
250 static struct hil_proc * _initialize(void *pdata, int cpu_id)
252         (void) cpu_id;
253         int ret;
254         int i;
255         struct proc_intr *intr_info;
257         struct hil_proc *proc;
258         /* Allocate memory for proc instance */
259         proc = metal_allocate_memory(sizeof(struct hil_proc));
260         if (!proc) {
261                 return NULL;
262         }
263         memset(proc, 0, sizeof(struct hil_proc));
265         ret = rproc_init_plat_data(pdata, proc);
266         if (ret)
267                 goto error;
269         for (i = 0; i < 2; i++) {
270                 intr_info = &(proc->vdev.vring_info[i].intr_info);
271                 atomic_store(&(intr_info->data), 1);
272         }
274         return proc;
275 error:
276         if (proc) {
277                 rproc_close_plat(proc);
278                 metal_free_memory(proc);
279         }
280         return NULL;
283 static void _release(struct hil_proc *proc)
285         if (proc) {
286                 rproc_close_plat(proc);
287                 metal_free_memory(proc);
288         }