remoteproc: remove remoteproc drivers

Move remoteproc drivers implementation to applications'
platform implementation.

Signed-off-by: Wendy Liang <jliang@xilinx.com>
This commit is contained in:
Wendy Liang
2018-07-26 09:32:19 -07:00
committed by wjliang
parent 5b6ff0a498
commit de0afcd58c
7 changed files with 0 additions and 1207 deletions

View File

@@ -2,4 +2,3 @@ collect (PROJECT_LIB_SOURCES elf_loader.c)
collect (PROJECT_LIB_SOURCES remoteproc.c)
collect (PROJECT_LIB_SOURCES remoteproc_virtio.c)
collect (PROJECT_LIB_SOURCES rsc_table_parser.c)
#add_subdirectory (drivers)

View File

@@ -1,16 +0,0 @@
if ("${MACHINE}" STREQUAL "zynqmp_r5")
collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_a53.c)
endif ("${MACHINE}" STREQUAL "zynqmp_r5")
if ("${MACHINE}" STREQUAL "zynq7")
collect (PROJECT_LIB_SOURCES zynq_remoteproc_a9.c)
collect (PROJECT_LIB_SOURCES zynq_a9_trampoline.S)
endif ("${MACHINE}" STREQUAL "zynq7")
if ("${MACHINE}" STREQUAL "zynqmp")
collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_r5.c)
endif ("${MACHINE}" STREQUAL "zynqmp")
if ("${PROJECT_SYSTEM}" STREQUAL "linux")
collect (PROJECT_LIB_SOURCES linux_remoteproc.c)
endif ("${PROJECT_SYSTEM}" STREQUAL "linux")

View File

@@ -1,352 +0,0 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* zynqmp_remoteproc_r5.c
*
* DESCRIPTION
*
* This file is the Implementation of IPC hardware layer interface
* for Xilinx Zynq UltraScale+ MPSoC system.
*
**************************************************************************/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <poll.h>
#include <metal/io.h>
#include <metal/device.h>
#include <metal/utilities.h>
#include <metal/atomic.h>
#include <metal/irq.h>
#include <metal/cpu.h>
#include <metal/alloc.h>
#include <metal/assert.h>
#include <metal/shmem.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <openamp/hil.h>
#include <openamp/virtqueue.h>
#define MAX_VRING_MEM_SIZE 0x20000
#define _rproc_wait() metal_cpu_yield()
#define UNIX_PREFIX "unix:"
#define UNIXS_PREFIX "unixs:"
struct vring_ipi_info {
/* Socket file path */
char *path;
int fd;
struct metal_io_region *vring_io;
atomic_int sync;
};
/*--------------------------- Declare Functions ------------------------ */
static int _ipi_handler(int vect_id, void *data);
static int _enable_interrupt(struct proc_intr *intr);
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
static void _shutdown_cpu(struct hil_proc *proc);
static int _poll(struct hil_proc *proc, int nonblock);
static int _initialize(struct hil_proc *proc);
static void _release(struct hil_proc *proc);
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev);
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io);
/*--------------------------- Globals ---------------------------------- */
struct hil_platform_ops linux_proc_ops = {
.enable_interrupt = _enable_interrupt,
.notify = _notify,
.boot_cpu = _boot_cpu,
.shutdown_cpu = _shutdown_cpu,
.poll = _poll,
.alloc_shm = _alloc_shm,
.release_shm = _release_shm,
.initialize = _initialize,
.release = _release,
};
static int sk_unix_client(const char *descr)
{
struct sockaddr_un addr;
int fd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX),
sizeof addr.sun_path);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
printf("connected to %s\n", descr + strlen(UNIX_PREFIX));
return fd;
}
close(fd);
return -1;
}
static int sk_unix_server(const char *descr)
{
struct sockaddr_un addr;
int fd, nfd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, descr + strlen(UNIXS_PREFIX),
sizeof addr.sun_path);
unlink(addr.sun_path);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
goto fail;
}
listen(fd, 5);
printf("Waiting for connection on %s\n", addr.sun_path);
nfd = accept(fd, NULL, NULL);
close(fd);
return nfd;
fail:
close(fd);
return -1;
}
static int event_open(const char *descr)
{
int fd = -1;
int i;
if (descr == NULL) {
return fd;
}
if (memcmp(UNIX_PREFIX, descr, strlen(UNIX_PREFIX)) == 0) {
/* UNIX. Retry to connect a few times to give the peer a
* chance to setup. */
for (i = 0; i < 100 && fd == -1; i++) {
fd = sk_unix_client(descr);
if (fd == -1)
usleep(i * 10 * 1000);
}
}
if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)) == 0) {
/* UNIX. */
fd = sk_unix_server(descr);
}
printf("Open IPI: %s\n", descr);
return fd;
}
static int _ipi_handler(int vect_id, void *data)
{
char dummy_buf[32];
struct proc_intr *intr = data;
struct vring_ipi_info *ipi = intr->data;
(void) vect_id;
read(vect_id, dummy_buf, sizeof(dummy_buf));
atomic_flag_clear(&ipi->sync);
return 0;
}
static int _enable_interrupt(struct proc_intr *intr)
{
struct vring_ipi_info *ipi = intr->data;
ipi->fd = event_open(ipi->path);
if (ipi->fd < 0) {
fprintf(stderr, "ERROR: Failed to open sock %s for IPI.\n",
ipi->path);
return -1;
}
intr->vect_id = ipi->fd;
/* Register ISR */
metal_irq_register(ipi->fd, _ipi_handler,
NULL, intr);
return 0;
}
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
{
(void)proc;
struct vring_ipi_info *ipi = (struct vring_ipi_info *)(intr_info->data);
if (ipi == NULL)
return;
char dummy = 1;
send(ipi->fd, &dummy, 1, MSG_NOSIGNAL);
}
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
{
(void)proc;
(void)load_addr;
return -1;
}
static void _shutdown_cpu(struct hil_proc *proc)
{
(void)proc;
return;
}
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev)
{
(void)proc;
(void)pa;
(void)size;
*dev = NULL;
return NULL;
}
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io)
{
(void)proc;
(void)io;
hil_close_generic_mem_dev(dev);
}
static int _poll(struct hil_proc *proc, int nonblock)
{
(void) nonblock;
struct proc_vring *vring;
struct vring_ipi_info *ipi;
unsigned int flags;
int num_vrings = proc->vdev.num_vrings;
int ret = 0;
int notified;
int i;
metal_assert(proc);
notified = 0;
while (1) {
for (i = 0; i < num_vrings; i++) {
vring = &proc->vdev.vring_info[i];
ipi = (struct vring_ipi_info *)(vring->intr_info.data);
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&ipi->sync))) {
metal_irq_restore_enable(flags);
virtqueue_notification(vring->vq);
notified = 1;
} else {
metal_irq_restore_enable(flags);
}
}
if (notified)
return 0;
if (nonblock)
return -EAGAIN;
_rproc_wait();
}
return ret;
}
/**
* @brief _adjust_vring_io - Adjust the vring I/O region to map to the
* specified start device address.
* @param[in] io - vring I/O region
* @param[in] start_phy - start device address of the vring, this is
* not the actual physical address.
* @return adjusted I/O region
*/
static struct metal_io_region *_create_vring_io(struct metal_io_region *in_io,
int start_phy)
{
struct metal_io_region *io = 0;
metal_phys_addr_t *phys;
io = metal_allocate_memory(sizeof(struct metal_io_region));
if (!io) {
fprintf(stderr, "ERROR: Failed to allocation I/O for vring.\n");
return NULL;
}
phys = metal_allocate_memory(sizeof(metal_phys_addr_t));
if (!phys) {
fprintf(stderr, "ERROR: Failed to allocation phys for vring.\n");
metal_free_memory(io);
return NULL;
}
*phys = (metal_phys_addr_t)start_phy;
metal_io_init(io, in_io->virt, phys, in_io->size,
sizeof(metal_phys_addr_t)*8 - 1, 0, NULL);
return io;
}
static int _initialize(struct hil_proc *proc)
{
struct proc_vring *vring;
struct vring_ipi_info *ipi;
struct metal_io_region *io;
int i;
if (proc) {
for (i = 0; i < 2; i++) {
vring = &proc->vdev.vring_info[i];
ipi = (struct vring_ipi_info *)vring->intr_info.data;
if (ipi && !ipi->vring_io && vring->io) {
io = _create_vring_io(vring->io, 0);
if (!io)
return -1;
ipi->vring_io = vring->io;
vring->io = io;
atomic_store(&ipi->sync, 1);
}
}
}
return 0;
}
static void _release(struct hil_proc *proc)
{
struct proc_vring *vring;
struct vring_ipi_info *ipi;
int i;
if (proc) {
for (i = 0; i < 2; i++) {
vring = &proc->vdev.vring_info[i];
ipi = (struct vring_ipi_info *)vring->intr_info.data;
if (ipi) {
if (ipi->fd >= 0) {
metal_irq_unregister(ipi->fd, 0, NULL,
vring);
close(ipi->fd);
}
if (ipi->vring_io) {
metal_free_memory(vring->io->physmap);
metal_free_memory(vring->io);
vring->io = NULL;
if (ipi->vring_io->ops.close)
ipi->vring_io->ops.close(ipi->vring_io);
ipi->vring_io = NULL;
}
}
}
}
}

View File

@@ -1,16 +0,0 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
.global zynq_trampoline
zynq_trampoline:
ldr r0, [pc]
bx r0
.global zynq_trampoline_jump
zynq_trampoline_jump:
.word
.global zynq_trampoline_end
zynq_trampoline_end:

View File

@@ -1,312 +0,0 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform.c
*
* DESCRIPTION
*
* This file is the Implementation of IPC hardware layer interface
* for Xilinx Zynq ZC702EVK platform.
*
**************************************************************************/
#include <string.h>
#include <errno.h>
#include <openamp/hil.h>
#include <metal/alloc.h>
#include <metal/irq.h>
#include <metal/atomic.h>
/* ------------------------- Macros --------------------------*/
#define SCUGIC_PERIPH_BASE 0xF8F00000
#define SCUGIC_DIST_BASE (SCUGIC_PERIPH_BASE + 0x00001000)
#define ESAL_DP_SLCR_BASE 0xF8000000
#define GIC_DIST_SOFTINT 0xF00
#define GIC_SFI_TRIG_CPU_MASK 0x00FF0000
#define GIC_SFI_TRIG_SATT_MASK 0x00008000
#define GIC_SFI_TRIG_INTID_MASK 0x0000000F
#define GIC_CPU_ID_BASE (1 << 4)
#define A9_CPU_SLCR_RESET_CTRL 0x244
#define A9_CPU_SLCR_CLK_STOP (1 << 4)
#define A9_CPU_SLCR_RST (1 << 0)
#define unlock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x08, 0xDF0DDF0D)
#define lock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x04, 0x767B767B)
/* L2Cpl310 L2 cache controller base address. */
#define HIL_PL130_BASE 0xF8F02000
/********************/
/* Register offsets */
/********************/
#define HIL_PL130_INVALLINE 0x770
#define HIL_PL130_CLEANINVLINE 0x7F0
#define HIL_PA_SBZ_MASK ~(HIL_CACHE_LINE_SIZE - 1UL)
#define HIL_CACHE_LINE_SIZE 32
#define HIL_CACHE_INV_ALL_WAYS 0xFF
#define HIL_CACHE_UNLOCK_ALL_WAYS 0xFFFF0000
#define HIL_CACHE_CLEAR_INT 0x1FF
/* Memory attributes */
#define NORM_NONCACHE 0x11DE2 /* Normal Non-cacheable */
#define STRONG_ORDERED 0xC02 /* Strongly ordered */
#define DEVICE_MEMORY 0xC06 /* Device memory */
#define RESERVED 0x0 /* reserved memory */
#define HIL_DEV_NAME_PREFIX "hil-dev."
#define _rproc_wait() asm volatile("wfi")
/*--------------------------- Declare Functions ------------------------ */
static int _enable_interrupt(struct proc_intr *intr);
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
static void _shutdown_cpu(struct hil_proc *proc);
static int _poll(struct hil_proc *proc, int nonblock);
static int _initialize(struct hil_proc *proc);
static void _release(struct hil_proc *proc);
static int _ipi_handler(int vect_id, void *data);
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev);
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io);
/*--------------------------- Globals ---------------------------------- */
struct hil_platform_ops zynq_a9_proc_ops = {
.enable_interrupt = _enable_interrupt,
.notify = _notify,
.boot_cpu = _boot_cpu,
.shutdown_cpu = _shutdown_cpu,
.poll = _poll,
.alloc_shm = _alloc_shm,
.release_shm = _release_shm,
.initialize = _initialize,
.release = _release,
};
struct hil_mem_device {
struct metal_device device;
char name[64];
metal_phys_addr_t pa;
};
static metal_phys_addr_t git_dist_base_addr = SCUGIC_DIST_BASE;
static struct metal_io_region gic_dist_io = {
(void *)SCUGIC_DIST_BASE,
&git_dist_base_addr,
0x1000,
(sizeof(metal_phys_addr_t) << 3),
(metal_phys_addr_t)(-1),
0,
{NULL},
};
//volatile unsigned int ipi_counter = 0;
//volatile unsigned int enableirq_counter = 0;
int _ipi_handler(int vect_id, void *data)
{
struct proc_intr *intr_info = data;
(void) vect_id;
atomic_flag_clear((atomic_uint *)&(intr_info->data));
//ipi_counter++;
return 0;
}
static int _enable_interrupt(struct proc_intr *intr)
{
//enableirq_counter++;
/* Register ISR */
metal_irq_register(intr->vect_id, _ipi_handler,
intr->dev, intr);
/* Enable the interrupts */
metal_irq_enable(intr->vect_id);
/* FIXME: This is a workaround for Zynq. As Linux is possible
* to have already generate the soft IRQ
*/
atomic_flag_clear((atomic_uint *)&(intr->data));
return 0;
}
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
{
unsigned long mask = 0;
mask = ((1 << (GIC_CPU_ID_BASE + proc->cpu_id)) | (intr_info->vect_id))
& (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK);
/* Trigger IPI */
metal_io_write32(&gic_dist_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(
(atomic_uint *)&(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;
extern char zynq_trampoline_jump;
extern char zynq_trampoline_end;
static int _boot_cpu(struct hil_proc *proc, 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;
if (load_addr) {
tramp_size = zynq_trampoline_end - zynq_trampoline;
if ((load_addr < tramp_size) || (load_addr & 0x3)) {
return -1;
}
tramp_size = &zynq_trampoline_jump - &zynq_trampoline;
/*
* Trampoline code is copied to address 0 from where remote core is expected to
* fetch first instruction after reset.If master is using the address 0 then
* this mem copy will screwed the system. It is user responsibility to not
* copy trampoline code in such cases.
*
*/
memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size);
/* Write image address at the word reserved at the trampoline end */
HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr);
}
unlock_slcr();
reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id);
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
/* De-assert reset signal and start clock to start the core */
reg &= ~(A9_CPU_SLCR_RST << cpu_id);
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
lock_slcr();
#else
(void)proc;
(void)load_addr;
#endif
return 0;
}
static void _shutdown_cpu(struct hil_proc *proc)
{
/* FIXME: Will need to add the shutdown CPU implementation back */
#if 0
unsigned int reg;
unlock_slcr();
reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL);
/* Assert reset signal and stop clock to halt the core */
reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id;
HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg);
lock_slcr();
#else
(void)proc;
#endif
}
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev)
{
(void)proc;
*dev = hil_create_generic_mem_dev(pa, size,
NORM_NONCACHE | STRONG_ORDERED);
if ((*dev))
return &((*dev)->regions[0]);
return NULL;
}
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io)
{
(void)proc;
(void)io;
hil_close_generic_mem_dev(dev);
}
static int _initialize(struct hil_proc *proc)
{
int i;
struct proc_intr *intr_info;
for (i = 0; i < 2; i++) {
intr_info = &(proc->vdev.vring_info[i].intr_info);
atomic_store((atomic_uint *)&(intr_info->data), 1);
}
return 0;
}
static void _release(struct hil_proc *proc)
{
(void)proc;
return;
}

View File

@@ -1,273 +0,0 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform.c
*
* DESCRIPTION
*
* This file is the Implementation of IPC hardware layer interface
* for Xilinx Zynq ZC702EVK platform.
*
**************************************************************************/
#include <errno.h>
#include <string.h>
#include <metal/io.h>
#include <metal/device.h>
#include <metal/utilities.h>
#include <metal/atomic.h>
#include <metal/irq.h>
#include <metal/alloc.h>
#include <openamp/hil.h>
#include <openamp/virtqueue.h>
/* IPI REGs OFFSET */
#define IPI_TRIG_OFFSET 0x00000000 /* IPI trigger register offset */
#define IPI_OBS_OFFSET 0x00000004 /* IPI observation register offset */
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
/* memory attributes */
#define DEVICE_SHARED 0x00000001U /*device, shareable*/
#define DEVICE_NONSHARED 0x00000010U /*device, non shareable*/
#define NORM_NSHARED_NCACHE 0x00000008U /* Non cacheable non shareable */
#define NORM_SHARED_NCACHE 0x0000000CU /* Non cacheable shareable */
#define PRIV_RW_USER_RW (0x00000003U<<8U) /*Full Access*/
#define _rproc_wait() asm volatile("wfi")
/* -- FIX ME: ipi info is to be defined -- */
struct ipi_info {
const char *name;
const char *bus_name;
struct metal_device *dev;
struct metal_io_region *io;
metal_phys_addr_t paddr;
uint32_t ipi_chn_mask;
int registered;
atomic_int sync;
};
/*--------------------------- Declare Functions ------------------------ */
static int _enable_interrupt(struct proc_intr *intr);
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
static void _shutdown_cpu(struct hil_proc *proc);
static int _poll(struct hil_proc *proc, int nonblock);
static int _initialize(struct hil_proc *proc);
static void _release(struct hil_proc *proc);
static int _ipi_handler(int vect_id, void *data);
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev);
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io);
/*--------------------------- Globals ---------------------------------- */
struct hil_platform_ops zynqmp_r5_a53_proc_ops = {
.enable_interrupt = _enable_interrupt,
.notify = _notify,
.boot_cpu = _boot_cpu,
.shutdown_cpu = _shutdown_cpu,
.poll = _poll,
.alloc_shm = _alloc_shm,
.release_shm = _release_shm,
.initialize = _initialize,
.release = _release,
};
int _ipi_handler(int vect_id, void *data)
{
struct proc_intr *intr = data;
struct ipi_info *ipi = intr->data;
struct metal_io_region *io = ipi->io;
unsigned int ipi_intr_status =
(unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
(void) vect_id;
if (ipi_intr_status & ipi->ipi_chn_mask) {
atomic_flag_clear(&ipi->sync);
metal_io_write32(io, IPI_ISR_OFFSET,
ipi->ipi_chn_mask);
return 0;
}
return -1;
}
static int _enable_interrupt(struct proc_intr *intr)
{
struct ipi_info *ipi =
(struct ipi_info *)(intr->data);
struct metal_io_region *io = ipi->io;
if (ipi->registered) {
return 0;
}
/* Register ISR */
metal_irq_register(intr->vect_id, _ipi_handler,
intr->dev, intr);
/* Enable IPI interrupt */
metal_irq_enable(intr->vect_id);
metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask);
ipi->registered = 1;
return 0;
}
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
{
(void)proc;
struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
if (ipi == NULL)
return;
/* Trigger IPI */
metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
}
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
{
(void)proc;
(void)load_addr;
return -1;
}
static void _shutdown_cpu(struct hil_proc *proc)
{
(void)proc;
return;
}
static int _poll(struct hil_proc *proc, int nonblock)
{
struct proc_vdev *vdev;
struct ipi_info *ipi;
unsigned int flags;
vdev = &proc->vdev;
ipi = (struct ipi_info *)(vdev->intr_info.data);
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&ipi->sync))) {
metal_irq_restore_enable(flags);
hil_notified(proc, (uint32_t)(-1));
return 0;
}
if (nonblock) {
metal_irq_restore_enable(flags);
return -EAGAIN;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
}
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev)
{
(void)proc;
*dev = hil_create_generic_mem_dev(pa, size,
NORM_SHARED_NCACHE | PRIV_RW_USER_RW);
if ((*dev))
return &((*dev)->regions[0]);
return NULL;
}
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io)
{
(void)proc;
(void)io;
hil_close_generic_mem_dev(dev);
}
static int _initialize(struct hil_proc *proc)
{
int ret;
struct proc_intr *intr_info;
struct ipi_info *ipi;
if (!proc)
return -1;
intr_info = &(proc->vdev.intr_info);
ipi = intr_info->data;
if (ipi && ipi->name && ipi->bus_name) {
ret = metal_device_open(ipi->bus_name, ipi->name,
&ipi->dev);
if (ret)
return -ENODEV;
ipi->io = metal_device_io_region(ipi->dev, 0);
} else if (ipi->paddr) {
ipi->io = metal_allocate_memory(
sizeof(struct metal_io_region));
if (!ipi->io)
goto error;
metal_io_init(ipi->io, (void *)ipi->paddr,
&ipi->paddr, 0x1000,
sizeof(metal_phys_addr_t) << 3,
0,
NULL);
}
if (ipi->io) {
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
ipi->ipi_chn_mask);
atomic_store(&ipi->sync, 1);
}
ipi->registered = 0;
return 0;
error:
_release(proc);
return -1;
}
static void _release(struct hil_proc *proc)
{
struct proc_intr *intr_info;
struct ipi_info *ipi;
if (!proc)
return;
intr_info = &(proc->vdev.intr_info);
ipi = (struct ipi_info *)(intr_info->data);
if (ipi) {
if (ipi->io) {
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
ipi->ipi_chn_mask);
if (ipi->dev) {
metal_device_close(ipi->dev);
ipi->dev = NULL;
} else {
metal_free_memory(ipi->io);
}
ipi->io = NULL;
}
}
}

View File

@@ -1,237 +0,0 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2015 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* zynqmp_remoteproc_r5.c
*
* DESCRIPTION
*
* This file is the Implementation of IPC hardware layer interface
* for Xilinx Zynq UltraScale+ MPSoC system.
*
**************************************************************************/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <metal/io.h>
#include <metal/device.h>
#include <metal/utilities.h>
#include <metal/atomic.h>
#include <metal/irq.h>
#include <metal/cpu.h>
#include <metal/alloc.h>
#include <openamp/hil.h>
#include <openamp/virtqueue.h>
/* IPI REGs OFFSET */
#define IPI_TRIG_OFFSET 0x00000000 /** IPI trigger register offset */
#define IPI_OBS_OFFSET 0x00000004 /** IPI observation register offset */
#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */
#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */
#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */
#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */
#define _rproc_wait() metal_cpu_yield()
/* -- FIX ME: ipi info is to be defined -- */
struct ipi_info {
const char *name;
const char *bus_name;
struct metal_device *dev;
struct metal_io_region *io;
metal_phys_addr_t paddr;
uint32_t ipi_chn_mask;
atomic_int sync;
};
/*--------------------------- Declare Functions ------------------------ */
static int _enable_interrupt(struct proc_intr *intr);
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info);
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr);
static void _shutdown_cpu(struct hil_proc *proc);
static int _poll(struct hil_proc *proc, int nonblock);
static int _initialize(struct hil_proc *proc);
static void _release(struct hil_proc *proc);
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev);
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io);
/*--------------------------- Globals ---------------------------------- */
struct hil_platform_ops zynqmp_a53_r5_proc_ops = {
.enable_interrupt = _enable_interrupt,
.notify = _notify,
.boot_cpu = _boot_cpu,
.shutdown_cpu = _shutdown_cpu,
.poll = _poll,
.alloc_shm = _alloc_shm,
.release_shm = _release_shm,
.initialize = _initialize,
.release = _release,
};
static int _enable_interrupt(struct proc_intr *intr)
{
(void)intr;
return 0;
}
static void _notify(struct hil_proc *proc, struct proc_intr *intr_info)
{
(void)proc;
struct ipi_info *ipi = (struct ipi_info *)(intr_info->data);
if (ipi == NULL)
return;
/* Trigger IPI */
metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask);
}
static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr)
{
(void)proc;
(void)load_addr;
return -1;
}
static void _shutdown_cpu(struct hil_proc *proc)
{
(void)proc;
return;
}
static int _poll(struct hil_proc *proc, int nonblock)
{
struct proc_vdev *vdev;
struct ipi_info *ipi;
struct metal_io_region *io;
vdev = &proc->vdev;
ipi = (struct ipi_info *)(vdev->intr_info.data);
io = ipi->io;
while(1) {
unsigned int ipi_intr_status =
(unsigned int)metal_io_read32(io, IPI_ISR_OFFSET);
if (ipi_intr_status & ipi->ipi_chn_mask) {
metal_io_write32(io, IPI_ISR_OFFSET,
ipi->ipi_chn_mask);
hil_notified(proc, (uint32_t)(-1));
return 0;
} else if (nonblock) {
return -EAGAIN;
}
_rproc_wait();
}
}
static struct metal_io_region* _alloc_shm(struct hil_proc *proc,
metal_phys_addr_t pa,
size_t size,
struct metal_device **dev)
{
(void)proc;
(void)pa;
(void)size;
*dev = NULL;
return NULL;
}
static void _release_shm(struct hil_proc *proc,
struct metal_device *dev,
struct metal_io_region *io)
{
(void)proc;
(void)io;
hil_close_generic_mem_dev(dev);
}
static int _initialize(struct hil_proc *proc)
{
int ret;
struct proc_intr *intr_info;
struct ipi_info *ipi;
unsigned int ipi_intr_status;
if (!proc)
return -1;
intr_info = &(proc->vdev.intr_info);
ipi = intr_info->data;
if (ipi && ipi->name && ipi->bus_name) {
ret = metal_device_open(ipi->bus_name, ipi->name,
&ipi->dev);
if (ret)
return -ENODEV;
ipi->io = metal_device_io_region(ipi->dev, 0);
intr_info->vect_id = (uintptr_t)ipi->dev->irq_info;
} else if (ipi->paddr) {
ipi->io = metal_allocate_memory(
sizeof(struct metal_io_region));
if (!ipi->io)
goto error;
metal_io_init(ipi->io, (void *)ipi->paddr,
&ipi->paddr, 0x1000,
(unsigned)(-1),
0,
NULL);
}
if (ipi->io) {
ipi_intr_status = (unsigned int)metal_io_read32(
ipi->io, IPI_ISR_OFFSET);
if (ipi_intr_status & ipi->ipi_chn_mask)
metal_io_write32(ipi->io, IPI_ISR_OFFSET,
ipi->ipi_chn_mask);
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
ipi->ipi_chn_mask);
atomic_store(&ipi->sync, 1);
}
return 0;
error:
_release(proc);
return -1;
}
static void _release(struct hil_proc *proc)
{
struct proc_intr *intr_info;
struct ipi_info *ipi;
if (!proc)
return;
intr_info = &(proc->vdev.intr_info);
ipi = (struct ipi_info *)(intr_info->data);
if (ipi) {
if (ipi->io) {
metal_io_write32(ipi->io, IPI_IDR_OFFSET,
ipi->ipi_chn_mask);
if (ipi->dev) {
metal_device_close(ipi->dev);
ipi->dev = NULL;
} else {
metal_free_memory(ipi->io);
}
ipi->io = NULL;
}
}
}