reset.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * System Control and Management Interface (SCMI) Reset Protocol
  4. *
  5. * Copyright (C) 2019-2022 ARM Ltd.
  6. */
  7. #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt
  8. #include <linux/module.h>
  9. #include <linux/scmi_protocol.h>
  10. #include "protocols.h"
  11. #include "notify.h"
  12. enum scmi_reset_protocol_cmd {
  13. RESET_DOMAIN_ATTRIBUTES = 0x3,
  14. RESET = 0x4,
  15. RESET_NOTIFY = 0x5,
  16. RESET_DOMAIN_NAME_GET = 0x6,
  17. };
  18. #define NUM_RESET_DOMAIN_MASK 0xffff
  19. #define RESET_NOTIFY_ENABLE BIT(0)
  20. struct scmi_msg_resp_reset_domain_attributes {
  21. __le32 attributes;
  22. #define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31))
  23. #define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30))
  24. #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29))
  25. __le32 latency;
  26. u8 name[SCMI_SHORT_NAME_MAX_SIZE];
  27. };
  28. struct scmi_msg_reset_domain_reset {
  29. __le32 domain_id;
  30. __le32 flags;
  31. #define AUTONOMOUS_RESET BIT(0)
  32. #define EXPLICIT_RESET_ASSERT BIT(1)
  33. #define ASYNCHRONOUS_RESET BIT(2)
  34. __le32 reset_state;
  35. #define ARCH_COLD_RESET 0
  36. };
  37. struct scmi_msg_reset_notify {
  38. __le32 id;
  39. __le32 event_control;
  40. #define RESET_TP_NOTIFY_ALL BIT(0)
  41. };
  42. struct scmi_reset_issued_notify_payld {
  43. __le32 agent_id;
  44. __le32 domain_id;
  45. __le32 reset_state;
  46. };
  47. struct reset_dom_info {
  48. bool async_reset;
  49. bool reset_notify;
  50. u32 latency_us;
  51. char name[SCMI_MAX_STR_SIZE];
  52. };
  53. struct scmi_reset_info {
  54. u32 version;
  55. int num_domains;
  56. struct reset_dom_info *dom_info;
  57. };
  58. static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
  59. struct scmi_reset_info *pi)
  60. {
  61. int ret;
  62. struct scmi_xfer *t;
  63. u32 attr;
  64. ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,
  65. 0, sizeof(attr), &t);
  66. if (ret)
  67. return ret;
  68. ret = ph->xops->do_xfer(ph, t);
  69. if (!ret) {
  70. attr = get_unaligned_le32(t->rx.buf);
  71. pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
  72. }
  73. ph->xops->xfer_put(ph, t);
  74. return ret;
  75. }
  76. static int
  77. scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
  78. u32 domain, struct reset_dom_info *dom_info,
  79. u32 version)
  80. {
  81. int ret;
  82. u32 attributes;
  83. struct scmi_xfer *t;
  84. struct scmi_msg_resp_reset_domain_attributes *attr;
  85. ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
  86. sizeof(domain), sizeof(*attr), &t);
  87. if (ret)
  88. return ret;
  89. put_unaligned_le32(domain, t->tx.buf);
  90. attr = t->rx.buf;
  91. ret = ph->xops->do_xfer(ph, t);
  92. if (!ret) {
  93. attributes = le32_to_cpu(attr->attributes);
  94. dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
  95. dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
  96. dom_info->latency_us = le32_to_cpu(attr->latency);
  97. if (dom_info->latency_us == U32_MAX)
  98. dom_info->latency_us = 0;
  99. strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
  100. }
  101. ph->xops->xfer_put(ph, t);
  102. /*
  103. * If supported overwrite short name with the extended one;
  104. * on error just carry on and use already provided short name.
  105. */
  106. if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
  107. SUPPORTS_EXTENDED_NAMES(attributes))
  108. ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
  109. dom_info->name, SCMI_MAX_STR_SIZE);
  110. return ret;
  111. }
  112. static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
  113. {
  114. struct scmi_reset_info *pi = ph->get_priv(ph);
  115. return pi->num_domains;
  116. }
  117. static const char *
  118. scmi_reset_name_get(const struct scmi_protocol_handle *ph, u32 domain)
  119. {
  120. struct scmi_reset_info *pi = ph->get_priv(ph);
  121. struct reset_dom_info *dom = pi->dom_info + domain;
  122. return dom->name;
  123. }
  124. static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
  125. u32 domain)
  126. {
  127. struct scmi_reset_info *pi = ph->get_priv(ph);
  128. struct reset_dom_info *dom = pi->dom_info + domain;
  129. return dom->latency_us;
  130. }
  131. static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
  132. u32 flags, u32 state)
  133. {
  134. int ret;
  135. struct scmi_xfer *t;
  136. struct scmi_msg_reset_domain_reset *dom;
  137. struct scmi_reset_info *pi = ph->get_priv(ph);
  138. struct reset_dom_info *rdom;
  139. if (domain >= pi->num_domains)
  140. return -EINVAL;
  141. rdom = pi->dom_info + domain;
  142. if (rdom->async_reset && flags & AUTONOMOUS_RESET)
  143. flags |= ASYNCHRONOUS_RESET;
  144. ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
  145. if (ret)
  146. return ret;
  147. dom = t->tx.buf;
  148. dom->domain_id = cpu_to_le32(domain);
  149. dom->flags = cpu_to_le32(flags);
  150. dom->reset_state = cpu_to_le32(state);
  151. if (flags & ASYNCHRONOUS_RESET)
  152. ret = ph->xops->do_xfer_with_response(ph, t);
  153. else
  154. ret = ph->xops->do_xfer(ph, t);
  155. ph->xops->xfer_put(ph, t);
  156. return ret;
  157. }
  158. static int scmi_reset_domain_reset(const struct scmi_protocol_handle *ph,
  159. u32 domain)
  160. {
  161. return scmi_domain_reset(ph, domain, AUTONOMOUS_RESET,
  162. ARCH_COLD_RESET);
  163. }
  164. static int
  165. scmi_reset_domain_assert(const struct scmi_protocol_handle *ph, u32 domain)
  166. {
  167. return scmi_domain_reset(ph, domain, EXPLICIT_RESET_ASSERT,
  168. ARCH_COLD_RESET);
  169. }
  170. static int
  171. scmi_reset_domain_deassert(const struct scmi_protocol_handle *ph, u32 domain)
  172. {
  173. return scmi_domain_reset(ph, domain, 0, ARCH_COLD_RESET);
  174. }
  175. static const struct scmi_reset_proto_ops reset_proto_ops = {
  176. .num_domains_get = scmi_reset_num_domains_get,
  177. .name_get = scmi_reset_name_get,
  178. .latency_get = scmi_reset_latency_get,
  179. .reset = scmi_reset_domain_reset,
  180. .assert = scmi_reset_domain_assert,
  181. .deassert = scmi_reset_domain_deassert,
  182. };
  183. static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
  184. u32 domain_id, bool enable)
  185. {
  186. int ret;
  187. u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0;
  188. struct scmi_xfer *t;
  189. struct scmi_msg_reset_notify *cfg;
  190. ret = ph->xops->xfer_get_init(ph, RESET_NOTIFY, sizeof(*cfg), 0, &t);
  191. if (ret)
  192. return ret;
  193. cfg = t->tx.buf;
  194. cfg->id = cpu_to_le32(domain_id);
  195. cfg->event_control = cpu_to_le32(evt_cntl);
  196. ret = ph->xops->do_xfer(ph, t);
  197. ph->xops->xfer_put(ph, t);
  198. return ret;
  199. }
  200. static int scmi_reset_set_notify_enabled(const struct scmi_protocol_handle *ph,
  201. u8 evt_id, u32 src_id, bool enable)
  202. {
  203. int ret;
  204. ret = scmi_reset_notify(ph, src_id, enable);
  205. if (ret)
  206. pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
  207. evt_id, src_id, ret);
  208. return ret;
  209. }
  210. static void *
  211. scmi_reset_fill_custom_report(const struct scmi_protocol_handle *ph,
  212. u8 evt_id, ktime_t timestamp,
  213. const void *payld, size_t payld_sz,
  214. void *report, u32 *src_id)
  215. {
  216. const struct scmi_reset_issued_notify_payld *p = payld;
  217. struct scmi_reset_issued_report *r = report;
  218. if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz)
  219. return NULL;
  220. r->timestamp = timestamp;
  221. r->agent_id = le32_to_cpu(p->agent_id);
  222. r->domain_id = le32_to_cpu(p->domain_id);
  223. r->reset_state = le32_to_cpu(p->reset_state);
  224. *src_id = r->domain_id;
  225. return r;
  226. }
  227. static int scmi_reset_get_num_sources(const struct scmi_protocol_handle *ph)
  228. {
  229. struct scmi_reset_info *pinfo = ph->get_priv(ph);
  230. if (!pinfo)
  231. return -EINVAL;
  232. return pinfo->num_domains;
  233. }
  234. static const struct scmi_event reset_events[] = {
  235. {
  236. .id = SCMI_EVENT_RESET_ISSUED,
  237. .max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld),
  238. .max_report_sz = sizeof(struct scmi_reset_issued_report),
  239. },
  240. };
  241. static const struct scmi_event_ops reset_event_ops = {
  242. .get_num_sources = scmi_reset_get_num_sources,
  243. .set_notify_enabled = scmi_reset_set_notify_enabled,
  244. .fill_custom_report = scmi_reset_fill_custom_report,
  245. };
  246. static const struct scmi_protocol_events reset_protocol_events = {
  247. .queue_sz = SCMI_PROTO_QUEUE_SZ,
  248. .ops = &reset_event_ops,
  249. .evts = reset_events,
  250. .num_events = ARRAY_SIZE(reset_events),
  251. };
  252. static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
  253. {
  254. int domain, ret;
  255. u32 version;
  256. struct scmi_reset_info *pinfo;
  257. ret = ph->xops->version_get(ph, &version);
  258. if (ret)
  259. return ret;
  260. dev_dbg(ph->dev, "Reset Version %d.%d\n",
  261. PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
  262. pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
  263. if (!pinfo)
  264. return -ENOMEM;
  265. ret = scmi_reset_attributes_get(ph, pinfo);
  266. if (ret)
  267. return ret;
  268. pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
  269. sizeof(*pinfo->dom_info), GFP_KERNEL);
  270. if (!pinfo->dom_info)
  271. return -ENOMEM;
  272. for (domain = 0; domain < pinfo->num_domains; domain++) {
  273. struct reset_dom_info *dom = pinfo->dom_info + domain;
  274. scmi_reset_domain_attributes_get(ph, domain, dom, version);
  275. }
  276. pinfo->version = version;
  277. return ph->set_priv(ph, pinfo);
  278. }
  279. static const struct scmi_protocol scmi_reset = {
  280. .id = SCMI_PROTOCOL_RESET,
  281. .owner = THIS_MODULE,
  282. .instance_init = &scmi_reset_protocol_init,
  283. .ops = &reset_proto_ops,
  284. .events = &reset_protocol_events,
  285. };
  286. DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)