1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <isr.h>
19 #include <platform.h>
20
21 #include <plat/cmsis.h>
22 #include <plat/exti.h>
23 #include <plat/pwr.h>
24
25 struct StmExti
26 {
27 volatile uint32_t IMR;
28 volatile uint32_t EMR;
29 volatile uint32_t RTSR;
30 volatile uint32_t FTSR;
31 volatile uint32_t SWIER;
32 volatile uint32_t PR;
33 };
34
35 #define EXTI ((struct StmExti*)EXTI_BASE)
36
extiEnableIntLine(const enum ExtiLine line,enum ExtiTrigger trigger)37 void extiEnableIntLine(const enum ExtiLine line, enum ExtiTrigger trigger)
38 {
39 if (trigger == EXTI_TRIGGER_BOTH) {
40 EXTI->RTSR |= (1UL << line);
41 EXTI->FTSR |= (1UL << line);
42 } else if (trigger == EXTI_TRIGGER_RISING) {
43 EXTI->RTSR |= (1UL << line);
44 EXTI->FTSR &= ~(1UL << line);
45 } else if (trigger == EXTI_TRIGGER_FALLING) {
46 EXTI->RTSR &= ~(1UL << line);
47 EXTI->FTSR |= (1UL << line);
48 }
49
50 /* Clear pending interrupt */
51 extiClearPendingLine(line);
52
53 /* Enable hardware interrupt */
54 EXTI->IMR |= (1UL << line);
55 }
56
extiDisableIntLine(const enum ExtiLine line)57 void extiDisableIntLine(const enum ExtiLine line)
58 {
59 EXTI->IMR &= ~(1UL << line);
60 }
61
extiClearPendingLine(const enum ExtiLine line)62 void extiClearPendingLine(const enum ExtiLine line)
63 {
64 EXTI->PR = (1UL << line);
65 }
66
extiIsPendingLine(const enum ExtiLine line)67 bool extiIsPendingLine(const enum ExtiLine line)
68 {
69 return (EXTI->PR & (1UL << line)) ? true : false;
70 }
71
72 struct ExtiInterrupt
73 {
74 struct ChainedInterrupt base;
75 IRQn_Type irq;
76 };
77
extiInterruptEnable(struct ChainedInterrupt * irq)78 static void extiInterruptEnable(struct ChainedInterrupt *irq)
79 {
80 struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
81 NVIC_EnableIRQ(exti->irq);
82 }
83
extiInterruptDisable(struct ChainedInterrupt * irq)84 static void extiInterruptDisable(struct ChainedInterrupt *irq)
85 {
86 struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
87 NVIC_DisableIRQ(exti->irq);
88 }
89
90 #define DECLARE_SHARED_EXTI(i) { \
91 .base = { \
92 .enable = extiInterruptEnable, \
93 .disable = extiInterruptDisable, \
94 }, \
95 .irq = i, \
96 }
97
98 uint32_t mMaxLatency = 0;
99
100 static struct ExtiInterrupt mInterrupts[] = {
101 DECLARE_SHARED_EXTI(EXTI0_IRQn),
102 DECLARE_SHARED_EXTI(EXTI1_IRQn),
103 DECLARE_SHARED_EXTI(EXTI2_IRQn),
104 DECLARE_SHARED_EXTI(EXTI3_IRQn),
105 DECLARE_SHARED_EXTI(EXTI4_IRQn),
106 DECLARE_SHARED_EXTI(EXTI9_5_IRQn),
107 DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
108 };
109
extiUpdateMaxLatency(uint32_t maxLatencyNs)110 static void extiUpdateMaxLatency(uint32_t maxLatencyNs)
111 {
112 if (!maxLatencyNs && mMaxLatency)
113 platReleaseDevInSleepMode(Stm32sleepDevExti);
114 else if (maxLatencyNs && !mMaxLatency)
115 platRequestDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
116 else if (maxLatencyNs && mMaxLatency)
117 platAdjustDevInSleepMode(Stm32sleepDevExti, maxLatencyNs);
118 mMaxLatency = maxLatencyNs;
119 }
120
extiCalcMaxLatency()121 static void extiCalcMaxLatency()
122 {
123 int i;
124 uint32_t maxLatency, newMaxLatency = 0;
125 struct ExtiInterrupt *exti = mInterrupts;
126
127 for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti) {
128 maxLatency = maxLatencyIsr(&exti->base);
129 if (!newMaxLatency || (maxLatency && maxLatency < newMaxLatency))
130 newMaxLatency = maxLatency;
131 }
132 extiUpdateMaxLatency(newMaxLatency);
133 }
134
extiForIrq(IRQn_Type n)135 static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
136 {
137 if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
138 return &mInterrupts[n - EXTI0_IRQn];
139 if (n == EXTI9_5_IRQn)
140 return &mInterrupts[ARRAY_SIZE(mInterrupts) - 2];
141 if (n == EXTI15_10_IRQn)
142 return &mInterrupts[ARRAY_SIZE(mInterrupts) - 1];
143 return NULL;
144 }
145
extiIrqHandler(IRQn_Type n)146 static void extiIrqHandler(IRQn_Type n)
147 {
148 struct ExtiInterrupt *exti = extiForIrq(n);
149 dispatchIsr(&exti->base);
150 }
151
152 #define DEFINE_SHARED_EXTI_ISR(i) \
153 void EXTI##i##_IRQHandler(void); \
154 void EXTI##i##_IRQHandler(void) { \
155 extiIrqHandler(EXTI##i##_IRQn); \
156 } \
157
158 DEFINE_SHARED_EXTI_ISR(0)
159 DEFINE_SHARED_EXTI_ISR(1)
160 DEFINE_SHARED_EXTI_ISR(2)
161 DEFINE_SHARED_EXTI_ISR(3)
162 DEFINE_SHARED_EXTI_ISR(4)
163 DEFINE_SHARED_EXTI_ISR(9_5)
164 DEFINE_SHARED_EXTI_ISR(15_10)
165
extiSetMaxLatency(struct ChainedIsr * isr,uint32_t maxLatencyNs)166 int extiSetMaxLatency(struct ChainedIsr *isr, uint32_t maxLatencyNs)
167 {
168 uint32_t latency;
169
170 if (!isr)
171 return -EINVAL;
172
173 if (maxLatencyNs != isr->maxLatencyNs) {
174 latency = isr->maxLatencyNs;
175 isr->maxLatencyNs = maxLatencyNs;
176 if (!mMaxLatency || latency == mMaxLatency || (maxLatencyNs && maxLatencyNs < mMaxLatency)) {
177 extiCalcMaxLatency();
178 }
179 }
180
181 return 0;
182 }
183
extiChainIsr(IRQn_Type n,struct ChainedIsr * isr)184 int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
185 {
186 struct ExtiInterrupt *exti = extiForIrq(n);
187 if (!exti)
188 return -EINVAL;
189 else if (!list_is_empty(&isr->node))
190 return -EINVAL;
191
192 chainIsr(&exti->base, isr);
193 if (!mMaxLatency || (isr->maxLatencyNs && isr->maxLatencyNs < mMaxLatency))
194 extiUpdateMaxLatency(isr->maxLatencyNs);
195
196 return 0;
197 }
198
extiUnchainIsr(IRQn_Type n,struct ChainedIsr * isr)199 int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
200 {
201 struct ExtiInterrupt *exti = extiForIrq(n);
202 if (!exti)
203 return -EINVAL;
204 else if (list_is_empty(&isr->node))
205 return -EINVAL;
206
207 unchainIsr(&exti->base, isr);
208 if (isr->maxLatencyNs && isr->maxLatencyNs == mMaxLatency)
209 extiCalcMaxLatency();
210 return 0;
211 }
212
extiUnchainAll(uint32_t tid)213 int extiUnchainAll(uint32_t tid)
214 {
215 int i, count = 0;
216 struct ExtiInterrupt *exti = mInterrupts;
217
218 for (i = 0; i < ARRAY_SIZE(mInterrupts); ++i, ++exti)
219 count += unchainIsrAll(&exti->base, tid);
220 extiCalcMaxLatency();
221
222 return count;
223 }
224