scmi_agent-uclass.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2020 Linaro Limited.
  4. */
  5. #include <common.h>
  6. #include <dm.h>
  7. #include <dm/device_compat.h>
  8. #include <errno.h>
  9. #include <scmi_agent-uclass.h>
  10. #include <scmi_protocols.h>
  11. #include <dm/device-internal.h>
  12. #include <linux/compat.h>
  13. /**
  14. * struct error_code - Helper structure for SCMI error code conversion
  15. * @scmi: SCMI error code
  16. * @errno: Related standard error number
  17. */
  18. struct error_code {
  19. int scmi;
  20. int errno;
  21. };
  22. static const struct error_code scmi_linux_errmap[] = {
  23. { .scmi = SCMI_NOT_SUPPORTED, .errno = -EOPNOTSUPP, },
  24. { .scmi = SCMI_INVALID_PARAMETERS, .errno = -EINVAL, },
  25. { .scmi = SCMI_DENIED, .errno = -EACCES, },
  26. { .scmi = SCMI_NOT_FOUND, .errno = -ENOENT, },
  27. { .scmi = SCMI_OUT_OF_RANGE, .errno = -ERANGE, },
  28. { .scmi = SCMI_BUSY, .errno = -EBUSY, },
  29. { .scmi = SCMI_COMMS_ERROR, .errno = -ECOMM, },
  30. { .scmi = SCMI_GENERIC_ERROR, .errno = -EIO, },
  31. { .scmi = SCMI_HARDWARE_ERROR, .errno = -EREMOTEIO, },
  32. { .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
  33. };
  34. int scmi_to_linux_errno(s32 scmi_code)
  35. {
  36. int n;
  37. if (!scmi_code)
  38. return 0;
  39. for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
  40. if (scmi_code == scmi_linux_errmap[n].scmi)
  41. return scmi_linux_errmap[1].errno;
  42. return -EPROTO;
  43. }
  44. /*
  45. * SCMI agent devices binds devices of various uclasses depeding on
  46. * the FDT description. scmi_bind_protocol() is a generic bind sequence
  47. * called by the uclass at bind stage, that is uclass post_bind.
  48. */
  49. static int scmi_bind_protocols(struct udevice *dev)
  50. {
  51. int ret = 0;
  52. ofnode node;
  53. dev_for_each_subnode(node, dev) {
  54. struct driver *drv = NULL;
  55. u32 protocol_id;
  56. if (!ofnode_is_available(node))
  57. continue;
  58. if (ofnode_read_u32(node, "reg", &protocol_id))
  59. continue;
  60. switch (protocol_id) {
  61. case SCMI_PROTOCOL_ID_CLOCK:
  62. if (IS_ENABLED(CONFIG_CLK_SCMI))
  63. drv = DM_DRIVER_GET(scmi_clock);
  64. break;
  65. case SCMI_PROTOCOL_ID_RESET_DOMAIN:
  66. if (IS_ENABLED(CONFIG_RESET_SCMI))
  67. drv = DM_DRIVER_GET(scmi_reset_domain);
  68. break;
  69. default:
  70. break;
  71. }
  72. if (!drv) {
  73. dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
  74. protocol_id);
  75. continue;
  76. }
  77. ret = device_bind(dev, drv, ofnode_get_name(node), NULL, node,
  78. NULL);
  79. if (ret)
  80. break;
  81. }
  82. return ret;
  83. }
  84. static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
  85. {
  86. return (const struct scmi_agent_ops *)dev->driver->ops;
  87. }
  88. int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
  89. {
  90. const struct scmi_agent_ops *ops = transport_dev_ops(dev);
  91. if (ops->process_msg)
  92. return ops->process_msg(dev, msg);
  93. return -EPROTONOSUPPORT;
  94. }
  95. UCLASS_DRIVER(scmi_agent) = {
  96. .id = UCLASS_SCMI_AGENT,
  97. .name = "scmi_agent",
  98. .post_bind = scmi_bind_protocols,
  99. };