scmi_agent-uclass.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2020 Linaro Limited.
  4. */
  5. #define LOG_CATEGORY UCLASS_SCMI_AGENT
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <errno.h>
  9. #include <scmi_agent-uclass.h>
  10. #include <scmi_protocols.h>
  11. #include <dm/device_compat.h>
  12. #include <dm/device-internal.h>
  13. #include <linux/compat.h>
  14. /**
  15. * struct error_code - Helper structure for SCMI error code conversion
  16. * @scmi: SCMI error code
  17. * @errno: Related standard error number
  18. */
  19. struct error_code {
  20. int scmi;
  21. int errno;
  22. };
  23. static const struct error_code scmi_linux_errmap[] = {
  24. { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
  25. { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
  26. { .scmi = SCMI_DENIED, .errno = -EACCES, },
  27. { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
  28. { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
  29. { .scmi = SCMI_BUSY, .errno = -EBUSY, },
  30. { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
  31. { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
  32. { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
  33. { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
  34. };
  35. int scmi_to_linux_errno(s32 scmi_code)
  36. {
  37. int n;
  38. if (!scmi_code)
  39. return 0;
  40. for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
  41. if (scmi_code == scmi_linux_errmap[n].scmi)
  42. return scmi_linux_errmap[n].errno;
  43. return -EPROTO;
  44. }
  45. /*
  46. * SCMI agent devices binds devices of various uclasses depeding on
  47. * the FDT description. scmi_bind_protocol() is a generic bind sequence
  48. * called by the uclass at bind stage, that is uclass post_bind.
  49. */
  50. static int scmi_bind_protocols(struct udevice *dev)
  51. {
  52. int ret = 0;
  53. ofnode node;
  54. const char *name;
  55. dev_for_each_subnode(node, dev) {
  56. struct driver *drv = NULL;
  57. u32 protocol_id;
  58. if (!ofnode_is_enabled(node))
  59. continue;
  60. if (ofnode_read_u32(node, "reg", &protocol_id))
  61. continue;
  62. name = ofnode_get_name(node);
  63. switch (protocol_id) {
  64. case SCMI_PROTOCOL_ID_CLOCK:
  65. if (CONFIG_IS_ENABLED(CLK_SCMI))
  66. drv = DM_DRIVER_GET(scmi_clock);
  67. break;
  68. case SCMI_PROTOCOL_ID_RESET_DOMAIN:
  69. if (IS_ENABLED(CONFIG_RESET_SCMI))
  70. drv = DM_DRIVER_GET(scmi_reset_domain);
  71. break;
  72. case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
  73. if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
  74. node = ofnode_find_subnode(node, "regulators");
  75. if (!ofnode_valid(node)) {
  76. dev_err(dev, "no regulators node\n");
  77. return -ENXIO;
  78. }
  79. drv = DM_DRIVER_GET(scmi_voltage_domain);
  80. }
  81. break;
  82. default:
  83. break;
  84. }
  85. if (!drv) {
  86. dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
  87. protocol_id);
  88. continue;
  89. }
  90. ret = device_bind(dev, drv, name, NULL, node, NULL);
  91. if (ret)
  92. break;
  93. }
  94. return ret;
  95. }
  96. static struct udevice *find_scmi_transport_device(struct udevice *dev)
  97. {
  98. struct udevice *parent = dev;
  99. do {
  100. parent = dev_get_parent(parent);
  101. } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
  102. if (!parent)
  103. dev_err(dev, "Invalid SCMI device, agent not found\n");
  104. return parent;
  105. }
  106. static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
  107. {
  108. return (const struct scmi_agent_ops *)dev->driver->ops;
  109. }
  110. int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
  111. {
  112. struct udevice *parent;
  113. parent = find_scmi_transport_device(dev);
  114. if (!parent)
  115. return -ENODEV;
  116. if (transport_dev_ops(parent)->of_get_channel)
  117. return transport_dev_ops(parent)->of_get_channel(parent, channel);
  118. /* Drivers without a get_channel operator don't need a channel ref */
  119. *channel = NULL;
  120. return 0;
  121. }
  122. int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
  123. struct scmi_msg *msg)
  124. {
  125. const struct scmi_agent_ops *ops;
  126. struct udevice *parent;
  127. parent = find_scmi_transport_device(dev);
  128. if (!parent)
  129. return -ENODEV;
  130. ops = transport_dev_ops(parent);
  131. if (ops->process_msg)
  132. return ops->process_msg(parent, channel, msg);
  133. return -EPROTONOSUPPORT;
  134. }
  135. UCLASS_DRIVER(scmi_agent) = {
  136. .id = UCLASS_SCMI_AGENT,
  137. .name = "scmi_agent",
  138. .post_bind = scmi_bind_protocols,
  139. };