1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/firmware/scmi/clk.h>
8 #include <string.h>
9
10 /* TODO: if extended attributes are supported this should be moved
11 * to the header file so that users will have access to it.
12 */
13 #define SCMI_CLK_CONFIG_EA_MASK GENMASK(23, 16)
14
15 struct scmi_clock_attributes_reply {
16 int32_t status;
17 uint32_t attributes;
18 };
19
20 struct scmi_clock_rate_set_reply {
21 int32_t status;
22 uint32_t rate[2];
23 };
24
scmi_clock_rate_get(struct scmi_protocol * proto,uint32_t clk_id,uint32_t * rate)25 int scmi_clock_rate_get(struct scmi_protocol *proto,
26 uint32_t clk_id, uint32_t *rate)
27 {
28 struct scmi_message msg, reply;
29 int ret;
30 struct scmi_clock_rate_set_reply reply_buffer;
31
32 /* sanity checks */
33 if (!proto || !rate) {
34 return -EINVAL;
35 }
36
37 if (proto->id != SCMI_PROTOCOL_CLOCK) {
38 return -EINVAL;
39 }
40
41 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_RATE_GET,
42 SCMI_COMMAND, proto->id, 0x0);
43 msg.len = sizeof(clk_id);
44 msg.content = &clk_id;
45
46 reply.hdr = msg.hdr;
47 reply.len = sizeof(reply_buffer);
48 reply.content = &reply_buffer;
49
50 ret = scmi_send_message(proto, &msg, &reply);
51 if (ret < 0) {
52 return ret;
53 }
54
55 if (reply_buffer.status != SCMI_SUCCESS) {
56 return scmi_status_to_errno(reply_buffer.status);
57 }
58
59 *rate = reply_buffer.rate[0];
60
61 return 0;
62 }
63
scmi_clock_config_set(struct scmi_protocol * proto,struct scmi_clock_config * cfg)64 int scmi_clock_config_set(struct scmi_protocol *proto,
65 struct scmi_clock_config *cfg)
66 {
67 struct scmi_message msg, reply;
68 int status, ret;
69
70 /* sanity checks */
71 if (!proto || !cfg) {
72 return -EINVAL;
73 }
74
75 if (proto->id != SCMI_PROTOCOL_CLOCK) {
76 return -EINVAL;
77 }
78
79 /* extended attributes currently not supported */
80 if (cfg->attributes & SCMI_CLK_CONFIG_EA_MASK) {
81 return -ENOTSUP;
82 }
83
84 /* invalid because extended attributes are not supported */
85 if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 3) {
86 return -ENOTSUP;
87 }
88
89 /* this is a reserved value */
90 if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 2) {
91 return -EINVAL;
92 }
93
94 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_CONFIG_SET,
95 SCMI_COMMAND, proto->id, 0x0);
96 msg.len = sizeof(*cfg);
97 msg.content = cfg;
98
99 reply.hdr = msg.hdr;
100 reply.len = sizeof(status);
101 reply.content = &status;
102
103 ret = scmi_send_message(proto, &msg, &reply);
104 if (ret < 0) {
105 return ret;
106 }
107
108 if (status != SCMI_SUCCESS) {
109 return scmi_status_to_errno(status);
110 }
111
112 return 0;
113 }
114
scmi_clock_protocol_attributes(struct scmi_protocol * proto,uint32_t * attributes)115 int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attributes)
116 {
117 struct scmi_message msg, reply;
118 struct scmi_clock_attributes_reply reply_buffer;
119 int ret;
120
121 /* sanity checks */
122 if (!proto || !attributes) {
123 return -EINVAL;
124 }
125
126 if (proto->id != SCMI_PROTOCOL_CLOCK) {
127 return -EINVAL;
128 }
129
130 msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_PROTOCOL_ATTRIBUTES,
131 SCMI_COMMAND, proto->id, 0x0);
132 /* command has no parameters */
133 msg.len = 0x0;
134 msg.content = NULL;
135
136 reply.hdr = msg.hdr;
137 reply.len = sizeof(reply_buffer);
138 reply.content = &reply_buffer;
139
140 ret = scmi_send_message(proto, &msg, &reply);
141 if (ret < 0) {
142 return ret;
143 }
144
145 if (reply_buffer.status != 0) {
146 return scmi_status_to_errno(reply_buffer.status);
147 }
148
149 *attributes = reply_buffer.attributes;
150
151 return 0;
152 }
153