u-boot/drivers/clk/clk_scmi.c
Etienne Carriere 6038884483 clk: add clock driver for SCMI agents
This change introduces a clock driver for SCMI agent devices. When
SCMI agent and SCMI clock drivers are enabled, SCMI agent binds a
clock device for each SCMI clock protocol devices enabled in the FDT.

SCMI clock driver is embedded upon CONFIG_CLK_SCMI=y. If enabled,
CONFIG_SCMI_AGENT is also enabled.

SCMI Clock protocol is defined in the SCMI specification [1].

Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Cc: Lukasz Majewski <lukma@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
2020-09-30 11:55:23 -04:00

99 lines
2.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <scmi_agent.h>
#include <scmi_protocols.h>
#include <asm/types.h>
static int scmi_clk_gate(struct clk *clk, int enable)
{
struct scmi_clk_state_in in = {
.clock_id = clk->id,
.attributes = enable,
};
struct scmi_clk_state_out out;
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
SCMI_CLOCK_CONFIG_SET,
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev->parent, &msg);
if (ret)
return ret;
return scmi_to_linux_errno(out.status);
}
static int scmi_clk_enable(struct clk *clk)
{
return scmi_clk_gate(clk, 1);
}
static int scmi_clk_disable(struct clk *clk)
{
return scmi_clk_gate(clk, 0);
}
static ulong scmi_clk_get_rate(struct clk *clk)
{
struct scmi_clk_rate_get_in in = {
.clock_id = clk->id,
};
struct scmi_clk_rate_get_out out;
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
SCMI_CLOCK_RATE_GET,
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev->parent, &msg);
if (ret < 0)
return ret;
ret = scmi_to_linux_errno(out.status);
if (ret < 0)
return ret;
return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
}
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
{
struct scmi_clk_rate_set_in in = {
.clock_id = clk->id,
.flags = SCMI_CLK_RATE_ROUND_CLOSEST,
.rate_lsb = (u32)rate,
.rate_msb = (u32)((u64)rate >> 32),
};
struct scmi_clk_rate_set_out out;
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
SCMI_CLOCK_RATE_SET,
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev->parent, &msg);
if (ret < 0)
return ret;
ret = scmi_to_linux_errno(out.status);
if (ret < 0)
return ret;
return scmi_clk_get_rate(clk);
}
static const struct clk_ops scmi_clk_ops = {
.enable = scmi_clk_enable,
.disable = scmi_clk_disable,
.get_rate = scmi_clk_get_rate,
.set_rate = scmi_clk_set_rate,
};
U_BOOT_DRIVER(scmi_clock) = {
.name = "scmi_clk",
.id = UCLASS_CLK,
.ops = &scmi_clk_ops,
};