Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/bus/mhi/ep/sm.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2022 Linaro Ltd.
4
* Author: Manivannan Sadhasivam <[email protected]>
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
/* 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
94
err_unlock:
95
mutex_unlock(&mhi_cntrl->state_lock);
96
97
return ret;
98
}
99
100
int 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
122
err_unlock:
123
mutex_unlock(&mhi_cntrl->state_lock);
124
125
return ret;
126
}
127
128
int 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
150
err_unlock:
151
mutex_unlock(&mhi_cntrl->state_lock);
152
153
return ret;
154
}
155
156