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 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 31 static int scmi_clk_enable(struct clk *clk) 32 { 33 return scmi_clk_gate(clk, 1); 34 } 35 36 static int scmi_clk_disable(struct clk *clk) 37 { 38 return scmi_clk_gate(clk, 0); 39 } 40 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 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