pm-domain-scmi.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-21 GuEe-GUI first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #define DBG_TAG "pm-domain.scmi"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. struct scmi_pm_domain_proxy;
  16. struct scmi_pm_domain
  17. {
  18. struct rt_dm_power_domain parent;
  19. rt_uint32_t domain;
  20. struct scmi_pm_domain_proxy *proxy;
  21. };
  22. #define raw_to_scmi_pm_domain(raw) rt_container_of(raw, struct scmi_pm_domain, parent)
  23. struct scmi_pm_domain_proxy
  24. {
  25. struct rt_dm_power_domain_proxy parent;
  26. struct rt_scmi_device *sdev;
  27. rt_uint32_t num_domains;
  28. struct scmi_pm_domain domains[];
  29. };
  30. #define raw_to_scmi_pm_domain_proxy(raw) rt_container_of(raw, struct scmi_pm_domain_proxy, parent)
  31. static rt_err_t scmi_pm_domain_power(struct scmi_pm_domain *scmi_pd, rt_bool_t power_on)
  32. {
  33. struct scmi_power_state_set_in in =
  34. {
  35. .flags = rt_cpu_to_le32(0),
  36. .domain = rt_cpu_to_le32(scmi_pd->domain),
  37. .state = rt_cpu_to_le32(power_on ? SCMI_POWER_STATE_GENERIC_ON : SCMI_POWER_STATE_GENERIC_OFF),
  38. };
  39. struct scmi_power_state_set_out out;
  40. struct rt_scmi_msg msg = RT_SCMI_MSG_IN_OUT(SCMI_POWER_STATE_SET, &in, &out);
  41. return rt_scmi_process_msg(scmi_pd->proxy->sdev, &msg);
  42. }
  43. static rt_err_t scmi_pd_power_on(struct rt_dm_power_domain *domain)
  44. {
  45. return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_TRUE);
  46. }
  47. static rt_err_t scmi_pd_power_off(struct rt_dm_power_domain *domain)
  48. {
  49. return scmi_pm_domain_power(raw_to_scmi_pm_domain(domain), RT_FALSE);
  50. }
  51. static struct rt_dm_power_domain *scmi_pm_domain_proxy_ofw_parse(
  52. struct rt_dm_power_domain_proxy *proxy, struct rt_ofw_cell_args *args)
  53. {
  54. struct scmi_pm_domain_proxy *scmi_proxy = raw_to_scmi_pm_domain_proxy(proxy);
  55. return &scmi_proxy->domains[args->args[0]].parent;
  56. }
  57. static rt_err_t scmi_pm_domain_probe(struct rt_scmi_device *sdev)
  58. {
  59. rt_err_t err;
  60. rt_uint32_t num_domains;
  61. struct scmi_pm_domain *scmi_pds;
  62. struct scmi_pm_domain_proxy *scmi_proxy;
  63. struct scmi_power_attributes attr = {};
  64. struct rt_scmi_msg msg = RT_SCMI_MSG_OUT(SCMI_COM_MSG_ATTRIBUTES, &attr);
  65. if ((err = rt_scmi_process_msg(sdev, &msg)))
  66. {
  67. return err;
  68. }
  69. num_domains = rt_le16_to_cpu(attr.num_domains);
  70. scmi_proxy = rt_calloc(1, sizeof(*scmi_proxy) + sizeof(*scmi_pds) * num_domains);
  71. if (!scmi_proxy)
  72. {
  73. return -RT_ENOMEM;
  74. }
  75. scmi_proxy->sdev = sdev;
  76. scmi_proxy->num_domains = num_domains;
  77. scmi_pds = scmi_proxy->domains;
  78. for (int i = 0; i < num_domains; ++i, ++scmi_pds)
  79. {
  80. struct rt_dm_power_domain *domain = &scmi_pds->parent;
  81. domain->power_off = scmi_pd_power_off;
  82. domain->power_on = scmi_pd_power_on;
  83. scmi_pds->domain = i;
  84. scmi_pds->proxy = scmi_proxy;
  85. rt_dm_power_domain_register(domain);
  86. }
  87. scmi_proxy->parent.ofw_parse = scmi_pm_domain_proxy_ofw_parse;
  88. rt_dm_power_domain_proxy_ofw_bind(&scmi_proxy->parent, sdev->parent.ofw_node);
  89. return RT_EOK;
  90. }
  91. static const struct rt_scmi_device_id scmi_pm_domain_ids[] =
  92. {
  93. { SCMI_PROTOCOL_ID_POWER, "genpd" },
  94. { /* sentinel */ },
  95. };
  96. static struct rt_scmi_driver scmi_pm_domain_driver =
  97. {
  98. .name = "pm-domain-scmi",
  99. .ids = scmi_pm_domain_ids,
  100. .probe = scmi_pm_domain_probe,
  101. };
  102. RT_SCMI_DRIVER_EXPORT(scmi_pm_domain_driver);