reset.c 9.2 KB

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