aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMorten Borup Petersen <morten.petersen@arm.com>2019-05-29 11:05:35 +0100
committerTushar Khandelwal <tushar.khandelwal@arm.com>2019-09-04 11:37:10 +0100
commit1823b4070df6fb9fd214d75f08e79ba815a95a33 (patch)
treed88684620192d8ef0b852adc7a2ef661217dd7fd
parentdcdab40635b39fb7b2cb24474060d0d4560cb2af (diff)
add openamp framework and rpmsg clientCORSTONE-700-2019.09.23
Change-Id: I3c0cb2b52975af89d6e2d5482389d9ebc06a0cfe Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
-rw-r--r--framework/include/libmetal/compiler.h71
-rw-r--r--framework/include/libmetal/list.h102
-rw-r--r--framework/include/libmetal/mutex.h71
-rw-r--r--framework/include/libmetal/utilities.h153
-rw-r--r--framework/include/openamp/rpmsg.h353
-rw-r--r--framework/include/openamp/rpmsg_client.h16
-rw-r--r--framework/include/openamp/rpmsg_internal.h101
-rw-r--r--framework/src/Makefile4
-rw-r--r--framework/src/openamp/rpmsg.c269
-rw-r--r--framework/src/openamp/rpmsg_client.c100
-rw-r--r--tools/build_system/firmware.mk7
11 files changed, 1247 insertions, 0 deletions
diff --git a/framework/include/libmetal/compiler.h b/framework/include/libmetal/compiler.h
new file mode 100644
index 0000000..acb4c9b
--- /dev/null
+++ b/framework/include/libmetal/compiler.h
@@ -0,0 +1,71 @@
+#ifndef _COMPILER_H_
+#define _COMPILER_H_
+
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**************************************************************************
+ * FILE NAME
+ *
+ * compiler.h
+ *
+ * DESCRIPTION
+ *
+ * This file defines compiler-specific macros.
+ *
+ ***************************************************************************/
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/* IAR ARM build tools */
+#if defined(__ICCARM__)
+
+#ifndef OPENAMP_PACKED_BEGIN
+#define OPENAMP_PACKED_BEGIN __packed
+#endif
+
+#ifndef OPENAMP_PACKED_END
+#define OPENAMP_PACKED_END
+#endif
+
+/* GNUC */
+#elif defined(__GNUC__)
+
+#ifndef OPENAMP_PACKED_BEGIN
+#define OPENAMP_PACKED_BEGIN
+#endif
+
+#ifndef OPENAMP_PACKED_END
+#define OPENAMP_PACKED_END __attribute__((__packed__))
+#endif
+
+/* ARM GCC */
+#elif defined(__CC_ARM)
+
+#ifndef OPENAMP_PACKED_BEGIN
+#define OPENAMP_PACKED_BEGIN _Pragma("pack(1U)")
+#endif
+
+#ifndef OPENAMP_PACKED_END
+#define OPENAMP_PACKED_END _Pragma("pack()")
+#endif
+
+#else
+/*
+ * There is no default definition here to avoid wrong structures packing in case
+ * of not supported compiler
+ */
+#error Please implement the structure packing macros for your compiler here!
+#endif
+
+#if defined __cplusplus
+}
+#endif
+
+#endif /* _COMPILER_H_ */
diff --git a/framework/include/libmetal/list.h b/framework/include/libmetal/list.h
new file mode 100644
index 0000000..8e1f2db
--- /dev/null
+++ b/framework/include/libmetal/list.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * @file list.h
+ * @brief List primitives for libmetal.
+ */
+
+#ifndef __METAL_LIST__H__
+#define __METAL_LIST__H__
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup list List Primitives
+ * @{ */
+
+struct metal_list {
+ struct metal_list *next, *prev;
+};
+
+/*
+ * METAL_INIT_LIST - used for initializing an list elmenet in a static struct
+ * or global
+ */
+#define METAL_INIT_LIST(name) { .next = &name, .prev = &name }
+/*
+ * METAL_DECLARE_LIST - used for defining and initializing a global or
+ * static singleton list
+ */
+#define METAL_DECLARE_LIST(name) \
+ struct metal_list name = METAL_INIT_LIST(name)
+
+static inline void metal_list_init(struct metal_list *list)
+{
+ list->next = list->prev = list;
+}
+
+static void __attribute__ ((noinline)) metal_list_add_before(struct metal_list *node,
+ struct metal_list *new_node)
+{
+ new_node->prev = node->prev;
+ new_node->next = node;
+ new_node->next->prev = new_node;
+ new_node->prev->next = new_node;
+}
+
+static inline void metal_list_add_after(struct metal_list *node,
+ struct metal_list *new_node)
+{
+ new_node->prev = node;
+ new_node->next = node->next;
+ new_node->next->prev = new_node;
+ new_node->prev->next = new_node;
+}
+
+static inline void metal_list_add_head(struct metal_list *list,
+ struct metal_list *node)
+{
+ metal_list_add_after(list, node);
+}
+
+static inline void metal_list_add_tail(struct metal_list *list,
+ struct metal_list *node)
+{
+ metal_list_add_before(list, node);
+}
+
+static inline int metal_list_is_empty(struct metal_list *list)
+{
+ return list->next == list;
+}
+
+static inline void metal_list_del(struct metal_list *node)
+{
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ node->next = node->prev = node;
+}
+
+static inline struct metal_list *metal_list_first(struct metal_list *list)
+{
+ return metal_list_is_empty(list) ? NULL : list->next;
+}
+
+#define metal_list_for_each(list, node) \
+ for ((node) = (list)->next; \
+ (node) != (list); \
+ (node) = (node)->next)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __METAL_LIST__H__ */
diff --git a/framework/include/libmetal/mutex.h b/framework/include/libmetal/mutex.h
new file mode 100644
index 0000000..2dfd21e
--- /dev/null
+++ b/framework/include/libmetal/mutex.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * @file generic/mutex.h
+ * @brief Generic mutex primitives for libmetal.
+ */
+
+#ifndef __METAL_GENERIC_MUTEX__H__
+#define __METAL_GENERIC_MUTEX__H__
+
+#include <stdatomic.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ atomic_int v;
+} metal_mutex_t;
+
+/*
+ * METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct
+ * or global
+ */
+#define METAL_MUTEX_INIT(m) { ATOMIC_VAR_INIT(0) }
+/*
+ * METAL_MUTEX_DEFINE - used for defining and initializing a global or
+ * static singleton mutex
+ */
+#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = METAL_MUTEX_INIT(m)
+
+static inline void metal_mutex_init(metal_mutex_t *mutex)
+{
+ atomic_store(&mutex->v, 0);
+}
+
+static inline void __metal_mutex_deinit(metal_mutex_t *mutex)
+{
+ (void)mutex;
+}
+
+static inline int metal_mutex_try_acquire(metal_mutex_t *mutex)
+{
+ return 1 - atomic_flag_test_and_set(&mutex->v);
+}
+
+static inline void metal_mutex_acquire(metal_mutex_t *mutex)
+{
+ while (atomic_flag_test_and_set(&mutex->v)) {
+ ;
+ }
+}
+
+static inline void metal_mutex_release(metal_mutex_t *mutex)
+{
+ atomic_flag_clear(&mutex->v);
+}
+
+static inline int metal_mutex_is_acquired(metal_mutex_t *mutex)
+{
+ return atomic_load(&mutex->v);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __METAL_GENERIC_MUTEX__H__ */
diff --git a/framework/include/libmetal/utilities.h b/framework/include/libmetal/utilities.h
new file mode 100644
index 0000000..e60f345
--- /dev/null
+++ b/framework/include/libmetal/utilities.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * @file utilities.h
+ * @brief Utility routines for libmetal.
+ */
+
+#ifndef __METAL_UTILITIES__H__
+#define __METAL_UTILITIES__H__
+
+#include <stdint.h>
+#include <limits.h>
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup utilities Simple Utilities
+ * @{ */
+
+/** Marker for unused function arguments/variables. */
+#define metal_unused(x) do { (x) = (x); } while (0)
+
+/** Figure out number of elements in an array. */
+#define metal_dim(x) (sizeof(x) / sizeof(x[0]))
+
+/** Minimum of two numbers (warning: multiple evaluation!). */
+#define metal_min(x, y) ((x) < (y) ? (x) : (y))
+
+/** Maximum of two numbers (warning: multiple evaluation!). */
+#define metal_max(x, y) ((x) > (y) ? (x) : (y))
+
+/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!). */
+#define metal_sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
+
+/** Align 'size' down to a multiple of 'align' (must be a power of two). */
+#define metal_align_down(size, align) \
+ ((size) & ~((align) - 1))
+
+/** Align 'size' up to a multiple of 'align' (must be a power of two). */
+#define metal_align_up(size, align) \
+ metal_align_down((size) + (align) - 1, align)
+
+/** Divide (and round down). */
+#define metal_div_round_down(num, den) \
+ ((num) / (den))
+
+/** Divide (and round up). */
+#define metal_div_round_up(num, den) \
+ metal_div_round_down((num) + (den) - 1, (den))
+
+/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */
+#define metal_ptr_align_down(ptr, align) \
+ (void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align)))
+
+/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */
+#define metal_ptr_align_up(ptr, align) \
+ (void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align)))
+
+/** Compute offset of a field within a structure. */
+#define metal_offset_of(structure, member) \
+ ((uintptr_t) &(((structure *) 0)->member))
+
+/** Compute pointer to a structure given a pointer to one of its fields. */
+#define metal_container_of(ptr, structure, member) \
+ (void *)((uintptr_t)(ptr) - metal_offset_of(structure, member))
+
+#define METAL_BITS_PER_ULONG (CHAR_BIT * sizeof(unsigned long))
+
+#define metal_bit(bit) (1UL << (bit))
+
+#define metal_bitmap_longs(x) metal_div_round_up((x), METAL_BITS_PER_ULONG)
+
+static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit)
+{
+ bitmap[bit / METAL_BITS_PER_ULONG] |=
+ metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
+}
+
+static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit)
+{
+ return ((bitmap[bit / METAL_BITS_PER_ULONG] &
+ metal_bit(bit & (METAL_BITS_PER_ULONG - 1))) == 0) ? 0 : 1;
+}
+
+static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit)
+{
+ bitmap[bit / METAL_BITS_PER_ULONG] &=
+ ~metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
+}
+
+static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit)
+{
+ return !metal_bitmap_is_bit_set(bitmap, bit);
+}
+
+static inline unsigned int
+metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start,
+ unsigned int max)
+{
+ unsigned int bit;
+ for (bit = start;
+ bit < max && !metal_bitmap_is_bit_set(bitmap, bit);
+ bit ++)
+ ;
+ return bit;
+}
+
+#define metal_bitmap_for_each_set_bit(bitmap, bit, max) \
+ for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max)); \
+ (bit) < (max); \
+ (bit) = metal_bitmap_next_set_bit((bitmap), (bit + 1), (max)))
+
+static inline unsigned int
+metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start,
+ unsigned int max)
+{
+ unsigned int bit;
+ for (bit = start;
+ bit < max && !metal_bitmap_is_bit_clear(bitmap, bit);
+ bit ++)
+ ;
+ return bit;
+}
+
+#define metal_bitmap_for_each_clear_bit(bitmap, bit, max) \
+ for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max)); \
+ (bit) < (max); \
+ (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max)))
+
+static inline unsigned long metal_log2(unsigned long in)
+{
+ unsigned long result;
+
+ assert((in & (in - 1)) == 0);
+
+ for (result = 0; (1UL << result) < in; result ++)
+ ;
+ return result;
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __METAL_UTILITIES__H__ */
diff --git a/framework/include/openamp/rpmsg.h b/framework/include/openamp/rpmsg.h
new file mode 100644
index 0000000..6e4fbcd
--- /dev/null
+++ b/framework/include/openamp/rpmsg.h
@@ -0,0 +1,353 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * All rights reserved.
+ * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _RPMSG_H_
+#define _RPMSG_H_
+
+#include <libmetal/mutex.h>
+#include <libmetal/list.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/* Configurable parameters */
+#define RPMSG_NAME_SIZE (32)
+#define RPMSG_ADDR_BMP_SIZE (4)
+
+#define RPMSG_NS_EPT_ADDR (0x35)
+#define RPMSG_ADDR_ANY 0xFFFFFFFF
+
+/* Error macros. */
+#define RPMSG_SUCCESS 0
+#define RPMSG_ERROR_BASE -2000
+#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1)
+#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2)
+#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 3)
+#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 4)
+#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5)
+#define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6)
+#define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7)
+
+struct rpmsg_endpoint;
+struct rpmsg_device;
+
+typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data,
+ size_t len, uint32_t src, void *priv);
+typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept);
+typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev,
+ const char *name, uint32_t dest);
+
+/**
+ * struct rpmsg_endpoint - binds a local rpmsg address to its user
+ * @name:name of the service supported
+ * @rdev: pointer to the rpmsg device
+ * @addr: local address of the endpoint
+ * @dest_addr: address of the default remote endpoint binded.
+ * @cb: user rx callback, return value of this callback is reserved
+ * for future use, for now, only allow RPMSG_SUCCESS as return value.
+ * @ns_unbind_cb: end point service service unbind callback, called when remote
+ * ept is destroyed.
+ * @node: end point node.
+ * @addr: local rpmsg address
+ * @priv: private data for the driver's use
+ *
+ * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
+ * it binds an rpmsg address with an rx callback handler.
+ */
+struct rpmsg_endpoint {
+ char name[RPMSG_NAME_SIZE];
+ struct rpmsg_device *rdev;
+ uint32_t addr;
+ uint32_t dest_addr;
+ rpmsg_ept_cb cb;
+ rpmsg_ns_unbind_cb ns_unbind_cb;
+ struct metal_list node;
+ void *priv;
+};
+
+/**
+ * struct rpmsg_device_ops - RPMsg device operations
+ * @send_offchannel_raw: send RPMsg data
+ */
+struct rpmsg_device_ops {
+ int (*send_offchannel_raw)(struct rpmsg_device *rdev,
+ uint32_t src, uint32_t dst,
+ const void *data, int size, int wait);
+};
+
+/**
+ * struct rpmsg_device - representation of a RPMsg device
+ * @endpoints: list of endpoints
+ * @ns_ept: name service endpoint
+ * @bitmap: table endpoin address allocation.
+ * @lock: mutex lock for rpmsg management
+ * @ns_bind_cb: callback handler for name service announcement without local
+ * endpoints waiting to bind.
+ * @ops: RPMsg device operations
+ */
+struct rpmsg_device {
+ struct metal_list endpoints;
+ struct rpmsg_endpoint ns_ept;
+ unsigned long bitmap[RPMSG_ADDR_BMP_SIZE];
+ metal_mutex_t lock;
+ rpmsg_ns_bind_cb ns_bind_cb;
+ struct rpmsg_device_ops ops;
+};
+
+/**
+ * rpmsg_send_offchannel_raw() - send a message across to the remote processor,
+ * specifying source and destination address.
+ * @ept: the rpmsg endpoint
+ * @data: payload of the message
+ * @len: length of the payload
+ *
+ * This function sends @data of length @len to the remote @dst address from
+ * the source @src address.
+ * The message will be sent to the remote processor which the channel belongs
+ * to.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
+ uint32_t dst, const void *data, int size,
+ int wait);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of the message
+ * @len: length of the payload
+ *
+ * This function sends @data of length @len based on the @ept.
+ * The message will be sent to the remote processor which the channel belongs
+ * to, using @ept's source and destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data,
+ int len)
+{
+ if (ept->dest_addr == RPMSG_ADDR_ANY)
+ return RPMSG_ERR_ADDR;
+ return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data,
+ len, true);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * channel belongs to, using @ept's source address.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data,
+ int len, uint32_t dst)
+{
+ return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, true);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept,
+ uint32_t src, uint32_t dst,
+ const void *data, int len)
+{
+ return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_trysend() - send a message across to the remote processor
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @ept channel.
+ * The message will be sent to the remote processor which the @ept
+ * channel belongs to, using @ept's source and destination addresses.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data,
+ int len)
+{
+ if (ept->dest_addr == RPMSG_ADDR_ANY)
+ return RPMSG_ERR_ADDR;
+ return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data,
+ len, false);
+}
+
+/**
+ * rpmsg_trysendto() - send a message across to the remote processor,
+ * specify dst
+ * @ept: the rpmsg endpoint
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @ept
+ * channel belongs to, using @ept's source address.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data,
+ int len, uint32_t dst)
+{
+ return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, false);
+}
+
+/**
+ * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses
+ * @ept: the rpmsg endpoint
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @ept
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Returns number of bytes it has sent or negative error value on failure.
+ */
+static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept,
+ uint32_t src, uint32_t dst,
+ const void *data, int len)
+{
+ return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false);
+}
+
+/**
+ * rpmsg_init_ept - initialize rpmsg endpoint
+ *
+ * Initialize an RPMsg endpoint with a name, source address,
+ * remoteproc address, endpoitn callback, and destroy endpoint callback.
+ *
+ * @ept: pointer to rpmsg endpoint
+ * @name: service name associated to the endpoint
+ * @src: local address of the endpoint
+ * @dest: target address of the endpoint
+ * @cb: endpoint callback
+ * @ns_unbind_cb: end point service unbind callback, called when remote ept is
+ * destroyed.
+ */
+static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept,
+ const char *name,
+ uint32_t src, uint32_t dest,
+ rpmsg_ept_cb cb,
+ rpmsg_ns_unbind_cb ns_unbind_cb)
+{
+ strncpy(ept->name, name, sizeof(ept->name));
+ ept->addr = src;
+ ept->dest_addr = dest;
+ ept->cb = cb;
+ ept->ns_unbind_cb = ns_unbind_cb;
+}
+
+/**
+ * rpmsg_create_ept - create rpmsg endpoint and register it to rpmsg device
+ *
+ * Create a RPMsg endpoint, initialize it with a name, source address,
+ * remoteproc address, endpoitn callback, and destroy endpoint callback,
+ * and register it to the RPMsg device.
+ *
+ * @ept: pointer to rpmsg endpoint
+ * @name: service name associated to the endpoint
+ * @src: local address of the endpoint
+ * @dest: target address of the endpoint
+ * @cb: endpoint callback
+ * @ns_unbind_cb: end point service unbind callback, called when remote ept is
+ * destroyed.
+ *
+ * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
+ * it binds an rpmsg address with an rx callback handler.
+ *
+ * Rpmsg client should create an endpoint to discuss with remote. rpmsg client
+ * provide at least a channel name, a callback for message notification and by
+ * default endpoint source address should be set to RPMSG_ADDR_ANY.
+ *
+ * As an option Some rpmsg clients can specify an endpoint with a specific
+ * source address.
+ */
+
+int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
+ const char *name, uint32_t src, uint32_t dest,
+ rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb);
+
+/**
+ * rpmsg_destroy_ept - destroy rpmsg endpoint and unregister it from rpmsg
+ * device
+ *
+ * @ept: pointer to the rpmsg endpoint
+ *
+ * It unregisters the rpmsg endpoint from the rpmsg device and calls the
+ * destroy endpoint callback if it is provided.
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
+
+/**
+ * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send
+ *
+ * @ept: pointer to rpmsg endpoint
+ *
+ * Returns 1 if the rpmsg endpoint has both local addr and destination
+ * addr set, 0 otherwise
+ */
+static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept)
+{
+ return (ept->dest_addr != RPMSG_ADDR_ANY &&
+ ept->addr != RPMSG_ADDR_ANY);
+}
+
+#if defined __cplusplus
+}
+#endif
+
+#endif /* _RPMSG_H_ */
diff --git a/framework/include/openamp/rpmsg_client.h b/framework/include/openamp/rpmsg_client.h
new file mode 100644
index 0000000..e64fdec
--- /dev/null
+++ b/framework/include/openamp/rpmsg_client.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _RPMSG_CLIENT_H_
+#define _RPMSG_CLIENT_H_
+
+struct rpmsg_device *rpmesg_device;
+extern struct rpmsg_endpoint* endpoint_create(struct rpmsg_device *rdev, void *priv);
+extern struct rpmsg_device* init_rpmsg();
+struct rpmsg_endpoint* get_endpoint(uint32_t address);
+
+#endif
diff --git a/framework/include/openamp/rpmsg_internal.h b/framework/include/openamp/rpmsg_internal.h
new file mode 100644
index 0000000..e4e1221
--- /dev/null
+++ b/framework/include/openamp/rpmsg_internal.h
@@ -0,0 +1,101 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RPMSG_INTERNAL_H_
+#define _RPMSG_INTERNAL_H_
+
+#include <stdint.h>
+#include <openamp/rpmsg.h>
+#include <libmetal/compiler.h>
+
+#ifdef RPMSG_DEBUG
+#include <metal/log.h>
+
+#define RPMSG_ASSERT(_exp, _msg) do { \
+ if (!(_exp)) { \
+ metal_log(METAL_LOG_EMERGENCY, \
+ "FATAL: %s - "_msg, __func__); \
+ while (1) { \
+ ; \
+ } \
+ } \
+ } while (0)
+#else
+#define RPMSG_ASSERT(_exp, _msg) do { \
+ if (!(_exp)) \
+ while (1) { \
+ ; \
+ } \
+ } while (0)
+#endif
+
+#define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr))
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting
+ * acknowledgment.
+ */
+enum rpmsg_ns_flags {
+ RPMSG_NS_CREATE = 0,
+ RPMSG_NS_DESTROY = 1,
+};
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+OPENAMP_PACKED_BEGIN
+struct rpmsg_hdr {
+ uint32_t src;
+ uint32_t dst;
+ uint32_t reserved;
+ uint16_t len;
+ uint16_t flags;
+} OPENAMP_PACKED_END;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+OPENAMP_PACKED_BEGIN
+struct rpmsg_ns_msg {
+ char name[RPMSG_NAME_SIZE];
+ uint32_t addr;
+ uint32_t flags;
+} OPENAMP_PACKED_END;
+
+int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags);
+
+struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev,
+ const char *name, uint32_t addr,
+ uint32_t dest_addr);
+int rpmsg_register_endpoint(struct rpmsg_device *rdev,
+ struct rpmsg_endpoint *ept);
+
+static inline struct rpmsg_endpoint *
+rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr)
+{
+ return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY);
+}
+
+#endif /* _RPMSG_INTERNAL_H_ */
diff --git a/framework/src/Makefile b/framework/src/Makefile
index b83968e..61512ce 100644
--- a/framework/src/Makefile
+++ b/framework/src/Makefile
@@ -14,6 +14,10 @@ BS_LIB_SOURCES += fwk_interrupt.c
BS_LIB_SOURCES += fwk_mm.c
BS_LIB_SOURCES += fwk_module.c
BS_LIB_SOURCES += fwk_slist.c
+ifeq ($(BUILD_HAS_OPENAMP),yes)
+ BS_LIB_SOURCES += openamp/rpmsg.c
+ BS_LIB_SOURCES += openamp/rpmsg_client.c
+endif
ifeq ($(BUILD_HAS_MULTITHREADING),yes)
BS_LIB_SOURCES += fwk_multi_thread.c
else
diff --git a/framework/src/openamp/rpmsg.c b/framework/src/openamp/rpmsg.c
new file mode 100644
index 0000000..66413d4
--- /dev/null
+++ b/framework/src/openamp/rpmsg.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2014, Mentor Graphics Corporation
+ * All rights reserved.
+ * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (c) 2018 Linaro, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libmetal/utilities.h>
+#include <libmetal/mutex.h>
+#include <openamp/rpmsg_internal.h>
+
+/**
+ * rpmsg_get_address
+ *
+ * This function provides unique 32 bit address.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ *
+ * return - a unique address
+ */
+static uint32_t rpmsg_get_address(unsigned long *bitmap, int size)
+{
+ unsigned int addr = RPMSG_ADDR_ANY;
+ unsigned int nextbit;
+
+ nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size);
+ if (nextbit < (uint32_t)size) {
+ addr = nextbit;
+ metal_bitmap_set_bit(bitmap, nextbit);
+ }
+
+ return addr;
+}
+
+/**
+ * rpmsg_release_address
+ *
+ * Frees the given address.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ */
+static void rpmsg_release_address(unsigned long *bitmap, int size,
+ int addr)
+{
+ if (addr < size)
+ metal_bitmap_clear_bit(bitmap, addr);
+}
+
+/**
+ * rpmsg_is_address_set
+ *
+ * Checks whether address is used or free.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ *
+ * return - TRUE/FALSE
+ */
+static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
+{
+ if (addr < size)
+ return metal_bitmap_is_bit_set(bitmap, addr);
+ else
+ return RPMSG_ERR_PARAM;
+}
+
+/**
+ * rpmsg_set_address
+ *
+ * Marks the address as consumed.
+ *
+ * @param bitmap - bit map for addresses
+ * @param size - size of bitmap
+ * @param addr - address to free
+ *
+ * return - none
+ */
+static int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
+{
+ if (addr < size) {
+ metal_bitmap_set_bit(bitmap, addr);
+ return RPMSG_SUCCESS;
+ } else {
+ return RPMSG_ERR_PARAM;
+ }
+}
+
+/**
+ * This function sends rpmsg "message" to remote device.
+ *
+ * @param ept - pointer to end point
+ * @param src - source address of channel
+ * @param dst - destination address of channel
+ * @param data - data to transmit
+ * @param size - size of data
+ * @param wait - boolean, wait or not for buffer to become
+ * available
+ *
+ * @return - size of data sent or negative value for failure.
+ *
+ */
+int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
+ uint32_t dst, const void *data, int size,
+ int wait)
+{
+ struct rpmsg_device *rdev;
+
+ if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY)
+ return RPMSG_ERR_PARAM;
+
+ rdev = ept->rdev;
+
+ if (rdev->ops.send_offchannel_raw)
+ return rdev->ops.send_offchannel_raw(rdev, src, dst, data,
+ size, wait);
+
+ return RPMSG_ERR_PARAM;
+}
+
+int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags)
+{
+ struct rpmsg_ns_msg ns_msg;
+ int ret;
+
+ ns_msg.flags = flags;
+ ns_msg.addr = ept->addr;
+ strncpy(ns_msg.name, ept->name, sizeof(ns_msg.name));
+ ret = rpmsg_send_offchannel_raw(ept, ept->addr,
+ RPMSG_NS_EPT_ADDR,
+ &ns_msg, sizeof(ns_msg), true);
+ if (ret < 0)
+ return ret;
+ else
+ return RPMSG_SUCCESS;
+}
+
+struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev,
+ const char *name, uint32_t addr,
+ uint32_t dest_addr)
+{
+ struct metal_list *node;
+ struct rpmsg_endpoint *ept;
+
+ metal_list_for_each(&rdev->endpoints, node) {
+ int name_match = 0;
+
+ ept = metal_container_of(node, struct rpmsg_endpoint, node);
+ /* try to get by local address only */
+ if (addr != RPMSG_ADDR_ANY && ept->addr == addr)
+ return ept;
+ /* try to find match on local end remote address */
+ if (addr == ept->addr && dest_addr == ept->dest_addr)
+ return ept;
+ /* else use name service and destination address */
+ if (name)
+ name_match = !strncmp(ept->name, name,
+ sizeof(ept->name));
+ if (!name || !name_match)
+ continue;
+ /* destination address is known, equal to ept remote address*/
+ if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr)
+ return ept;
+ /* ept is registered but not associated to remote ept*/
+ if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY)
+ return ept;
+ }
+ return NULL;
+}
+
+static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept)
+{
+ struct rpmsg_device *rdev;
+
+ if (!ept)
+ return;
+
+ rdev = ept->rdev;
+
+ if (ept->addr != RPMSG_ADDR_ANY)
+ rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
+ ept->addr);
+ metal_list_del(&ept->node);
+}
+
+int rpmsg_register_endpoint(struct rpmsg_device *rdev,
+ struct rpmsg_endpoint *ept)
+{
+ ept->rdev = rdev;
+
+ metal_list_add_tail(&rdev->endpoints, &ept->node);
+ return RPMSG_SUCCESS;
+}
+
+int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
+ const char *name, uint32_t src, uint32_t dest,
+ rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb)
+{
+ int status;
+ uint32_t addr = src;
+
+ if (!ept)
+ return RPMSG_ERR_PARAM;
+
+ metal_mutex_acquire(&rdev->lock);
+ if (src != RPMSG_ADDR_ANY) {
+ status = rpmsg_is_address_set(rdev->bitmap,
+ RPMSG_ADDR_BMP_SIZE, src);
+ if (!status) {
+ /* Mark the address as used in the address bitmap. */
+ rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
+ src);
+ } else if (status > 0) {
+ status = RPMSG_SUCCESS;
+ goto ret_status;
+ } else {
+ goto ret_status;
+ }
+ } else {
+ addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
+ }
+
+ rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb);
+
+ status = rpmsg_register_endpoint(rdev, ept);
+ if (status < 0)
+ rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr);
+
+ if (!status && ept->dest_addr == RPMSG_ADDR_ANY) {
+ /* Send NS announcement to remote processor */
+ metal_mutex_release(&rdev->lock);
+ status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE);
+ metal_mutex_acquire(&rdev->lock);
+ if (status)
+ rpmsg_unregister_endpoint(ept);
+ }
+
+ret_status:
+ metal_mutex_release(&rdev->lock);
+ return status;
+}
+
+/**
+ * rpmsg_destroy_ept
+ *
+ * This function deletes rpmsg endpoint and performs cleanup.
+ *
+ * @param ept - pointer to endpoint to destroy
+ *
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+ struct rpmsg_device *rdev;
+
+ if (!ept)
+ return;
+
+ rdev = ept->rdev;
+ if (ept->addr != RPMSG_NS_EPT_ADDR)
+ (void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY);
+ metal_mutex_acquire(&rdev->lock);
+ rpmsg_unregister_endpoint(ept);
+ metal_mutex_release(&rdev->lock);
+}
diff --git a/framework/src/openamp/rpmsg_client.c b/framework/src/openamp/rpmsg_client.c
new file mode 100644
index 0000000..350d19c
--- /dev/null
+++ b/framework/src/openamp/rpmsg_client.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <fwk_errno.h>
+#include <fwk_id.h>
+#include <fwk_interrupt.h>
+#include <fwk_mm.h>
+#include <fwk_module.h>
+#include <fwk_module_idx.h>
+#include <openamp/rpmsg_internal.h>
+#include <openamp/rpmsg_client.h>
+#include <libmetal/mutex.h>
+#include <mod_mhuv2.h>
+#include <mod_log.h>
+#include <mod_eventhandler.h>
+
+struct rpmsg_ctx {
+ /* Log API pointer */
+ const struct mod_log_api *log_api;
+ const struct mod_mhu_driver_api *mhu2_api;
+ const struct mod_eventhandler_api *eventhandler_api;
+};
+static struct rpmsg_ctx rpmsg_ctx;
+
+
+struct rpmsg_endpoint* get_endpoint(uint32_t address)
+{
+ return rpmsg_get_endpoint(rpmesg_device,"arm-rpmsg", RPMSG_ADDR_ANY, address);
+}
+
+static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
+ uint32_t src, void *priv)
+{
+ int status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_EVENTHANDLER),
+ FWK_ID_API(FWK_MODULE_IDX_EVENTHANDLER, 0),&rpmsg_ctx.eventhandler_api);
+ if (status != FWK_SUCCESS)
+ return FWK_E_PANIC;
+
+ rpmsg_ctx.eventhandler_api->handleRpmsgEvent(ept, data, len);
+ return RPMSG_SUCCESS;
+}
+
+struct rpmsg_endpoint* endpoint_create(struct rpmsg_device *rdev, void *dest)
+{
+
+ struct rpmsg_endpoint *lept;
+ uint32_t dest_addr = (uint32_t)dest;
+ int status;
+ lept = fwk_mm_calloc(1,sizeof(*lept));
+ status = rpmsg_create_ept(lept, rdev, "arm-rpmsg",RPMSG_ADDR_ANY,
+ dest_addr,rpmsg_endpoint_cb, NULL);
+ if (status == RPMSG_SUCCESS)
+ return lept;
+ else
+ return RPMSG_SUCCESS;
+}
+
+static int send_rpmsg(struct rpmsg_device *rdev,
+ uint32_t src, uint32_t dst,
+ const void *data, int size, int wait)
+{
+ uint32_t message;
+ int status;
+ fwk_id_t fwk_dst;
+
+ status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_MHUV2),
+ FWK_ID_API(FWK_MODULE_IDX_MHUV2, 0),&rpmsg_ctx.mhu2_api);
+ if (status != FWK_SUCCESS)
+ return FWK_E_PANIC;
+
+ fwk_dst = rpmsg_ctx.mhu2_api->lookup_channel(dst);
+ message = *(uint32_t *)data;
+ status = rpmsg_ctx.mhu2_api->send_message(fwk_dst, message);
+
+ if(status == FWK_SUCCESS){
+ return RPMSG_SUCCESS;
+ } else {
+ return status;
+ }
+
+}
+
+struct rpmsg_device* init_rpmsg()
+{
+ struct rpmsg_device *rdev;
+ rdev = fwk_mm_calloc(1,sizeof(*rdev));
+ metal_mutex_init(&rdev->lock);
+ metal_list_init(&rdev->endpoints);
+ rdev->ops.send_offchannel_raw = send_rpmsg;
+ rdev->ns_bind_cb = NULL;
+ rpmesg_device = rdev;
+ return rdev;
+}
diff --git a/tools/build_system/firmware.mk b/tools/build_system/firmware.mk
index b9cebd4..91c7103 100644
--- a/tools/build_system/firmware.mk
+++ b/tools/build_system/firmware.mk
@@ -157,6 +157,13 @@ else
endif
export BUILD_HAS_NOTIFICATION
+ifeq ($(BS_FIRMWARE_HAS_OPENAMP),yes)
+ BUILD_HAS_OPENAMP := yes
+else
+ BUILD_HAS_OPENAMP := no
+endif
+export BUILD_HAS_OPENAMP
+
# Add directories to the list of targets to build
LIB_TARGETS_y += $(patsubst %,$(MODULES_DIR)/%/src, \
$(BUILD_STANDARD_MODULES))