Introduce core support for ARM's SCMI (System Control and Management Interface). This includes: * shared memory (SHMEM) driver. This consists of a suite of functions used to interact with the shared memory area. * shared memory and doorbell-based transport layer driver. Data is passed between platform and agent via shared memory. Signaling is done using polling (PRE_KERNEL) and doorbells (POST_KERNEL). This makes use of Zephyr MBOX API (for signaling purposes) and the SHMEM driver (for polling and data transfer). * core driver - acts as glue between transport and protocol layers. Provides synchronized access to transport layer channels and channel assignment/initialization. * infrastructure for creating SCMI protocols This is based on ARM's SCMI Platform Design Document: DEN0056E. Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
118 lines
4.1 KiB
C
118 lines
4.1 KiB
C
/*
|
|
* Copyright 2024 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_
|
|
#define _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_
|
|
|
|
#include <zephyr/drivers/firmware/scmi/transport.h>
|
|
#include <zephyr/drivers/firmware/scmi/util.h>
|
|
#include <zephyr/drivers/firmware/scmi/shmem.h>
|
|
#include <zephyr/drivers/mbox.h>
|
|
#include <zephyr/kernel.h>
|
|
|
|
#define DT_DRV_COMPAT arm_scmi
|
|
|
|
/* get a `struct device` for a protocol's shared memory area */
|
|
#define _SCMI_MBOX_SHMEM_BY_IDX(node_id, idx) \
|
|
COND_CODE_1(DT_PROP_HAS_IDX(node_id, shmem, idx), \
|
|
(DEVICE_DT_GET(DT_PROP_BY_IDX(node_id, shmem, idx))), \
|
|
(NULL))
|
|
|
|
/* get the name of mailbox channel's private data */
|
|
#define _SCMI_MBOX_CHAN_NAME(proto, idx)\
|
|
CONCAT(SCMI_TRANSPORT_CHAN_NAME(proto, idx), _, priv)
|
|
|
|
/* fetch a mailbox channel's doorbell */
|
|
#define _SCMI_MBOX_CHAN_DBELL(node_id, name) \
|
|
COND_CODE_1(DT_PROP_HAS_NAME(node_id, mboxes, name), \
|
|
(MBOX_DT_SPEC_GET(node_id, name)), \
|
|
({ }))
|
|
|
|
/* define private data for a protocol TX channel */
|
|
#define _SCMI_MBOX_CHAN_DEFINE_PRIV_TX(node_id, proto) \
|
|
static struct scmi_mbox_channel _SCMI_MBOX_CHAN_NAME(proto, 0) =\
|
|
{ \
|
|
.shmem = _SCMI_MBOX_SHMEM_BY_IDX(node_id, 0), \
|
|
.tx = _SCMI_MBOX_CHAN_DBELL(node_id, tx), \
|
|
.tx_reply = _SCMI_MBOX_CHAN_DBELL(node_id, tx_reply), \
|
|
}
|
|
|
|
/*
|
|
* Define a mailbox channel. This does two things:
|
|
* 1) Define the mandatory `struct scmi_channel` structure
|
|
* 2) Define the mailbox-specific private data for said
|
|
* channel (i.e: a struct scmi_mbox_channel)
|
|
*/
|
|
#define _SCMI_MBOX_CHAN_DEFINE(node_id, proto, idx) \
|
|
_SCMI_MBOX_CHAN_DEFINE_PRIV_TX(node_id, proto); \
|
|
DT_SCMI_TRANSPORT_CHAN_DEFINE(node_id, idx, proto, \
|
|
&(_SCMI_MBOX_CHAN_NAME(proto, idx))); \
|
|
|
|
/*
|
|
* Optionally define a mailbox channel for a protocol. This is optional
|
|
* because a protocol might not have a dedicated channel.
|
|
*/
|
|
#define _SCMI_MBOX_CHAN_DEFINE_OPTIONAL(node_id, proto, idx) \
|
|
COND_CODE_1(DT_PROP_HAS_IDX(node_id, shmem, idx), \
|
|
(_SCMI_MBOX_CHAN_DEFINE(node_id, proto, idx)), \
|
|
())
|
|
|
|
/* define a TX channel for a protocol node. This is preferred over
|
|
* _SCMI_MBOX_CHAN_DEFINE_OPTIONAL() since support for RX channels
|
|
* might be added later on. This macro is supposed to also define
|
|
* the RX channel
|
|
*/
|
|
#define SCMI_MBOX_PROTO_CHAN_DEFINE(node_id)\
|
|
_SCMI_MBOX_CHAN_DEFINE_OPTIONAL(node_id, DT_REG_ADDR(node_id), 0)
|
|
|
|
/* define and validate base protocol TX channel */
|
|
#define DT_INST_SCMI_MBOX_BASE_CHAN_DEFINE(inst) \
|
|
BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) != 1 || \
|
|
(DT_INST_PROP_HAS_IDX(inst, shmem, 0) && \
|
|
DT_INST_PROP_HAS_NAME(inst, mboxes, tx)), \
|
|
"bad bidirectional channel description"); \
|
|
\
|
|
BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) != 2 || \
|
|
(DT_INST_PROP_HAS_NAME(inst, mboxes, tx) && \
|
|
DT_INST_PROP_HAS_NAME(inst, mboxes, tx_reply)), \
|
|
"bad unidirectional channel description"); \
|
|
\
|
|
BUILD_ASSERT(DT_INST_PROP_LEN(inst, shmem) == 1, \
|
|
"bad SHMEM count"); \
|
|
\
|
|
BUILD_ASSERT(DT_INST_PROP_LEN(inst, mboxes) <= 2, \
|
|
"bad mbox count"); \
|
|
\
|
|
_SCMI_MBOX_CHAN_DEFINE(DT_INST(inst, DT_DRV_COMPAT), SCMI_PROTOCOL_BASE, 0)
|
|
|
|
/*
|
|
* Define the mailbox-based transport layer. What this does is:
|
|
*
|
|
* 1) Goes through all protocol nodes (children of the `scmi` node)
|
|
* and creates a `struct scmi_channel` and its associated
|
|
* `struct scmi_mbox_channel` if the protocol has a dedicated channel.
|
|
*
|
|
* 2) Creates aforementioned structures for the base protocol
|
|
* (identified by the `scmi` node)
|
|
*
|
|
* 3) "registers" the driver via `DT_INST_SCMI_TRANSPORT_DEFINE()`.
|
|
*/
|
|
#define DT_INST_SCMI_MAILBOX_DEFINE(inst, level, prio, api) \
|
|
DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, SCMI_MBOX_PROTO_CHAN_DEFINE) \
|
|
DT_INST_SCMI_MBOX_BASE_CHAN_DEFINE(inst) \
|
|
DT_INST_SCMI_TRANSPORT_DEFINE(inst, NULL, NULL, NULL, level, prio, api)
|
|
|
|
struct scmi_mbox_channel {
|
|
/* SHMEM area bound to the channel */
|
|
const struct device *shmem;
|
|
/* TX dbell */
|
|
struct mbox_dt_spec tx;
|
|
/* TX reply dbell */
|
|
struct mbox_dt_spec tx_reply;
|
|
};
|
|
|
|
#endif /* _ZEPHYR_DRIVERS_FIRMWARE_SCMI_MAILBOX_H_ */
|