sched.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2011-2017, The Linux Foundation
  4. */
  5. #include <linux/errno.h>
  6. #include "slimbus.h"
  7. /**
  8. * slim_ctrl_clk_pause() - Called by slimbus controller to enter/exit
  9. * 'clock pause'
  10. * @ctrl: controller requesting bus to be paused or woken up
  11. * @wakeup: Wakeup this controller from clock pause.
  12. * @restart: Restart time value per spec used for clock pause. This value
  13. * isn't used when controller is to be woken up.
  14. *
  15. * Slimbus specification needs this sequence to turn-off clocks for the bus.
  16. * The sequence involves sending 3 broadcast messages (reconfiguration
  17. * sequence) to inform all devices on the bus.
  18. * To exit clock-pause, controller typically wakes up active framer device.
  19. * This API executes clock pause reconfiguration sequence if wakeup is false.
  20. * If wakeup is true, controller's wakeup is called.
  21. * For entering clock-pause, -EBUSY is returned if a message txn in pending.
  22. */
  23. int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
  24. {
  25. int i, ret = 0;
  26. unsigned long flags;
  27. struct slim_sched *sched = &ctrl->sched;
  28. struct slim_val_inf msg = {0, 0, NULL, NULL};
  29. DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
  30. 3, SLIM_LA_MANAGER, &msg);
  31. if (wakeup == false && restart > SLIM_CLK_UNSPECIFIED)
  32. return -EINVAL;
  33. mutex_lock(&sched->m_reconf);
  34. if (wakeup) {
  35. if (sched->clk_state == SLIM_CLK_ACTIVE) {
  36. mutex_unlock(&sched->m_reconf);
  37. return 0;
  38. }
  39. /*
  40. * Fine-tune calculation based on clock gear,
  41. * message-bandwidth after bandwidth management
  42. */
  43. ret = wait_for_completion_timeout(&sched->pause_comp,
  44. msecs_to_jiffies(100));
  45. if (!ret) {
  46. mutex_unlock(&sched->m_reconf);
  47. pr_err("Previous clock pause did not finish");
  48. return -ETIMEDOUT;
  49. }
  50. ret = 0;
  51. /*
  52. * Slimbus framework will call controller wakeup
  53. * Controller should make sure that it sets active framer
  54. * out of clock pause
  55. */
  56. if (sched->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
  57. ret = ctrl->wakeup(ctrl);
  58. if (!ret)
  59. sched->clk_state = SLIM_CLK_ACTIVE;
  60. mutex_unlock(&sched->m_reconf);
  61. return ret;
  62. }
  63. /* already paused */
  64. if (ctrl->sched.clk_state == SLIM_CLK_PAUSED) {
  65. mutex_unlock(&sched->m_reconf);
  66. return 0;
  67. }
  68. spin_lock_irqsave(&ctrl->txn_lock, flags);
  69. for (i = 0; i < SLIM_MAX_TIDS; i++) {
  70. /* Pending response for a message */
  71. if (idr_find(&ctrl->tid_idr, i)) {
  72. spin_unlock_irqrestore(&ctrl->txn_lock, flags);
  73. mutex_unlock(&sched->m_reconf);
  74. return -EBUSY;
  75. }
  76. }
  77. spin_unlock_irqrestore(&ctrl->txn_lock, flags);
  78. sched->clk_state = SLIM_CLK_ENTERING_PAUSE;
  79. /* clock pause sequence */
  80. ret = slim_do_transfer(ctrl, &txn);
  81. if (ret)
  82. goto clk_pause_ret;
  83. txn.mc = SLIM_MSG_MC_NEXT_PAUSE_CLOCK;
  84. txn.rl = 4;
  85. msg.num_bytes = 1;
  86. msg.wbuf = &restart;
  87. ret = slim_do_transfer(ctrl, &txn);
  88. if (ret)
  89. goto clk_pause_ret;
  90. txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
  91. txn.rl = 3;
  92. msg.num_bytes = 1;
  93. msg.wbuf = NULL;
  94. ret = slim_do_transfer(ctrl, &txn);
  95. clk_pause_ret:
  96. if (ret) {
  97. sched->clk_state = SLIM_CLK_ACTIVE;
  98. } else {
  99. sched->clk_state = SLIM_CLK_PAUSED;
  100. complete(&sched->pause_comp);
  101. }
  102. mutex_unlock(&sched->m_reconf);
  103. return ret;
  104. }
  105. EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);