建立工程,成功创建两个虚拟串口

This commit is contained in:
ranchuan
2023-06-21 18:00:56 +08:00
commit 3604192d8f
872 changed files with 428764 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")
add_subdirectory (${PROJECT_MACHINE})
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE}/CMakeLists.txt")

View File

@@ -0,0 +1,6 @@
collect (APP_COMMON_SOURCES helper.c)
collect (APP_COMMON_SOURCES rsc_table.c)
collect (APP_COMMON_SOURCES platform_info.c)
collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <stdio.h>
#include <metal/sys.h>
#include <metal/shmem.h>
#include <metal/device.h>
#include <metal/io.h>
int init_system()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
metal_param.log_level = LOG_DEBUG;
metal_init(&metal_param);
return 0;
}
void cleanup_system()
{
metal_finish();
}

View File

@@ -0,0 +1,551 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 Xilinx, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**************************************************************************
* FILE NAME
*
* platform_info.c
*
* DESCRIPTION
*
* This file implements APIs to get platform specific
* information for OpenAMP.
*
**************************************************************************/
#include <metal/alloc.h>
#include <metal/atomic.h>
#include <metal/io.h>
#include <metal/irq.h>
#include <metal/shmem.h>
#include <metal/utilities.h>
#include <openamp/remoteproc.h>
#include <openamp/rpmsg_virtio.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include "rsc_table.h"
#define IPI_CHAN_NUMS 2
#define IPI_CHAN_SEND 0
#define IPI_CHAN_RECV 1
#define UNIX_PREFIX "unix:"
#define UNIXS_PREFIX "unixs:"
#define RSC_MEM_PA 0x0UL
#define SHARED_BUF_PA 0x10000UL
#define SHARED_BUF_SIZE 0x40000UL
#define _rproc_wait() metal_cpu_yield()
struct vring_ipi_info {
/* Socket file path */
const char *path;
int fd;
atomic_int sync;
};
struct remoteproc_priv {
const char *shm_file;
int shm_size;
struct metal_io_region *shm_old_io;
struct metal_io_region shm_new_io;
struct remoteproc_mem shm;
struct vring_ipi_info ipi;
};
static struct remoteproc_priv rproc_priv_table [] = {
{
.shm_file = "openamp.shm",
.shm_size = 0x80000,
.ipi = {
.path = "unixs:/tmp/openamp.event.0",
},
},
{
.shm_file = "openamp.shm",
.shm_size = 0x80000,
.ipi = {
.path = "unix:/tmp/openamp.event.0",
},
},
};
static struct remoteproc rproc_inst;
/* External functions */
extern int init_system(void);
extern void cleanup_system(void);
static int linux_proc_block_read(struct metal_io_region *io,
unsigned long offset,
void *restrict dst,
memory_order order,
int len)
{
void *src = metal_io_virt(io, offset);
(void)order;
(void)memcpy(dst, src, len);
return len;
}
static int linux_proc_block_write(struct metal_io_region *io,
unsigned long offset,
const void *restrict src,
memory_order order,
int len)
{
void *dst = metal_io_virt(io, offset);
(void)order;
(void)memcpy(dst, src, len);
return len;
}
static void linux_proc_block_set(struct metal_io_region *io,
unsigned long offset,
unsigned char value,
memory_order order,
int len)
{
void *dst = metal_io_virt(io, offset);
(void)order;
(void)memset(dst, value, len);
return;
}
static struct metal_io_ops linux_proc_io_ops = {
.write = NULL,
.read = NULL,
.block_read = linux_proc_block_read,
.block_write = linux_proc_block_write,
.block_set = linux_proc_block_set,
.close = NULL,
};
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 inline int is_sk_unix_server(const char *descr)
{
if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)))
return 0;
else
return 1;
}
static int event_open(const char *descr)
{
int fd = -1;
int i;
if (descr == NULL) {
return fd;
}
if (!is_sk_unix_server(descr)) {
/* UNIX client. 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);
}
} else {
/* UNIX server. */
fd = sk_unix_server(descr);
}
printf("Open IPI: %s\n", descr);
return fd;
}
static int linux_proc_irq_handler(int vect_id, void *data)
{
char dummy_buf[32];
struct vring_ipi_info *ipi = data;
read(vect_id, dummy_buf, sizeof(dummy_buf));
atomic_flag_clear(&ipi->sync);
return 0;
}
static struct remoteproc *
linux_proc_init(struct remoteproc *rproc,
struct remoteproc_ops *ops, void *arg)
{
struct remoteproc_priv *prproc = arg;
struct metal_io_region *io;
struct remoteproc_mem *shm;
struct vring_ipi_info *ipi;
int ret;
if (!rproc || !prproc)
return NULL;
rproc->priv = prproc;
/* Create shared memory io */
ret = metal_shmem_open(prproc->shm_file, prproc->shm_size, &io);
if (ret) {
printf("Failed to init rproc, failed to open shm %s.\n",
prproc->shm_file);
return NULL;
}
prproc->shm_old_io = io;
shm = &prproc->shm;
shm->pa = 0;
shm->da = 0;
shm->size = prproc->shm_size;
metal_io_init(&prproc->shm_new_io, io->virt, &shm->pa,
shm->size, -1, 0, &linux_proc_io_ops);
shm->io = &prproc->shm_new_io;
/* Open IPI */
ipi = &prproc->ipi;
if (!ipi->path) {
fprintf(stderr,
"ERROR: No IPI sock path specified.\n");
goto err;
}
ipi->fd = event_open(ipi->path);
if (ipi->fd < 0) {
fprintf(stderr,
"ERROR: Failed to open sock %s for IPI.\n",
ipi->path);
goto err;
}
metal_irq_register(ipi->fd, linux_proc_irq_handler, NULL, ipi);
rproc->ops = ops;
return rproc;
err:
return NULL;
}
static void linux_proc_remove(struct remoteproc *rproc)
{
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
struct metal_io_region *io;
if (!rproc)
return;
prproc = rproc->priv;
/* Close IPI */
ipi = &prproc->ipi;
if (ipi->fd >= 0) {
metal_irq_unregister(ipi->fd, 0, NULL, ipi);
close(ipi->fd);
}
/* Close shared memory */
io = prproc->shm_old_io;
if (io && io->ops.close) {
io->ops.close(io);
prproc->shm_old_io = NULL;
}
}
static void *
linux_proc_mmap(struct remoteproc *rproc, metal_phys_addr_t *pa,
metal_phys_addr_t *da, size_t size,
unsigned int attribute, struct metal_io_region **io)
{
struct remoteproc_mem *mem;
struct remoteproc_priv *prproc;
metal_phys_addr_t lpa, lda;
void *va;
(void)attribute;
(void)size;
lpa = *pa;
lda = *da;
if (lpa == METAL_BAD_PHYS && lda == METAL_BAD_PHYS)
return NULL;
if (lpa == METAL_BAD_PHYS)
lpa = lda;
if (lda == METAL_BAD_PHYS)
lda = lpa;
if (!rproc)
return NULL;
prproc = rproc->priv;
mem = &prproc->shm;
va = metal_io_phys_to_virt(mem->io, lpa);
if (va) {
if (io)
*io = mem->io;
metal_list_add_tail(&rproc->mems, &mem->node);
}
return va;
}
static int linux_proc_notify(struct remoteproc *rproc, uint32_t id)
{
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
char dummy = 1;
(void)id;
if (!rproc)
return -1;
prproc = rproc->priv;
ipi = &prproc->ipi;
send(ipi->fd, &dummy, 1, MSG_NOSIGNAL);
return 0;
}
/* processor operations from r5 to a53. It defines
* notification operation and remote processor managementi operations. */
static struct remoteproc_ops linux_proc_ops = {
.init = linux_proc_init,
.remove = linux_proc_remove,
.mmap = linux_proc_mmap,
.notify = linux_proc_notify,
.start = NULL,
.stop = NULL,
.shutdown = NULL,
};
/* RPMsg virtio shared buffer pool */
static struct rpmsg_virtio_shm_pool shpool;
static int platform_slave_setup_resource_table(const char *shm_file,
int shm_size,
void *rsc_table, int rsc_size,
metal_phys_addr_t rsc_pa)
{
struct metal_io_region *io;
void *rsc_shm;
int ret;
ret = metal_shmem_open(shm_file, shm_size, &io);
if (ret) {
printf("Failed to init rproc, failed to open shm %s.\n",
shm_file);
return -1;
}
rsc_shm = metal_io_virt(io, rsc_pa);
memcpy(rsc_shm, rsc_table, rsc_size);
io->ops.close(io);
free(io);
return 0;
}
static struct remoteproc *
platform_create_proc(int proc_index, int rsc_index)
{
struct remoteproc_priv *prproc;
void *rsc_table, *rsc_table_shm;
int rsc_size;
int ret;
metal_phys_addr_t pa;
(void)proc_index;
rsc_table = get_resource_table(rsc_index, &rsc_size);
prproc = &rproc_priv_table[proc_index];
/* Setup resource table
* This step can be done out of the application.
* Assumes the unix server side setup resource table. */
if (is_sk_unix_server(prproc->ipi.path)) {
ret = platform_slave_setup_resource_table(prproc->shm_file,
prproc->shm_size,
rsc_table, rsc_size,
RSC_MEM_PA);
if (ret) {
printf("Failed to initialize resource table\n");
return NULL;
}
}
/* Initialize remoteproc instance */
if (!remoteproc_init(&rproc_inst, &linux_proc_ops, prproc))
return NULL;
/* Mmap resource table */
pa = RSC_MEM_PA;
rsc_table_shm = remoteproc_mmap(&rproc_inst, &pa, NULL, rsc_size,
0, &rproc_inst.rsc_io);
/* parse resource table to remoteproc */
ret = remoteproc_set_rsc_table(&rproc_inst, rsc_table_shm, rsc_size);
if (ret) {
printf("Failed to set resource table to remoteproc\r\n");
remoteproc_remove(&rproc_inst);
return NULL;
}
printf("Initialize remoteproc successfully.\r\n");
return &rproc_inst;
}
int platform_init(int argc, char *argv[], void **platform)
{
unsigned long proc_id = 0;
unsigned long rsc_id = 0;
struct remoteproc *rproc;
if (!platform) {
fprintf(stderr, "Failed to initialize platform, NULL pointer"
"to store platform data.\n");
return -EINVAL;
}
/* Initialize HW system components */
init_system();
if (argc >= 2) {
proc_id = strtoul(argv[1], NULL, 0);
}
if (argc >= 3) {
rsc_id = strtoul(argv[2], NULL, 0);
}
rproc = platform_create_proc(proc_id, rsc_id);
if (!rproc) {
fprintf(stderr, "Failed to create remoteproc device.\n");
return -EINVAL;
}
*platform = rproc;
return 0;
}
struct rpmsg_device *
platform_create_rpmsg_vdev(void *platform, unsigned int vdev_index,
unsigned int role,
void (*rst_cb)(struct virtio_device *vdev),
rpmsg_ns_bind_cb ns_bind_cb)
{
struct remoteproc *rproc = platform;
struct rpmsg_virtio_device *rpmsg_vdev;
struct virtio_device *vdev;
void *shbuf;
struct metal_io_region *shbuf_io;
int ret;
/* Setup resource table */
rpmsg_vdev = metal_allocate_memory(sizeof(*rpmsg_vdev));
if (!rpmsg_vdev)
return NULL;
shbuf_io = remoteproc_get_io_with_pa(rproc, SHARED_BUF_PA);
if (!shbuf_io)
return NULL;
shbuf = metal_io_phys_to_virt(shbuf_io, SHARED_BUF_PA);
printf("creating remoteproc virtio\r\n");
/* TODO: can we have a wrapper for the following two functions? */
vdev = remoteproc_create_virtio(rproc, vdev_index, role, rst_cb);
if (!vdev) {
printf("failed remoteproc_create_virtio\r\n");
goto err1;
}
printf("initializing rpmsg shared buffer pool\r\n");
/* Only RPMsg virtio master needs to initialize the shared buffers pool */
rpmsg_virtio_init_shm_pool(&shpool, shbuf, SHARED_BUF_SIZE);
printf("initializing rpmsg vdev\r\n");
/* RPMsg virtio slave can set shared buffers pool argument to NULL */
ret = rpmsg_init_vdev(rpmsg_vdev, vdev, ns_bind_cb,
shbuf_io,
&shpool);
if (ret) {
printf("failed rpmsg_init_vdev\r\n");
goto err2;
}
return rpmsg_virtio_get_rpmsg_device(rpmsg_vdev);
err2:
remoteproc_remove_virtio(rproc, vdev);
err1:
metal_free_memory(rpmsg_vdev);
return NULL;
}
int platform_poll(void *priv)
{
struct remoteproc *rproc = priv;
struct remoteproc_priv *prproc;
struct vring_ipi_info *ipi;
unsigned int flags;
prproc = rproc->priv;
ipi = &prproc->ipi;
while(1) {
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&ipi->sync))) {
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
break;
}
_rproc_wait();
metal_irq_restore_enable(flags);
}
return 0;
}
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev)
{
(void)rpdev;
}
void platform_cleanup(void *platform)
{
struct remoteproc *rproc = platform;
if (rproc)
remoteproc_remove(rproc);
cleanup_system();
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2016 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* This file populates resource table for BM remote
* for use by the Linux Master */
#ifndef PLATFORM_INFO_H
#define PLATFORM_INFO_H
#include <openamp/remoteproc.h>
#include <openamp/virtio.h>
#include <openamp/rpmsg.h>
#if defined __cplusplus
extern "C" {
#endif
/**
* platform_init - initialize the platform
*
* It will initialize the platform.
*
* @argc: number of arguments
* @argv: array of the input arguements
* @platform: pointer to store the platform data pointer
*
* return 0 for success or negative value for failure
*/
int platform_init(int argc, char *argv[], void **platform);
/**
* platform_create_rpmsg_vdev - create rpmsg vdev
*
* It will create rpmsg virtio device, and returns the rpmsg virtio
* device pointer.
*
* @platform: pointer to the private data
* @vdev_index: index of the virtio device, there can more than one vdev
* on the platform.
* @role: virtio master or virtio slave of the vdev
* @rst_cb: virtio device reset callback
* @ns_bind_cb: rpmsg name service bind callback
*
* return pointer to the rpmsg virtio device
*/
struct rpmsg_device *
platform_create_rpmsg_vdev(void *platform, unsigned int vdev_index,
unsigned int role,
void (*rst_cb)(struct virtio_device *vdev),
rpmsg_ns_bind_cb ns_bind_cb);
/**
* platform_poll - platform poll function
*
* @platform: pointer to the platform
*
* return negative value for errors, otherwise 0.
*/
int platform_poll(void *platform);
/**
* platform_release_rpmsg_vdev - release rpmsg virtio device
*
* @rpdev: pointer to the rpmsg device
*/
void platform_release_rpmsg_vdev(struct rpmsg_device *rpdev);
/**
* platform_cleanup - clean up the platform resource
*
* @platform: pointer to the platform
*/
void platform_cleanup(void *platform);
#if defined __cplusplus
}
#endif
#endif /* PLATFORM_INFO_H */

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* This file populates resource table for BM remote
* for use by the Linux Master */
#include <openamp/open_amp.h>
#include "rsc_table.h"
#define RPMSG_IPU_C0_FEATURES 1
/* VirtIO rpmsg device id */
#define VIRTIO_ID_RPMSG_ 7
/* Remote supports Name Service announcement */
#define VIRTIO_RPMSG_F_NS 0
#define NUM_VRINGS 0x02
#define VRING_ALIGN 0x1000
#define RING_TX 0x00004000
#define RING_RX 0x00008000
#define VRING_SIZE 256
#define NUM_TABLE_ENTRIES 1
struct remote_resource_table resources = {
/* Version */
1,
/* NUmber of table entries */
NUM_TABLE_ENTRIES,
/* reserved fields */
{0, 0,},
/* Offsets of rsc entries */
{
offsetof(struct remote_resource_table, rpmsg_vdev),
},
/* Virtio device entry */
{
RSC_VDEV, VIRTIO_ID_RPMSG_, 0, RPMSG_IPU_C0_FEATURES, 0, 0, 0,
NUM_VRINGS, {0, 0},
},
/* Vring rsc entry - part of vdev rsc entry */
{RING_TX, VRING_ALIGN, VRING_SIZE, 1, 0},
{RING_RX, VRING_ALIGN, VRING_SIZE, 2, 0},
};
void *get_resource_table (int rsc_id, int *len)
{
(void) rsc_id;
*len = sizeof(resources);
return &resources;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
* Copyright (c) 2016 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* This file populates resource table for BM remote
* for use by the Linux Master */
#ifndef RSC_TABLE_H_
#define RSC_TABLE_H_
#include <stddef.h>
#include <openamp/open_amp.h>
#if defined __cplusplus
extern "C" {
#endif
#define NO_RESOURCE_ENTRIES 1
/* Resource table for the given remote */
struct remote_resource_table {
unsigned int version;
unsigned int num;
unsigned int reserved[2];
unsigned int offset[NO_RESOURCE_ENTRIES];
/* rpmsg vdev entry */
struct fw_rsc_vdev rpmsg_vdev;
struct fw_rsc_vdev_vring rpmsg_vring0;
struct fw_rsc_vdev_vring rpmsg_vring1;
};
void *get_resource_table (int rsc_id, int *len);
#if defined __cplusplus
}
#endif
#endif /* RSC_TABLE_H_ */

View File

@@ -0,0 +1,2 @@
collect (APP_COMMON_SOURCES helper.c)

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* All rights reserved.
*
* Copyright (c) 2015 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <stdio.h>
#include <metal/sys.h>
int init_system()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
metal_init(&metal_param);
return 0;
}
void cleanup_system()
{
metal_finish();
}