clock.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // SPDX-License-Identifier: BSD-3-Clause
  2. /*
  3. * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
  4. * Copyright (c) 2019-2020, Linaro Limited
  5. */
  6. #include <cdefs.h>
  7. #include <string.h>
  8. #include <drivers/scmi-msg.h>
  9. #include <drivers/scmi.h>
  10. #include <lib/utils_def.h>
  11. #include "common.h"
  12. #pragma weak plat_scmi_clock_count
  13. #pragma weak plat_scmi_clock_get_name
  14. #pragma weak plat_scmi_clock_rates_array
  15. #pragma weak plat_scmi_clock_rates_by_step
  16. #pragma weak plat_scmi_clock_get_rate
  17. #pragma weak plat_scmi_clock_set_rate
  18. #pragma weak plat_scmi_clock_get_state
  19. #pragma weak plat_scmi_clock_set_state
  20. static bool message_id_is_supported(unsigned int message_id);
  21. size_t plat_scmi_clock_count(unsigned int agent_id __unused)
  22. {
  23. return 0U;
  24. }
  25. const char *plat_scmi_clock_get_name(unsigned int agent_id __unused,
  26. unsigned int scmi_id __unused)
  27. {
  28. return NULL;
  29. }
  30. int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused,
  31. unsigned int scmi_id __unused,
  32. unsigned long *rates __unused,
  33. size_t *nb_elts __unused,
  34. uint32_t start_idx __unused)
  35. {
  36. return SCMI_NOT_SUPPORTED;
  37. }
  38. int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
  39. unsigned int scmi_id __unused,
  40. unsigned long *steps __unused)
  41. {
  42. return SCMI_NOT_SUPPORTED;
  43. }
  44. unsigned long plat_scmi_clock_get_rate(unsigned int agent_id __unused,
  45. unsigned int scmi_id __unused)
  46. {
  47. return 0U;
  48. }
  49. int32_t plat_scmi_clock_set_rate(unsigned int agent_id __unused,
  50. unsigned int scmi_id __unused,
  51. unsigned long rate __unused)
  52. {
  53. return SCMI_NOT_SUPPORTED;
  54. }
  55. int32_t plat_scmi_clock_get_state(unsigned int agent_id __unused,
  56. unsigned int scmi_id __unused)
  57. {
  58. return SCMI_NOT_SUPPORTED;
  59. }
  60. int32_t plat_scmi_clock_set_state(unsigned int agent_id __unused,
  61. unsigned int scmi_id __unused,
  62. bool enable_not_disable __unused)
  63. {
  64. return SCMI_NOT_SUPPORTED;
  65. }
  66. static void report_version(struct scmi_msg *msg)
  67. {
  68. struct scmi_protocol_version_p2a return_values = {
  69. .status = SCMI_SUCCESS,
  70. .version = SCMI_PROTOCOL_VERSION_CLOCK,
  71. };
  72. if (msg->in_size != 0) {
  73. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  74. return;
  75. }
  76. scmi_write_response(msg, &return_values, sizeof(return_values));
  77. }
  78. static void report_attributes(struct scmi_msg *msg)
  79. {
  80. size_t agent_count = plat_scmi_clock_count(msg->agent_id);
  81. struct scmi_protocol_attributes_p2a return_values = {
  82. .status = SCMI_SUCCESS,
  83. .attributes = SCMI_CLOCK_PROTOCOL_ATTRIBUTES(1U, agent_count),
  84. };
  85. if (msg->in_size != 0) {
  86. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  87. return;
  88. }
  89. scmi_write_response(msg, &return_values, sizeof(return_values));
  90. }
  91. static void report_message_attributes(struct scmi_msg *msg)
  92. {
  93. struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
  94. struct scmi_protocol_message_attributes_p2a return_values = {
  95. .status = SCMI_SUCCESS,
  96. /* For this protocol, attributes shall be zero */
  97. .attributes = 0U,
  98. };
  99. if (msg->in_size != sizeof(*in_args)) {
  100. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  101. return;
  102. }
  103. if (!message_id_is_supported(in_args->message_id)) {
  104. scmi_status_response(msg, SCMI_NOT_FOUND);
  105. return;
  106. }
  107. scmi_write_response(msg, &return_values, sizeof(return_values));
  108. }
  109. static void scmi_clock_attributes(struct scmi_msg *msg)
  110. {
  111. const struct scmi_clock_attributes_a2p *in_args = (void *)msg->in;
  112. struct scmi_clock_attributes_p2a return_values = {
  113. .status = SCMI_SUCCESS,
  114. };
  115. const char *name = NULL;
  116. unsigned int clock_id = 0U;
  117. if (msg->in_size != sizeof(*in_args)) {
  118. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  119. return;
  120. }
  121. clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
  122. if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
  123. scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
  124. return;
  125. }
  126. name = plat_scmi_clock_get_name(msg->agent_id, clock_id);
  127. if (name == NULL) {
  128. scmi_status_response(msg, SCMI_NOT_FOUND);
  129. return;
  130. }
  131. COPY_NAME_IDENTIFIER(return_values.clock_name, name);
  132. return_values.attributes = plat_scmi_clock_get_state(msg->agent_id,
  133. clock_id);
  134. scmi_write_response(msg, &return_values, sizeof(return_values));
  135. }
  136. static void scmi_clock_rate_get(struct scmi_msg *msg)
  137. {
  138. const struct scmi_clock_rate_get_a2p *in_args = (void *)msg->in;
  139. unsigned long rate = 0U;
  140. struct scmi_clock_rate_get_p2a return_values = {
  141. .status = SCMI_SUCCESS,
  142. };
  143. unsigned int clock_id = 0U;
  144. if (msg->in_size != sizeof(*in_args)) {
  145. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  146. return;
  147. }
  148. clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
  149. if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
  150. scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
  151. return;
  152. }
  153. rate = plat_scmi_clock_get_rate(msg->agent_id, clock_id);
  154. return_values.rate[0] = (uint32_t)rate;
  155. return_values.rate[1] = (uint32_t)((uint64_t)rate >> 32);
  156. scmi_write_response(msg, &return_values, sizeof(return_values));
  157. }
  158. static void scmi_clock_rate_set(struct scmi_msg *msg)
  159. {
  160. const struct scmi_clock_rate_set_a2p *in_args = (void *)msg->in;
  161. unsigned long rate = 0U;
  162. int32_t status = 0;
  163. unsigned int clock_id = 0U;
  164. if (msg->in_size != sizeof(*in_args)) {
  165. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  166. return;
  167. }
  168. clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
  169. if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
  170. scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
  171. return;
  172. }
  173. rate = (unsigned long)(((uint64_t)in_args->rate[1] << 32) |
  174. in_args->rate[0]);
  175. status = plat_scmi_clock_set_rate(msg->agent_id, clock_id, rate);
  176. scmi_status_response(msg, status);
  177. }
  178. static void scmi_clock_config_set(struct scmi_msg *msg)
  179. {
  180. const struct scmi_clock_config_set_a2p *in_args = (void *)msg->in;
  181. int32_t status = SCMI_GENERIC_ERROR;
  182. bool enable = false;
  183. unsigned int clock_id = 0U;
  184. if (msg->in_size != sizeof(*in_args)) {
  185. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  186. return;
  187. }
  188. clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
  189. if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
  190. scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
  191. return;
  192. }
  193. enable = in_args->attributes & SCMI_CLOCK_CONFIG_SET_ENABLE_MASK;
  194. status = plat_scmi_clock_set_state(msg->agent_id, clock_id, enable);
  195. scmi_status_response(msg, status);
  196. }
  197. #define RATES_ARRAY_SIZE_MAX (SCMI_PLAYLOAD_MAX - \
  198. sizeof(struct scmi_clock_describe_rates_p2a))
  199. #define SCMI_RATES_BY_ARRAY(_nb_rates, _rem_rates) \
  200. SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS((_nb_rates), \
  201. SCMI_CLOCK_RATE_FORMAT_LIST, \
  202. (_rem_rates))
  203. #define SCMI_RATES_BY_STEP \
  204. SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(3U, \
  205. SCMI_CLOCK_RATE_FORMAT_RANGE, \
  206. 0U)
  207. #define RATE_DESC_SIZE sizeof(struct scmi_clock_rate)
  208. static void write_rate_desc_array_in_buffer(char *dest, unsigned long *rates,
  209. size_t nb_elt)
  210. {
  211. uint32_t *out = (uint32_t *)(uintptr_t)dest;
  212. size_t n;
  213. ASSERT_SYM_PTR_ALIGN(out);
  214. for (n = 0U; n < nb_elt; n++) {
  215. out[2 * n] = (uint32_t)rates[n];
  216. out[2 * n + 1] = (uint32_t)((uint64_t)rates[n] >> 32);
  217. }
  218. }
  219. static void scmi_clock_describe_rates(struct scmi_msg *msg)
  220. {
  221. const struct scmi_clock_describe_rates_a2p *in_args = (void *)msg->in;
  222. struct scmi_clock_describe_rates_p2a p2a = {
  223. .status = SCMI_SUCCESS,
  224. };
  225. size_t nb_rates;
  226. int32_t status;
  227. unsigned int clock_id;
  228. if (msg->in_size != sizeof(*in_args)) {
  229. scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
  230. return;
  231. }
  232. clock_id = SPECULATION_SAFE_VALUE(in_args->clock_id);
  233. if (clock_id >= plat_scmi_clock_count(msg->agent_id)) {
  234. scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
  235. return;
  236. }
  237. /* Platform may support array rate description */
  238. status = plat_scmi_clock_rates_array(msg->agent_id, clock_id, NULL,
  239. &nb_rates, 0);
  240. if (status == SCMI_SUCCESS) {
  241. /* Currently 12 cells mex, so it's affordable for the stack */
  242. unsigned long plat_rates[RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE];
  243. size_t max_nb = RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE;
  244. size_t ret_nb = MIN(nb_rates - in_args->rate_index, max_nb);
  245. size_t rem_nb = nb_rates - in_args->rate_index - ret_nb;
  246. status = plat_scmi_clock_rates_array(msg->agent_id, clock_id,
  247. plat_rates, &ret_nb,
  248. in_args->rate_index);
  249. if (status == SCMI_SUCCESS) {
  250. write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
  251. plat_rates, ret_nb);
  252. p2a.num_rates_flags = SCMI_RATES_BY_ARRAY(ret_nb,
  253. rem_nb);
  254. p2a.status = SCMI_SUCCESS;
  255. memcpy(msg->out, &p2a, sizeof(p2a));
  256. msg->out_size_out = sizeof(p2a) +
  257. ret_nb * RATE_DESC_SIZE;
  258. }
  259. } else if (status == SCMI_NOT_SUPPORTED) {
  260. unsigned long triplet[3] = { 0U, 0U, 0U };
  261. /* Platform may support min§max/step triplet description */
  262. status = plat_scmi_clock_rates_by_step(msg->agent_id, clock_id,
  263. triplet);
  264. if (status == SCMI_SUCCESS) {
  265. write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
  266. triplet, 3U);
  267. p2a.num_rates_flags = SCMI_RATES_BY_STEP;
  268. p2a.status = SCMI_SUCCESS;
  269. memcpy(msg->out, &p2a, sizeof(p2a));
  270. msg->out_size_out = sizeof(p2a) + (3U * RATE_DESC_SIZE);
  271. }
  272. } else {
  273. /* Fallthrough generic exit sequence below with error status */
  274. }
  275. if (status != SCMI_SUCCESS) {
  276. scmi_status_response(msg, status);
  277. } else {
  278. /*
  279. * Message payload is already written to msg->out, and
  280. * msg->out_size_out updated.
  281. */
  282. }
  283. }
  284. static const scmi_msg_handler_t scmi_clock_handler_table[] = {
  285. [SCMI_PROTOCOL_VERSION] = report_version,
  286. [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
  287. [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
  288. [SCMI_CLOCK_ATTRIBUTES] = scmi_clock_attributes,
  289. [SCMI_CLOCK_DESCRIBE_RATES] = scmi_clock_describe_rates,
  290. [SCMI_CLOCK_RATE_SET] = scmi_clock_rate_set,
  291. [SCMI_CLOCK_RATE_GET] = scmi_clock_rate_get,
  292. [SCMI_CLOCK_CONFIG_SET] = scmi_clock_config_set,
  293. };
  294. static bool message_id_is_supported(unsigned int message_id)
  295. {
  296. return (message_id < ARRAY_SIZE(scmi_clock_handler_table)) &&
  297. (scmi_clock_handler_table[message_id] != NULL);
  298. }
  299. scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg)
  300. {
  301. const size_t array_size = ARRAY_SIZE(scmi_clock_handler_table);
  302. unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
  303. if (message_id >= array_size) {
  304. VERBOSE("Clock handle not found %u", msg->message_id);
  305. return NULL;
  306. }
  307. return scmi_clock_handler_table[message_id];
  308. }