cc_pm.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (C) 2012-2018 ARM Limited or its affiliates. */
  3. #include <linux/kernel.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/pm_runtime.h>
  6. #include "cc_driver.h"
  7. #include "cc_buffer_mgr.h"
  8. #include "cc_request_mgr.h"
  9. #include "cc_sram_mgr.h"
  10. #include "cc_ivgen.h"
  11. #include "cc_hash.h"
  12. #include "cc_pm.h"
  13. #define POWER_DOWN_ENABLE 0x01
  14. #define POWER_DOWN_DISABLE 0x00
  15. const struct dev_pm_ops ccree_pm = {
  16. SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL)
  17. };
  18. int cc_pm_suspend(struct device *dev)
  19. {
  20. struct cc_drvdata *drvdata = dev_get_drvdata(dev);
  21. int rc;
  22. dev_dbg(dev, "set HOST_POWER_DOWN_EN\n");
  23. cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
  24. rc = cc_suspend_req_queue(drvdata);
  25. if (rc) {
  26. dev_err(dev, "cc_suspend_req_queue (%x)\n", rc);
  27. return rc;
  28. }
  29. fini_cc_regs(drvdata);
  30. cc_clk_off(drvdata);
  31. return 0;
  32. }
  33. int cc_pm_resume(struct device *dev)
  34. {
  35. int rc;
  36. struct cc_drvdata *drvdata = dev_get_drvdata(dev);
  37. dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n");
  38. cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
  39. rc = cc_clk_on(drvdata);
  40. if (rc) {
  41. dev_err(dev, "failed getting clock back on. We're toast.\n");
  42. return rc;
  43. }
  44. rc = init_cc_regs(drvdata, false);
  45. if (rc) {
  46. dev_err(dev, "init_cc_regs (%x)\n", rc);
  47. return rc;
  48. }
  49. rc = cc_resume_req_queue(drvdata);
  50. if (rc) {
  51. dev_err(dev, "cc_resume_req_queue (%x)\n", rc);
  52. return rc;
  53. }
  54. /* must be after the queue resuming as it uses the HW queue*/
  55. cc_init_hash_sram(drvdata);
  56. cc_init_iv_sram(drvdata);
  57. return 0;
  58. }
  59. int cc_pm_get(struct device *dev)
  60. {
  61. int rc = 0;
  62. struct cc_drvdata *drvdata = dev_get_drvdata(dev);
  63. if (cc_req_queue_suspended(drvdata))
  64. rc = pm_runtime_get_sync(dev);
  65. else
  66. pm_runtime_get_noresume(dev);
  67. return rc;
  68. }
  69. int cc_pm_put_suspend(struct device *dev)
  70. {
  71. int rc = 0;
  72. struct cc_drvdata *drvdata = dev_get_drvdata(dev);
  73. if (!cc_req_queue_suspended(drvdata)) {
  74. pm_runtime_mark_last_busy(dev);
  75. rc = pm_runtime_put_autosuspend(dev);
  76. } else {
  77. /* Something wrong happens*/
  78. dev_err(dev, "request to suspend already suspended queue");
  79. rc = -EBUSY;
  80. }
  81. return rc;
  82. }
  83. int cc_pm_init(struct cc_drvdata *drvdata)
  84. {
  85. int rc = 0;
  86. struct device *dev = drvdata_to_dev(drvdata);
  87. /* must be before the enabling to avoid resdundent suspending */
  88. pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
  89. pm_runtime_use_autosuspend(dev);
  90. /* activate the PM module */
  91. rc = pm_runtime_set_active(dev);
  92. if (rc)
  93. return rc;
  94. /* enable the PM module*/
  95. pm_runtime_enable(dev);
  96. return rc;
  97. }
  98. void cc_pm_fini(struct cc_drvdata *drvdata)
  99. {
  100. pm_runtime_disable(drvdata_to_dev(drvdata));
  101. }