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