reset.c 9.4 KB

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