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 mhi_ep_handle_syserr(mhi_cntrl); 73 return ret; 74 } 75 76 /* Signal host that the device moved to M0 */ 77 ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0); 78 if (ret) { 79 dev_err(dev, "Failed sending M0 state change event\n"); 80 return ret; 81 } 82 83 if (old_state == MHI_STATE_READY) { 84 /* Send AMSS EE event to host */ 85 ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS); 86 if (ret) { 87 dev_err(dev, "Failed sending AMSS EE event\n"); 88 return ret; 89 } 90 } 91 92 return 0; 93 } 94 95 int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl) 96 { 97 struct device *dev = &mhi_cntrl->mhi_dev->dev; 98 int ret; 99 100 spin_lock_bh(&mhi_cntrl->state_lock); 101 ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3); 102 spin_unlock_bh(&mhi_cntrl->state_lock); 103 104 if (ret) { 105 mhi_ep_handle_syserr(mhi_cntrl); 106 return ret; 107 } 108 109 /* Signal host that the device moved to M3 */ 110 ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3); 111 if (ret) { 112 dev_err(dev, "Failed sending M3 state change event\n"); 113 return ret; 114 } 115 116 return 0; 117 } 118 119 int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl) 120 { 121 struct device *dev = &mhi_cntrl->mhi_dev->dev; 122 enum mhi_state mhi_state; 123 int ret, is_ready; 124 125 spin_lock_bh(&mhi_cntrl->state_lock); 126 /* Ensure that the MHISTATUS is set to RESET by host */ 127 mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK); 128 is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK); 129 130 if (mhi_state != MHI_STATE_RESET || is_ready) { 131 dev_err(dev, "READY state transition failed. MHI host not in RESET state\n"); 132 spin_unlock_bh(&mhi_cntrl->state_lock); 133 return -EIO; 134 } 135 136 ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY); 137 spin_unlock_bh(&mhi_cntrl->state_lock); 138 139 if (ret) 140 mhi_ep_handle_syserr(mhi_cntrl); 141 142 return ret; 143 } 144