blob: 93a4819501cac1ed3a9c9dd2dd4d409c3ff766e6 [file] [log] [blame]
Etienne Carriere78928e12020-09-09 18:44:04 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019-2020 Linaro Limited
4 */
5#include <common.h>
6#include <clk-uclass.h>
7#include <dm.h>
8#include <scmi_agent.h>
9#include <scmi_protocols.h>
10#include <asm/types.h>
11
12static int scmi_clk_gate(struct clk *clk, int enable)
13{
14 struct scmi_clk_state_in in = {
15 .clock_id = clk->id,
16 .attributes = enable,
17 };
18 struct scmi_clk_state_out out;
19 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
20 SCMI_CLOCK_CONFIG_SET,
21 in, out);
22 int ret;
23
24 ret = devm_scmi_process_msg(clk->dev->parent, &msg);
25 if (ret)
26 return ret;
27
28 return scmi_to_linux_errno(out.status);
29}
30
31static int scmi_clk_enable(struct clk *clk)
32{
33 return scmi_clk_gate(clk, 1);
34}
35
36static int scmi_clk_disable(struct clk *clk)
37{
38 return scmi_clk_gate(clk, 0);
39}
40
41static ulong scmi_clk_get_rate(struct clk *clk)
42{
43 struct scmi_clk_rate_get_in in = {
44 .clock_id = clk->id,
45 };
46 struct scmi_clk_rate_get_out out;
47 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
48 SCMI_CLOCK_RATE_GET,
49 in, out);
50 int ret;
51
52 ret = devm_scmi_process_msg(clk->dev->parent, &msg);
53 if (ret < 0)
54 return ret;
55
56 ret = scmi_to_linux_errno(out.status);
57 if (ret < 0)
58 return ret;
59
60 return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
61}
62
63static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
64{
65 struct scmi_clk_rate_set_in in = {
66 .clock_id = clk->id,
67 .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
68 .rate_lsb = (u32)rate,
69 .rate_msb = (u32)((u64)rate >> 32),
70 };
71 struct scmi_clk_rate_set_out out;
72 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
73 SCMI_CLOCK_RATE_SET,
74 in, out);
75 int ret;
76
77 ret = devm_scmi_process_msg(clk->dev->parent, &msg);
78 if (ret < 0)
79 return ret;
80
81 ret = scmi_to_linux_errno(out.status);
82 if (ret < 0)
83 return ret;
84
85 return scmi_clk_get_rate(clk);
86}
87
88static const struct clk_ops scmi_clk_ops = {
89 .enable = scmi_clk_enable,
90 .disable = scmi_clk_disable,
91 .get_rate = scmi_clk_get_rate,
92 .set_rate = scmi_clk_set_rate,
93};
94
95U_BOOT_DRIVER(scmi_clock) = {
96 .name = "scmi_clk",
97 .id = UCLASS_CLK,
98 .ops = &scmi_clk_ops,
99};