155 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 11bool __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 30int 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 59int 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 /* If MHI is in M3, resume suspended channels */66 mutex_lock(&mhi_cntrl->state_lock);67 68 old_state = mhi_cntrl->mhi_state;69 if (old_state == MHI_STATE_M3)70 mhi_ep_resume_channels(mhi_cntrl);71 72 ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M0);73 if (ret) {74 mhi_ep_handle_syserr(mhi_cntrl);75 goto err_unlock;76 }77 78 /* Signal host that the device moved to M0 */79 ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0);80 if (ret) {81 dev_err(dev, "Failed sending M0 state change event\n");82 goto err_unlock;83 }84 85 if (old_state == MHI_STATE_READY) {86 /* Send AMSS EE event to host */87 ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS);88 if (ret) {89 dev_err(dev, "Failed sending AMSS EE event\n");90 goto err_unlock;91 }92 }93 94err_unlock:95 mutex_unlock(&mhi_cntrl->state_lock);96 97 return ret;98}99 100int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)101{102 struct device *dev = &mhi_cntrl->mhi_dev->dev;103 int ret;104 105 mutex_lock(&mhi_cntrl->state_lock);106 107 ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);108 if (ret) {109 mhi_ep_handle_syserr(mhi_cntrl);110 goto err_unlock;111 }112 113 mhi_ep_suspend_channels(mhi_cntrl);114 115 /* Signal host that the device moved to M3 */116 ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3);117 if (ret) {118 dev_err(dev, "Failed sending M3 state change event\n");119 goto err_unlock;120 }121 122err_unlock:123 mutex_unlock(&mhi_cntrl->state_lock);124 125 return ret;126}127 128int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)129{130 struct device *dev = &mhi_cntrl->mhi_dev->dev;131 enum mhi_state mhi_state;132 int ret, is_ready;133 134 mutex_lock(&mhi_cntrl->state_lock);135 136 /* Ensure that the MHISTATUS is set to RESET by host */137 mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK);138 is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK);139 140 if (mhi_state != MHI_STATE_RESET || is_ready) {141 dev_err(dev, "READY state transition failed. MHI host not in RESET state\n");142 ret = -EIO;143 goto err_unlock;144 }145 146 ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY);147 if (ret)148 mhi_ep_handle_syserr(mhi_cntrl);149 150err_unlock:151 mutex_unlock(&mhi_cntrl->state_lock);152 153 return ret;154}155