1 /*
2  * Copyright (c) 2017 The Fuchsia Authors.
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <platform/exti.h>
10 
11 #include <arch/arm/cm.h>
12 #include <assert.h>
13 #include <lk/compiler.h>
14 #include <platform/rcc.h>
15 #include <stdint.h>
16 
stm32_exti0_irq(void)17 bool __WEAK stm32_exti0_irq(void) {
18     return false;
19 }
20 
stm32_exti1_irq(void)21 bool __WEAK stm32_exti1_irq(void) {
22     return false;
23 }
24 
stm32_exti2_irq(void)25 bool __WEAK stm32_exti2_irq(void) {
26     return false;
27 }
28 
stm32_exti3_irq(void)29 bool __WEAK stm32_exti3_irq(void) {
30     return false;
31 }
32 
stm32_exti4_irq(void)33 bool __WEAK stm32_exti4_irq(void) {
34     return false;
35 }
36 
stm32_exti5_irq(void)37 bool __WEAK stm32_exti5_irq(void) {
38     return false;
39 }
40 
stm32_exti6_irq(void)41 bool __WEAK stm32_exti6_irq(void) {
42     return false;
43 }
44 
stm32_exti7_irq(void)45 bool __WEAK stm32_exti7_irq(void) {
46     return false;
47 }
48 
stm32_exti8_irq(void)49 bool __WEAK stm32_exti8_irq(void) {
50     return false;
51 }
52 
stm32_exti9_irq(void)53 bool __WEAK stm32_exti9_irq(void) {
54     return false;
55 }
56 
stm32_exti10_irq(void)57 bool __WEAK stm32_exti10_irq(void) {
58     return false;
59 }
60 
stm32_exti11_irq(void)61 bool __WEAK stm32_exti11_irq(void) {
62     return false;
63 }
64 
stm32_exti12_irq(void)65 bool __WEAK stm32_exti12_irq(void) {
66     return false;
67 }
68 
stm32_exti13_irq(void)69 bool __WEAK stm32_exti13_irq(void) {
70     return false;
71 }
72 
stm32_exti14_irq(void)73 bool __WEAK stm32_exti14_irq(void) {
74     return false;
75 }
76 
stm32_exti15_irq(void)77 bool __WEAK stm32_exti15_irq(void) {
78     return false;
79 }
80 
81 #define STM32_DISPATCH_EXTI(pr, irq, resched) do { \
82     if ((pr) & (1 << (irq))) { \
83         resched |= stm32_exti ## irq ## _irq(); \
84     } \
85  } while(0)
86 
stm32_EXTI0_1_IRQ(void)87 void stm32_EXTI0_1_IRQ(void) {
88     arm_cm_irq_entry();
89 
90     uint32_t pr = EXTI->PR & 0x3;
91     EXTI->PR = pr;
92 
93     bool resched = false;
94     STM32_DISPATCH_EXTI(pr, 0, resched);
95     STM32_DISPATCH_EXTI(pr, 1, resched);
96 
97     arm_cm_irq_exit(resched);
98 }
99 
stm32_EXTI2_3_IRQ(void)100 void stm32_EXTI2_3_IRQ(void) {
101     arm_cm_irq_entry();
102 
103     uint32_t pr = EXTI->PR & (0x3 << 2);
104     EXTI->PR = pr;
105 
106     bool resched = false;
107     STM32_DISPATCH_EXTI(pr, 2, resched);
108     STM32_DISPATCH_EXTI(pr, 3, resched);
109 
110     arm_cm_irq_exit(resched);
111 }
112 
stm32_EXTI4_15_IRQ(void)113 void stm32_EXTI4_15_IRQ(void) {
114     arm_cm_irq_entry();
115 
116     uint32_t pr = EXTI->PR & 0xfff0U;
117     EXTI->PR = pr;
118 
119     bool resched = false;
120     STM32_DISPATCH_EXTI(pr, 4, resched);
121     STM32_DISPATCH_EXTI(pr, 5, resched);
122     STM32_DISPATCH_EXTI(pr, 6, resched);
123     STM32_DISPATCH_EXTI(pr, 7, resched);
124     STM32_DISPATCH_EXTI(pr, 8, resched);
125     STM32_DISPATCH_EXTI(pr, 9, resched);
126     STM32_DISPATCH_EXTI(pr, 10, resched);
127     STM32_DISPATCH_EXTI(pr, 11, resched);
128     STM32_DISPATCH_EXTI(pr, 12, resched);
129     STM32_DISPATCH_EXTI(pr, 13, resched);
130     STM32_DISPATCH_EXTI(pr, 14, resched);
131     STM32_DISPATCH_EXTI(pr, 15, resched);
132 
133     arm_cm_irq_exit(resched);
134 }
135 
136 #undef STM32_DISPATCH_EXTI
137 
stm32_setup_ext_interrupt(int interrupt,stm32_ext_interrupt_port_t port,bool rising_edge,bool falling_edge)138 void stm32_setup_ext_interrupt(int interrupt, stm32_ext_interrupt_port_t port,
139                                bool rising_edge, bool falling_edge) {
140     assert(0 <= interrupt && interrupt <= 15);
141 
142     stm32_rcc_set_enable(STM32_RCC_CLK_SYSCFGCOMP, true);
143 
144     uint32_t cfg = SYSCFG->EXTICR[interrupt >> 2];
145     uint shift = 4 * (interrupt & 0x3);
146     cfg &= SYSCFG_EXTICR1_EXTI0 << shift;
147     cfg |= port << shift;
148     SYSCFG->EXTICR[interrupt >> 2] = cfg;
149 
150     if (rising_edge) {
151         EXTI->RTSR |= 1 << interrupt;
152     } else {
153         EXTI->RTSR &= ~(1 << interrupt);
154     }
155 
156     if (falling_edge) {
157         EXTI->FTSR |= 1 << interrupt;
158     } else {
159         EXTI->FTSR &= ~(1 << interrupt);
160     }
161 
162     EXTI->IMR |= 1 << interrupt;
163     EXTI->PR = 1 << interrupt;
164 
165     if (0 <= interrupt && interrupt <= 1) {
166         NVIC_EnableIRQ(EXTI0_1_IRQn);
167     } else if (2 <= interrupt && interrupt <= 3) {
168         NVIC_EnableIRQ(EXTI2_3_IRQn);
169     } else if (4 <= interrupt && interrupt <= 15) {
170         NVIC_EnableIRQ(EXTI4_15_IRQn);
171     }
172 }
173