diff options
Diffstat (limited to 'roms/u-boot/drivers/clk/clk_scmi.c')
-rw-r--r-- | roms/u-boot/drivers/clk/clk_scmi.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/clk/clk_scmi.c b/roms/u-boot/drivers/clk/clk_scmi.c new file mode 100644 index 000000000..93a481950 --- /dev/null +++ b/roms/u-boot/drivers/clk/clk_scmi.c @@ -0,0 +1,99 @@ +// 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, +}; |