ti-sci-power-domain.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Texas Instruments System Control Interface (TI SCI) power domain driver
  4. *
  5. * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  6. * Andreas Dannenberg <dannenberg@ti.com>
  7. *
  8. * Loosely based on Linux kernel ti_sci_pm_domains.c...
  9. */
  10. #include <common.h>
  11. #include <dm.h>
  12. #include <errno.h>
  13. #include <log.h>
  14. #include <malloc.h>
  15. #include <power-domain-uclass.h>
  16. #include <dm/device_compat.h>
  17. #include <linux/err.h>
  18. #include <linux/soc/ti/ti_sci_protocol.h>
  19. #include <dt-bindings/soc/ti,sci_pm_domain.h>
  20. /**
  21. * struct ti_sci_power_domain_data - pm domain controller information structure
  22. * @sci: TI SCI handle used for communication with system controller
  23. */
  24. struct ti_sci_power_domain_data {
  25. const struct ti_sci_handle *sci;
  26. };
  27. static int ti_sci_power_domain_probe(struct udevice *dev)
  28. {
  29. struct ti_sci_power_domain_data *data = dev_get_priv(dev);
  30. debug("%s(dev=%p)\n", __func__, dev);
  31. if (!data)
  32. return -ENOMEM;
  33. /* Store handle for communication with the system controller */
  34. data->sci = ti_sci_get_handle(dev);
  35. if (IS_ERR(data->sci))
  36. return PTR_ERR(data->sci);
  37. return 0;
  38. }
  39. static int ti_sci_power_domain_request(struct power_domain *pd)
  40. {
  41. debug("%s(pd=%p)\n", __func__, pd);
  42. return 0;
  43. }
  44. static int ti_sci_power_domain_free(struct power_domain *pd)
  45. {
  46. debug("%s(pd=%p)\n", __func__, pd);
  47. return 0;
  48. }
  49. static int ti_sci_power_domain_on(struct power_domain *pd)
  50. {
  51. struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
  52. const struct ti_sci_handle *sci = data->sci;
  53. const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
  54. u8 flags = (uintptr_t)pd->priv;
  55. int ret;
  56. debug("%s(pd=%p)\n", __func__, pd);
  57. if (flags & TI_SCI_PD_EXCLUSIVE)
  58. ret = dops->get_device_exclusive(sci, pd->id);
  59. else
  60. ret = dops->get_device(sci, pd->id);
  61. if (ret)
  62. dev_err(pd->dev, "%s: get_device(%lu) failed (%d)\n",
  63. __func__, pd->id, ret);
  64. return ret;
  65. }
  66. static int ti_sci_power_domain_off(struct power_domain *pd)
  67. {
  68. struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
  69. const struct ti_sci_handle *sci = data->sci;
  70. const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
  71. int ret;
  72. debug("%s(pd=%p)\n", __func__, pd);
  73. ret = dops->put_device(sci, pd->id);
  74. if (ret)
  75. dev_err(pd->dev, "%s: put_device(%lu) failed (%d)\n",
  76. __func__, pd->id, ret);
  77. return ret;
  78. }
  79. static int ti_sci_power_domain_of_xlate(struct power_domain *pd,
  80. struct ofnode_phandle_args *args)
  81. {
  82. u8 flags;
  83. debug("%s(power_domain=%p)\n", __func__, pd);
  84. if (args->args_count < 1) {
  85. debug("Invalid args_count: %d\n", args->args_count);
  86. return -EINVAL;
  87. }
  88. pd->id = args->args[0];
  89. /* By default request for device exclusive */
  90. flags = TI_SCI_PD_EXCLUSIVE;
  91. if (args->args_count == 2)
  92. flags = args->args[1] & TI_SCI_PD_EXCLUSIVE;
  93. pd->priv = (void *)(uintptr_t)flags;
  94. return 0;
  95. }
  96. static const struct udevice_id ti_sci_power_domain_of_match[] = {
  97. { .compatible = "ti,sci-pm-domain" },
  98. { /* sentinel */ }
  99. };
  100. static struct power_domain_ops ti_sci_power_domain_ops = {
  101. .request = ti_sci_power_domain_request,
  102. .rfree = ti_sci_power_domain_free,
  103. .on = ti_sci_power_domain_on,
  104. .off = ti_sci_power_domain_off,
  105. .of_xlate = ti_sci_power_domain_of_xlate,
  106. };
  107. U_BOOT_DRIVER(ti_sci_pm_domains) = {
  108. .name = "ti-sci-pm-domains",
  109. .id = UCLASS_POWER_DOMAIN,
  110. .of_match = ti_sci_power_domain_of_match,
  111. .probe = ti_sci_power_domain_probe,
  112. .priv_auto_alloc_size = sizeof(struct ti_sci_power_domain_data),
  113. .ops = &ti_sci_power_domain_ops,
  114. };