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