brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · fd200b2 Raw
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