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