[PATCH 4/7] drivers: clk: add support for RPMI clocks

Charles Perry charles.perry at microchip.com
Mon Jul 6 17:14:07 CEST 2026


On Sat, Jun 27, 2026 at 01:47:17AM +0000, Yao Zi wrote:
> On Fri, Jun 26, 2026 at 01:15:45PM -0700, Charles Perry wrote:
> > The RISC-V Platform Management Interface (RPMI) defines a service group
> > for control and monitoring of clocks [1]. This can be exposed as a
> > UCLASS_CLK driver.
> > 
> > [1]: https://github.com/riscv-non-isa/riscv-rpmi (chapter 4.8)
> > 
> > Signed-off-by: Charles Perry <charles.perry at microchip.com>
> > ---
> >  MAINTAINERS            |   1 +
> >  drivers/clk/Kconfig    |   7 +
> >  drivers/clk/Makefile   |   1 +
> >  drivers/clk/clk_rpmi.c | 346 +++++++++++++++++++++++++++++++++++++++++
> >  include/rpmi_proto.h   |  39 +++++
> >  5 files changed, 394 insertions(+)
> >  create mode 100644 drivers/clk/clk_rpmi.c
> 
> ...
> 
> > diff --git a/drivers/clk/clk_rpmi.c b/drivers/clk/clk_rpmi.c
> > new file mode 100644
> > index 000000000000..d2efb057600b
> > --- /dev/null
> > +++ b/drivers/clk/clk_rpmi.c
> > @@ -0,0 +1,346 @@
> 
> ...
> 
> > +struct rpmi_clk_def {
> > +	u32 num_rates;
> > +	u32 transition_latency;
> 
> rpmi_clk_def.transition_latency only gets assigned in
> rpmi_clk_get_attrs() and never used. Since U-Boot's clock infrastructure
> doesn't care about it at all, maybe we could drop the field?

Ack.

> 
> > +	enum rpmi_clock_type type;
> > +	char name[RPMI_CLK_NAME_LEN + 1];
> > +};
> 
> ...
> 
> > +static int _rpmi_clk_enable_disable(struct rpmi_clk_priv *priv, u32 clkid,
> > +				    bool ena)
> > +{
> > +	struct rpmi_set_config_tx tx = {
> > +		.clkid = cpu_to_le32(clkid),
> > +		.config = cpu_to_le32(ena ? RPMI_CLK_STATE_ENABLED :
> > +					    RPMI_CLK_STATE_DISABLED),
> > +	};
> > +	__le32 rx;
> > +	int ret, status;
> > +
> > +	ret = rpmi_send_with_resp(&priv->chan, RPMI_CLK_SRV_SET_CONFIG, &tx,
> > +				  sizeof(tx), &rx, sizeof(rx), NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	status = le32_to_cpu(rx);
> > +	if (status)
> > +		return rpmi_to_linux_error(status);
> > +
> > +	return 0;
> 
> Please return rpmi_to_linux_error(status) and drop the if above.

Ack.

> 
> > +}
> > +
> > +static ulong _rpmi_clk_get_rate(struct rpmi_clk_priv *priv, u32 clkid)
> > +{
> > +	__le32 tx = cpu_to_le32(clkid);
> > +	struct rpmi_get_rate_rx rx;
> > +	int ret, status;
> > +
> > +	ret = rpmi_send_with_resp(&priv->chan, RPMI_CLK_SRV_GET_RATE, &tx,
> > +				  sizeof(tx), &rx, sizeof(rx), NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	status = le32_to_cpu(rx.status);
> > +	if (status)
> > +		return rpmi_to_linux_error(status);
> > +
> > +	return (((u64)(le32_to_cpu(rx.hi)) << 32) | (u32)(le32_to_cpu(rx.lo)));
> > +}
> 
> ...
> 
> > +static int _rpmi_clk_set_rate(struct rpmi_clk_priv *priv, u32 clkid,
> > +			      unsigned long rate)
> 
> This function is declared to return int, but...
> 
> > +{
> > +	struct rpmi_set_rate_tx tx = {
> > +		.clkid = cpu_to_le32(clkid),
> > +		.flags = 0,
> > +		.lo = cpu_to_le32(lower_32_bits(rate)),
> > +		.hi = cpu_to_le32(upper_32_bits(rate)),
> > +	};
> > +	__le32 rx;
> > +	int ret, status;
> > +
> > +	ret = rpmi_send_with_resp(&priv->chan, RPMI_CLK_SRV_SET_RATE, &tx,
> > +				  sizeof(tx), &rx, sizeof(rx), NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	status = le32_to_cpu(rx);
> > +	if (status)
> > +		return rpmi_to_linux_error(status);
> > +
> > +	return _rpmi_clk_get_rate(priv, clkid);
> 
> _rpmi_clk_get_rate() returns ulong. This unnecessarily truncates the
> rate on 64bit platform when it's above approximately 2.1GHz.

Good catch.

I'll keep the return code as int here and put the call to
_rpmi_clk_get_rate() inside rpmi_clk_set_rate() instead.

Thanks,
Charles


More information about the U-Boot mailing list