1 // 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
scmi_clk_gate(struct clk * clk,int enable)12 static 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
scmi_clk_enable(struct clk * clk)31 static int scmi_clk_enable(struct clk *clk)
32 {
33 return scmi_clk_gate(clk, 1);
34 }
35
scmi_clk_disable(struct clk * clk)36 static int scmi_clk_disable(struct clk *clk)
37 {
38 return scmi_clk_gate(clk, 0);
39 }
40
scmi_clk_get_rate(struct clk * clk)41 static 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
scmi_clk_set_rate(struct clk * clk,ulong rate)63 static 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
88 static 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
95 U_BOOT_DRIVER(scmi_clock) = {
96 .name = "scmi_clk",
97 .id = UCLASS_CLK,
98 .ops = &scmi_clk_ops,
99 };
100