[PATCH 1/7] firmware: add support for RPMI
Charles Perry
charles.perry at microchip.com
Mon Jul 6 16:52:40 CEST 2026
On Sat, Jun 27, 2026 at 01:09:33AM +0000, Yao Zi wrote:
> On Fri, Jun 26, 2026 at 01:15:42PM -0700, Charles Perry wrote:
> > RISC-V Platform Management Interface (RPMI) defines an OS-agnostic
> > protocol for communication between an Application Processor (AP) and a
> > platform microcontroller (PuC) [1]
> >
> > Add UCLASS_RPMI to abstract the implementation details of an RPMI
> > transport layer. A transport driver should implement the struct
> > rpmi_transport_ops callback interface while an RPMI client driver should
> > use struct rpmi_chan and the rpmi_* API:
> >
> > * rpmi_get_by_index()
> > * rpmi_open()
> > * rpmi_close()
> > * rpmi_get_attr()
> > * rpmi_send_with_resp()
> > * rpmi_send_posted()
> >
> > The most important part of the API is rpmi_send_with_resp() and
> > rpmi_send_posted() which is used to send a message and possibly receive
> > a response from the firmware.
> >
> > rpmi_get_attr() can be used to retrieve attributes of the channel like
> > the implementation ID or the maximum message size. This is to retrieve
> > information that lives outside of the service group of the rpmi_chan,
> > either in the "base service group" or in the transport layer itself.
> >
> > rpmi_get_by_index() can be used to initialize a struct rpmi_chan using
> > info from the device tree.
> >
> > rpmi_open() and rpmi_close() must be called once at initialization and
> > deinitialization by clients to let the transport layer do some stateful
> > things if needed.
> >
> > A helper function is also added: rpmi_check_versions() which is just a
> > wrapper around rpmi_get_attr() to do some basic version checking that
> > all clients should perform.
> >
> > [1]: https://github.com/riscv-non-isa/riscv-rpmi
> >
> > Signed-off-by: Charles Perry <charles.perry at microchip.com>
> > ---
> > MAINTAINERS | 6 ++
> > drivers/firmware/Kconfig | 1 +
> > drivers/firmware/Makefile | 1 +
> > drivers/firmware/rpmi/Kconfig | 9 ++
> > drivers/firmware/rpmi/Makefile | 1 +
> > drivers/firmware/rpmi/rpmi-uclass.c | 138 ++++++++++++++++++++++++
> > include/dm/uclass-id.h | 1 +
> > include/rpmi-uclass.h | 79 ++++++++++++++
> > include/rpmi.h | 159 ++++++++++++++++++++++++++++
> > include/rpmi_proto.h | 63 +++++++++++
> > 10 files changed, 458 insertions(+)
> > create mode 100644 drivers/firmware/rpmi/Kconfig
> > create mode 100644 drivers/firmware/rpmi/Makefile
> > create mode 100644 drivers/firmware/rpmi/rpmi-uclass.c
> > create mode 100644 include/rpmi-uclass.h
> > create mode 100644 include/rpmi.h
> > create mode 100644 include/rpmi_proto.h
>
> ...
>
> > diff --git a/drivers/firmware/rpmi/rpmi-uclass.c b/drivers/firmware/rpmi/rpmi-uclass.c
> > new file mode 100644
> > index 000000000000..b725f9e59441
> > --- /dev/null
> > +++ b/drivers/firmware/rpmi/rpmi-uclass.c
> > @@ -0,0 +1,138 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2026 Microchip Technology Inc. All rights reserved.
> > + */
> > +
> > +#define LOG_CATEGORY UCLASS_RPMI
> > +
> > +#include <dm.h>
> > +#include <log.h>
> > +#include <rpmi-uclass.h>
> > +#include <dm/device_compat.h>
>
> Should we sort the headers? This applies to rest of the series, too.
Ack.
>
> ...
>
> > +int rpmi_check_versions(struct rpmi_chan *chan, u32 min_proto_version,
> > + u32 servicegroup_id_expect,
> > + u32 min_servicegroup_version)
> > +{
> > + u32 proto_version, servicegroup_id, servicegroup_version;
> > + int ret;
> > +
> > + ret = rpmi_get_attr(chan, RPMI_ATTR_SPEC_VERSION, &proto_version);
> > + if (ret)
> > + return ret;
> > +
> > + if (proto_version < min_proto_version) {
> > + dev_err(chan->dev, "protocol version mismatch\n");
>
> The error is caused by a "too old" protocol version instead of a
> "mismatched" one, shouldn't we be precise here?
>
> Furthermore, it would be good to print the the expected and implemented
> versions as well to ease debugging. debug() could be used so we don't
> get the binary size increased in a normal build. So do the
> servicegroup_id and servicegroup_version's case.
Ack for everything.
>
> > + return -EINVAL;
> > + }
> > +
> > + ret = rpmi_get_attr(chan, RPMI_ATTR_SERVICEGROUP_ID, &servicegroup_id);
> > + if (ret)
> > + return ret;
> > +
> > + if (servicegroup_id != servicegroup_id_expect) {
> > + dev_err(chan->dev, "service group match fail\n");
> > + return -EINVAL;
> > + }
> > +
> > + ret = rpmi_get_attr(chan, RPMI_ATTR_SERVICEGROUP_VERSION,
> > + &servicegroup_version);
> > + if (ret)
> > + return ret;
> > +
> > + if (servicegroup_version < min_servicegroup_version) {
> > + dev_err(chan->dev, "service group version mismatch\n");
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
>
> ...
>
> > diff --git a/include/rpmi.h b/include/rpmi.h
> > new file mode 100644
> > index 000000000000..de802026b31a
> > --- /dev/null
> > +++ b/include/rpmi.h
>
> ...
>
> > +static inline int rpmi_to_linux_error(int rpmi_error)
> > +{
> > + switch (rpmi_error) {
> > + case RPMI_SUCCESS:
> > + return 0;
> > + case RPMI_ERR_INVALID_PARAM:
> > + case RPMI_ERR_BAD_RANGE:
> > + case RPMI_ERR_INVALID_STATE:
> > + return -EINVAL;
> > + case RPMI_ERR_DENIED:
> > + return -EPERM;
> > + case RPMI_ERR_INVALID_ADDR:
> > + case RPMI_ERR_HW_FAULT:
> > + return -EFAULT;
>
> RPMI_ERR_HW_FAULT means "failed due to hardware fault" according to
> RPMI specification, does it really count as "-EFAULT" which is
> "bad address"?
This is taken as-is from Linux [1]. So unless there's a good reason to do
things differently, I suggest we keep it as-is.
[1]: https://elixir.bootlin.com/linux/v7.1.2/source/include/linux/mailbox/riscv-rpmi-message.h#L62
Thanks,
Charles
More information about the U-Boot
mailing list