06a07791ce3b31e5dd34d9364f80c8b539763f74
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)
120 {
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;
130 }
132 static int _enable_interrupt(struct proc_vring *vring_hw)
133 {
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;
143 }
145 static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
146 {
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);
154 }
156 static int _poll(struct hil_proc *proc, int nonblock)
157 {
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 }
194 }
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)
201 {
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;
244 }
246 static void _shutdown_cpu(struct hil_proc *proc)
247 {
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
263 }
265 static int _initialize(struct hil_proc *proc)
266 {
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;
276 }
278 static void _release(struct hil_proc *proc)
279 {
280 (void)proc;
281 return;
282 }