zephyr/include/zephyr/drivers/ipm.h
Yong Cong Sin bbe5e1e6eb build: namespace the generated headers with zephyr/
Namespaced the generated headers with `zephyr` to prevent
potential conflict with other headers.

Introduce a temporary Kconfig `LEGACY_GENERATED_INCLUDE_PATH`
that is enabled by default. This allows the developers to
continue the use of the old include paths for the time being
until it is deprecated and eventually removed. The Kconfig will
generate a build-time warning message, similar to the
`CONFIG_TIMER_RANDOM_GENERATOR`.

Updated the includes path of in-tree sources accordingly.

Most of the changes here are scripted, check the PR for more
info.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-28 22:03:55 +02:00

276 lines
8 KiB
C

/**
* @file
*
* @brief Generic low-level inter-processor mailbox communication API.
*/
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_IPM_H_
#define ZEPHYR_INCLUDE_DRIVERS_IPM_H_
/**
* @brief IPM Interface
* @defgroup ipm_interface IPM Interface
* @since 1.0
* @version 1.0.0
* @ingroup io_interfaces
* @{
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @typedef ipm_callback_t
* @brief Callback API for incoming IPM messages
*
* These callbacks execute in interrupt context. Therefore, use only
* interrupt-safe APIS. Registration of callbacks is done via
* @a ipm_register_callback
*
* @param ipmdev Driver instance
* @param user_data Pointer to some private data provided at registration
* time.
* @param id Message type identifier.
* @param data Message data pointer. The correct amount of data to read out
* must be inferred using the message id/upper level protocol.
*/
typedef void (*ipm_callback_t)(const struct device *ipmdev, void *user_data,
uint32_t id, volatile void *data);
/**
* @typedef ipm_send_t
* @brief Callback API to send IPM messages
*
* See @a ipm_send() for argument definitions.
*/
typedef int (*ipm_send_t)(const struct device *ipmdev, int wait, uint32_t id,
const void *data, int size);
/**
* @typedef ipm_max_data_size_get_t
* @brief Callback API to get maximum data size
*
* See @a ipm_max_data_size_get() for argument definitions.
*/
typedef int (*ipm_max_data_size_get_t)(const struct device *ipmdev);
/**
* @typedef ipm_max_id_val_get_t
* @brief Callback API to get the ID's maximum value
*
* See @a ipm_max_id_val_get() for argument definitions.
*/
typedef uint32_t (*ipm_max_id_val_get_t)(const struct device *ipmdev);
/**
* @typedef ipm_register_callback_t
* @brief Callback API upon registration
*
* See @a ipm_register_callback() for argument definitions.
*/
typedef void (*ipm_register_callback_t)(const struct device *port,
ipm_callback_t cb,
void *user_data);
/**
* @typedef ipm_set_enabled_t
* @brief Callback API upon enablement of interrupts
*
* See @a ipm_set_enabled() for argument definitions.
*/
typedef int (*ipm_set_enabled_t)(const struct device *ipmdev, int enable);
/**
* @typedef ipm_complete_t
* @brief Callback API upon command completion
*
* See @a ipm_complete() for argument definitions.
*/
typedef void (*ipm_complete_t)(const struct device *ipmdev);
__subsystem struct ipm_driver_api {
ipm_send_t send;
ipm_register_callback_t register_callback;
ipm_max_data_size_get_t max_data_size_get;
ipm_max_id_val_get_t max_id_val_get;
ipm_set_enabled_t set_enabled;
#ifdef CONFIG_IPM_CALLBACK_ASYNC
ipm_complete_t complete;
#endif
};
/**
* @brief Try to send a message over the IPM device.
*
* A message is considered consumed once the remote interrupt handler
* finishes. If there is deferred processing on the remote side,
* or if outgoing messages must be queued and wait on an
* event/semaphore, a high-level driver can implement that.
*
* There are constraints on how much data can be sent or the maximum value
* of id. Use the @a ipm_max_data_size_get and @a ipm_max_id_val_get routines
* to determine them.
*
* The @a size parameter is used only on the sending side to determine
* the amount of data to put in the message registers. It is not passed along
* to the receiving side. The upper-level protocol dictates the amount of
* data read back.
*
* @param ipmdev Driver instance
* @param wait If nonzero, busy-wait for remote to consume the message. The
* message is considered consumed once the remote interrupt handler
* finishes. If there is deferred processing on the remote side,
* or you would like to queue outgoing messages and wait on an
* event/semaphore, you can implement that in a high-level driver
* @param id Message identifier. Values are constrained by
* @a ipm_max_data_size_get since many boards only allow for a
* subset of bits in a 32-bit register to store the ID.
* @param data Pointer to the data sent in the message.
* @param size Size of the data.
*
* @retval -EBUSY If the remote hasn't yet read the last data sent.
* @retval -EMSGSIZE If the supplied data size is unsupported by the driver.
* @retval -EINVAL If there was a bad parameter, such as: too-large id value.
* or the device isn't an outbound IPM channel.
* @retval 0 On success.
*/
__syscall int ipm_send(const struct device *ipmdev, int wait, uint32_t id,
const void *data, int size);
static inline int z_impl_ipm_send(const struct device *ipmdev, int wait,
uint32_t id,
const void *data, int size)
{
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
return api->send(ipmdev, wait, id, data, size);
}
/**
* @brief Register a callback function for incoming messages.
*
* @param ipmdev Driver instance pointer.
* @param cb Callback function to execute on incoming message interrupts.
* @param user_data Application-specific data pointer which will be passed
* to the callback function when executed.
*/
static inline void ipm_register_callback(const struct device *ipmdev,
ipm_callback_t cb, void *user_data)
{
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
api->register_callback(ipmdev, cb, user_data);
}
/**
* @brief Return the maximum number of bytes possible in an outbound message.
*
* IPM implementations vary on the amount of data that can be sent in a
* single message since the data payload is typically stored in registers.
*
* @param ipmdev Driver instance pointer.
*
* @return Maximum possible size of a message in bytes.
*/
__syscall int ipm_max_data_size_get(const struct device *ipmdev);
static inline int z_impl_ipm_max_data_size_get(const struct device *ipmdev)
{
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
return api->max_data_size_get(ipmdev);
}
/**
* @brief Return the maximum id value possible in an outbound message.
*
* Many IPM implementations store the message's ID in a register with
* some bits reserved for other uses.
*
* @param ipmdev Driver instance pointer.
*
* @return Maximum possible value of a message ID.
*/
__syscall uint32_t ipm_max_id_val_get(const struct device *ipmdev);
static inline uint32_t z_impl_ipm_max_id_val_get(const struct device *ipmdev)
{
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
return api->max_id_val_get(ipmdev);
}
/**
* @brief Enable interrupts and callbacks for inbound channels.
*
* @param ipmdev Driver instance pointer.
* @param enable Set to 0 to disable and to nonzero to enable.
*
* @retval 0 On success.
* @retval -EINVAL If it isn't an inbound channel.
*/
__syscall int ipm_set_enabled(const struct device *ipmdev, int enable);
static inline int z_impl_ipm_set_enabled(const struct device *ipmdev,
int enable)
{
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
return api->set_enabled(ipmdev, enable);
}
/**
* @brief Signal asynchronous command completion
*
* Some IPM backends have an ability to deliver a command
* asynchronously. The callback will be invoked in interrupt context,
* but the message (including the provided data pointer) will stay
* "active" and unacknowledged until later code (presumably in thread
* mode) calls ipm_complete().
*
* This function is, obviously, a noop on drivers without async
* support.
*
* @param ipmdev Driver instance pointer.
*/
__syscall void ipm_complete(const struct device *ipmdev);
static inline void z_impl_ipm_complete(const struct device *ipmdev)
{
#ifdef CONFIG_IPM_CALLBACK_ASYNC
const struct ipm_driver_api *api =
(const struct ipm_driver_api *)ipmdev->api;
if (api->complete != NULL) {
api->complete(ipmdev);
}
#endif
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#include <zephyr/syscalls/ipm.h>
#endif /* ZEPHYR_INCLUDE_DRIVERS_IPM_H_ */