Zynq remoteproc: update to use libmetal APIs
authorWendy Liang <jliang@xilinx.com>
Tue, 16 Aug 2016 04:06:22 +0000 (21:06 -0700)
committerWendy Liang <jliang@xilinx.com>
Thu, 13 Oct 2016 05:01:48 +0000 (22:01 -0700)
Update the Zynq remoteproc driver to user libmetal I/O region
for IPI, and implement the hil_proc poll() for application to
poll if virings are notified.

Signed-off-by: Wendy Liang <jliang@xilinx.com>
lib/remoteproc/drivers/zynq_remoteproc_a9.c

index 7141f595a62b9a392ec5b90c26623055ad98df30..def8d3a3728830ae1e498387516d23116c47d78a 100644 (file)
 
 #include <string.h>
 #include "openamp/hil.h"
-#include "openamp/machine/machine_common.h"
+#include "openamp/remoteproc_plat.h"
 #include "metal/alloc.h"
+#include "metal/irq.h"
+#include "metal/atomic.h"
 
 /* ------------------------- Macros --------------------------*/
 #define ESAL_DP_SLCR_BASE                  0xF8000000
 #define         HIL_CACHE_UNLOCK_ALL_WAYS   0xFFFF0000
 #define         HIL_CACHE_CLEAR_INT         0x1FF
 
+#define _rproc_wait() asm volatile("wfi")
+
 /*--------------------------- Declare Functions ------------------------ */
 static int _enable_interrupt(struct proc_vring *vring_hw);
 static void _notify(int cpu_id, struct proc_intr *intr_info);
 static int _boot_cpu(int cpu_id, unsigned int load_addr);
 static void _shutdown_cpu(int cpu_id);
+static int _poll(struct hil_proc *proc, int nonblock);
 static struct hil_proc * _initialize(void *pdata, int cpu_id);
 static void _release(struct hil_proc *proc);
+static int _ipi_handler(int vect_id, void *data);
 
 /*--------------------------- Globals ---------------------------------- */
 struct hil_platform_ops zynq_a9_proc_ops = {
@@ -92,20 +98,31 @@ struct hil_platform_ops zynq_a9_proc_ops = {
        .notify           = _notify,
        .boot_cpu         = _boot_cpu,
        .shutdown_cpu     = _shutdown_cpu,
+       .poll             = _poll,
        .initialize = _initialize,
        .release = _release,
 };
 
+int _ipi_handler(int vect_id, void *data)
+{
+       (void) vect_id;
+       struct proc_vring *vring_hw = (struct proc_vring *)(data);
+       struct proc_intr *intr_info;
+
+       intr_info = &(vring_hw->intr_info);
+       atomic_flag_clear(&(intr_info->data));
+       return 0;
+}
+
 static int _enable_interrupt(struct proc_vring *vring_hw)
 {
 
        /* Register ISR */
-       env_register_isr(vring_hw->intr_info.vect_id, vring_hw, platform_isr);
+       metal_irq_register(vring_hw->intr_info.vect_id, _ipi_handler,
+                               vring_hw->intr_info.dev, vring_hw);
 
        /* Enable the interrupts */
-       env_enable_interrupt(vring_hw->intr_info.vect_id,
-                            vring_hw->intr_info.priority,
-                            vring_hw->intr_info.trigger_type);
+       metal_irq_enable(vring_hw->intr_info.vect_id);
        return 0;
 }
 
@@ -117,7 +134,47 @@ static void _notify(int cpu_id, struct proc_intr *intr_info)
        mask = ((1 << (GIC_CPU_ID_BASE + cpu_id)) | (intr_info->vect_id))
            & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
 
-       HIL_MEM_WRITE32((GIC_DIST_BASE + GIC_DIST_SOFTINT), mask);
+       /* Trigger IPI */
+       metal_io_write32(intr_info->io, GIC_DIST_SOFTINT, mask);
+}
+
+static int _poll(struct hil_proc *proc, int nonblock)
+{
+       struct proc_vring *vring;
+       unsigned int flags;
+       struct proc_intr *intr_info;
+       int i = 0;
+       int kicked = 0;
+
+       while(1) {
+               vring = &proc->vdev.vring_info[i];
+               intr_info = &(vring->intr_info);
+               flags = metal_irq_save_disable();
+               if (!(atomic_flag_test_and_set(&intr_info->data))) {
+                       metal_irq_restore_enable(flags);
+                       virtqueue_notification(vring->vq);
+                       kicked = 1;
+                       if (i)
+                               return 0;
+                       i++;
+               } else if (!i) {
+                       metal_irq_restore_enable(flags);
+                       i++;
+               } else {
+                       if (kicked) {
+                               metal_irq_restore_enable(flags);
+                               return 0;
+                       } else if (nonblock) {
+                               metal_irq_restore_enable(flags);
+                               return -EAGAIN;
+                       } else {
+                               _rproc_wait();
+                               metal_irq_restore_enable(flags);
+                               i--;
+                               continue;
+                       }
+               }
+       }
 }
 
 extern char zynq_trampoline;
@@ -126,6 +183,8 @@ extern char zynq_trampoline_end;
 
 static int _boot_cpu(int cpu_id, unsigned int load_addr)
 {
+       /* FIXME: Will need to add the boot_cpu implementation back */
+#if 0
        unsigned int reg;
        unsigned int tramp_size;
        unsigned int tramp_addr = 0;
@@ -161,11 +220,17 @@ static int _boot_cpu(int cpu_id, unsigned int load_addr)
 
        lock_slcr();
 
+#else
+       (void)cpu_id;
+       (void)load_addr;
+#endif
        return 0;
 }
 
 static void _shutdown_cpu(int cpu_id)
 {
+       /* FIXME: Will need to add the shutdown CPU implementation back */
+#if 0
        unsigned int reg;
 
        unlock_slcr();
@@ -176,11 +241,17 @@ static void _shutdown_cpu(int cpu_id)
        HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
 
        lock_slcr();
+#else
+       (void)cpu_id;
+#endif
 }
 
 static struct hil_proc * _initialize(void *pdata, int cpu_id)
 {
        (void) cpu_id;
+       int ret;
+       int i;
+       struct proc_intr *intr_info;
 
        struct hil_proc *proc;
        /* Allocate memory for proc instance */
@@ -188,18 +259,31 @@ static struct hil_proc * _initialize(void *pdata, int cpu_id)
        if (!proc) {
                return NULL;
        }
+       memset(proc, 0, sizeof(struct hil_proc));
+
+       ret = rproc_init_plat_data(pdata, proc);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 2; i++) {
+               intr_info = &(proc->vdev.vring_info[i].intr_info);
+               atomic_store(&(intr_info->data), 1);
+       }
 
-       memcpy(proc, pdata, sizeof(struct hil_proc));
-       /* Enable mapping for the shared memory region */
-       if (proc->sh_buff.size)
-               env_map_memory((unsigned int)proc->sh_buff.start_addr,
-                           (unsigned int)proc->sh_buff.start_addr,
-                           proc->sh_buff.size, (SHARED_MEM | UNCACHED));
        return proc;
+error:
+       if (proc) {
+               rproc_close_plat(proc);
+               metal_free_memory(proc);
+       }
+       return NULL;
 }
 
 static void _release(struct hil_proc *proc)
 {
-       metal_free_memory(proc);
+       if (proc) {
+               rproc_close_plat(proc);
+               metal_free_memory(proc);
+       }
 }