Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2022 Linaro Ltd.
0004  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
0005  */
0006 
0007 #include <linux/errno.h>
0008 #include <linux/mhi_ep.h>
0009 #include "internal.h"
0010 
0011 bool __must_check mhi_ep_check_mhi_state(struct mhi_ep_cntrl *mhi_cntrl,
0012                      enum mhi_state cur_mhi_state,
0013                      enum mhi_state mhi_state)
0014 {
0015     if (mhi_state == MHI_STATE_SYS_ERR)
0016         return true;    /* Allowed in any state */
0017 
0018     if (mhi_state == MHI_STATE_READY)
0019         return cur_mhi_state == MHI_STATE_RESET;
0020 
0021     if (mhi_state == MHI_STATE_M0)
0022         return cur_mhi_state == MHI_STATE_M3 || cur_mhi_state == MHI_STATE_READY;
0023 
0024     if (mhi_state == MHI_STATE_M3)
0025         return cur_mhi_state == MHI_STATE_M0;
0026 
0027     return false;
0028 }
0029 
0030 int mhi_ep_set_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state mhi_state)
0031 {
0032     struct device *dev = &mhi_cntrl->mhi_dev->dev;
0033 
0034     if (!mhi_ep_check_mhi_state(mhi_cntrl, mhi_cntrl->mhi_state, mhi_state)) {
0035         dev_err(dev, "MHI state change to %s from %s is not allowed!\n",
0036             mhi_state_str(mhi_state),
0037             mhi_state_str(mhi_cntrl->mhi_state));
0038         return -EACCES;
0039     }
0040 
0041     /* TODO: Add support for M1 and M2 states */
0042     if (mhi_state == MHI_STATE_M1 || mhi_state == MHI_STATE_M2) {
0043         dev_err(dev, "MHI state (%s) not supported\n", mhi_state_str(mhi_state));
0044         return -EOPNOTSUPP;
0045     }
0046 
0047     mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK, mhi_state);
0048     mhi_cntrl->mhi_state = mhi_state;
0049 
0050     if (mhi_state == MHI_STATE_READY)
0051         mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK, 1);
0052 
0053     if (mhi_state == MHI_STATE_SYS_ERR)
0054         mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_SYSERR_MASK, 1);
0055 
0056     return 0;
0057 }
0058 
0059 int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl)
0060 {
0061     struct device *dev = &mhi_cntrl->mhi_dev->dev;
0062     enum mhi_state old_state;
0063     int ret;
0064 
0065     /* If MHI is in M3, resume suspended channels */
0066     spin_lock_bh(&mhi_cntrl->state_lock);
0067     old_state = mhi_cntrl->mhi_state;
0068     if (old_state == MHI_STATE_M3)
0069         mhi_ep_resume_channels(mhi_cntrl);
0070 
0071     ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M0);
0072     spin_unlock_bh(&mhi_cntrl->state_lock);
0073 
0074     if (ret) {
0075         mhi_ep_handle_syserr(mhi_cntrl);
0076         return ret;
0077     }
0078 
0079     /* Signal host that the device moved to M0 */
0080     ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0);
0081     if (ret) {
0082         dev_err(dev, "Failed sending M0 state change event\n");
0083         return ret;
0084     }
0085 
0086     if (old_state == MHI_STATE_READY) {
0087         /* Send AMSS EE event to host */
0088         ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS);
0089         if (ret) {
0090             dev_err(dev, "Failed sending AMSS EE event\n");
0091             return ret;
0092         }
0093     }
0094 
0095     return 0;
0096 }
0097 
0098 int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
0099 {
0100     struct device *dev = &mhi_cntrl->mhi_dev->dev;
0101     int ret;
0102 
0103     spin_lock_bh(&mhi_cntrl->state_lock);
0104     ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
0105     spin_unlock_bh(&mhi_cntrl->state_lock);
0106 
0107     if (ret) {
0108         mhi_ep_handle_syserr(mhi_cntrl);
0109         return ret;
0110     }
0111 
0112     mhi_ep_suspend_channels(mhi_cntrl);
0113 
0114     /* Signal host that the device moved to M3 */
0115     ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3);
0116     if (ret) {
0117         dev_err(dev, "Failed sending M3 state change event\n");
0118         return ret;
0119     }
0120 
0121     return 0;
0122 }
0123 
0124 int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)
0125 {
0126     struct device *dev = &mhi_cntrl->mhi_dev->dev;
0127     enum mhi_state mhi_state;
0128     int ret, is_ready;
0129 
0130     spin_lock_bh(&mhi_cntrl->state_lock);
0131     /* Ensure that the MHISTATUS is set to RESET by host */
0132     mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK);
0133     is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK);
0134 
0135     if (mhi_state != MHI_STATE_RESET || is_ready) {
0136         dev_err(dev, "READY state transition failed. MHI host not in RESET state\n");
0137         spin_unlock_bh(&mhi_cntrl->state_lock);
0138         return -EIO;
0139     }
0140 
0141     ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY);
0142     spin_unlock_bh(&mhi_cntrl->state_lock);
0143 
0144     if (ret)
0145         mhi_ep_handle_syserr(mhi_cntrl);
0146 
0147     return ret;
0148 }