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