sm.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022 Linaro Ltd.
  4. * Author: Manivannan Sadhasivam <[email protected]>
  5. */
  6. #include <linux/errno.h>
  7. #include <linux/mhi_ep.h>
  8. #include "internal.h"
  9. bool __must_check mhi_ep_check_mhi_state(struct mhi_ep_cntrl *mhi_cntrl,
  10. enum mhi_state cur_mhi_state,
  11. enum mhi_state mhi_state)
  12. {
  13. if (mhi_state == MHI_STATE_SYS_ERR)
  14. return true; /* Allowed in any state */
  15. if (mhi_state == MHI_STATE_READY)
  16. return cur_mhi_state == MHI_STATE_RESET;
  17. if (mhi_state == MHI_STATE_M0)
  18. return cur_mhi_state == MHI_STATE_M3 || cur_mhi_state == MHI_STATE_READY;
  19. if (mhi_state == MHI_STATE_M3)
  20. return cur_mhi_state == MHI_STATE_M0;
  21. return false;
  22. }
  23. int mhi_ep_set_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state mhi_state)
  24. {
  25. struct device *dev = &mhi_cntrl->mhi_dev->dev;
  26. if (!mhi_ep_check_mhi_state(mhi_cntrl, mhi_cntrl->mhi_state, mhi_state)) {
  27. dev_err(dev, "MHI state change to %s from %s is not allowed!\n",
  28. mhi_state_str(mhi_state),
  29. mhi_state_str(mhi_cntrl->mhi_state));
  30. return -EACCES;
  31. }
  32. /* TODO: Add support for M1 and M2 states */
  33. if (mhi_state == MHI_STATE_M1 || mhi_state == MHI_STATE_M2) {
  34. dev_err(dev, "MHI state (%s) not supported\n", mhi_state_str(mhi_state));
  35. return -EOPNOTSUPP;
  36. }
  37. mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK, mhi_state);
  38. mhi_cntrl->mhi_state = mhi_state;
  39. if (mhi_state == MHI_STATE_READY)
  40. mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK, 1);
  41. if (mhi_state == MHI_STATE_SYS_ERR)
  42. mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_SYSERR_MASK, 1);
  43. return 0;
  44. }
  45. int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl)
  46. {
  47. struct device *dev = &mhi_cntrl->mhi_dev->dev;
  48. enum mhi_state old_state;
  49. int ret;
  50. /* If MHI is in M3, resume suspended channels */
  51. mutex_lock(&mhi_cntrl->state_lock);
  52. old_state = mhi_cntrl->mhi_state;
  53. if (old_state == MHI_STATE_M3)
  54. mhi_ep_resume_channels(mhi_cntrl);
  55. ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M0);
  56. if (ret) {
  57. mhi_ep_handle_syserr(mhi_cntrl);
  58. goto err_unlock;
  59. }
  60. /* Signal host that the device moved to M0 */
  61. ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0);
  62. if (ret) {
  63. dev_err(dev, "Failed sending M0 state change event\n");
  64. goto err_unlock;
  65. }
  66. if (old_state == MHI_STATE_READY) {
  67. /* Send AMSS EE event to host */
  68. ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS);
  69. if (ret) {
  70. dev_err(dev, "Failed sending AMSS EE event\n");
  71. goto err_unlock;
  72. }
  73. }
  74. err_unlock:
  75. mutex_unlock(&mhi_cntrl->state_lock);
  76. return ret;
  77. }
  78. int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
  79. {
  80. struct device *dev = &mhi_cntrl->mhi_dev->dev;
  81. int ret;
  82. mutex_lock(&mhi_cntrl->state_lock);
  83. ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
  84. if (ret) {
  85. mhi_ep_handle_syserr(mhi_cntrl);
  86. goto err_unlock;
  87. }
  88. mhi_ep_suspend_channels(mhi_cntrl);
  89. /* Signal host that the device moved to M3 */
  90. ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3);
  91. if (ret) {
  92. dev_err(dev, "Failed sending M3 state change event\n");
  93. goto err_unlock;
  94. }
  95. err_unlock:
  96. mutex_unlock(&mhi_cntrl->state_lock);
  97. return ret;
  98. }
  99. int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)
  100. {
  101. struct device *dev = &mhi_cntrl->mhi_dev->dev;
  102. enum mhi_state mhi_state;
  103. int ret, is_ready;
  104. mutex_lock(&mhi_cntrl->state_lock);
  105. /* Ensure that the MHISTATUS is set to RESET by host */
  106. mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK);
  107. is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK);
  108. if (mhi_state != MHI_STATE_RESET || is_ready) {
  109. dev_err(dev, "READY state transition failed. MHI host not in RESET state\n");
  110. ret = -EIO;
  111. goto err_unlock;
  112. }
  113. ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY);
  114. if (ret)
  115. mhi_ep_handle_syserr(mhi_cntrl);
  116. err_unlock:
  117. mutex_unlock(&mhi_cntrl->state_lock);
  118. return ret;
  119. }