1 /*
2 * Copyright (c) 2012-2013 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #ifndef __ARCH_ARM_CM_H
24 #define __ARCH_ARM_CM_H
25
26 /* support header for all cortex-m class cpus */
27
28 #include <compiler.h>
29 #include <stdint.h>
30 #include <stdbool.h>
31 #include <sys/types.h>
32 #include <platform/platform_cm.h>
33
34 #if ARM_CPU_CORTEX_M0
35 #include <core_cm0.h>
36 #elif ARM_CPU_CORTEX_M0_PLUS
37 #include <core_cm0plus.h>
38 #elif ARM_CPU_CORTEX_M3
39 #include <core_cm3.h>
40 #elif ARM_CPU_CORTEX_M4
41 #include <core_cm4.h>
42 #elif ARM_CPU_CORTEX_M7
43 #include <core_cm7.h>
44 #else
45 #error "unknown cortex-m core"
46 #endif
47
48 /* registers dealing with the cycle counter */
49 #define DWT_CTRL (0xE0001000)
50 #define DWT_CYCCNT (0xE0001004)
51 #define SCB_DEMCR (0xE000EDFC)
52
53 struct arm_cm_exception_frame {
54 uint32_t r4;
55 uint32_t r5;
56 uint32_t r6;
57 uint32_t r7;
58 uint32_t r8;
59 uint32_t r9;
60 uint32_t r10;
61 uint32_t r11;
62 uint32_t r0;
63 uint32_t r1;
64 uint32_t r2;
65 uint32_t r3;
66 uint32_t r12;
67 uint32_t lr;
68 uint32_t pc;
69 uint32_t psr;
70 };
71
72 struct arm_cm_exception_frame_short {
73 uint32_t r0;
74 uint32_t r1;
75 uint32_t r2;
76 uint32_t r3;
77 uint32_t r12;
78 uint32_t lr;
79 uint32_t pc;
80 uint32_t psr;
81 };
82
83 struct arm_cm_exception_frame_long {
84 uint32_t r4;
85 uint32_t r5;
86 uint32_t r6;
87 uint32_t r7;
88 uint32_t r8;
89 uint32_t r9;
90 uint32_t r10;
91 uint32_t r11;
92 uint32_t lr;
93 uint32_t r0;
94 uint32_t r1;
95 uint32_t r2;
96 uint32_t r3;
97 uint32_t r12;
98 uint32_t exc_lr;
99 uint32_t pc;
100 uint32_t psr;
101 };
102
103 /* when fpu context save is enabled, this goes just above psr in the previous structs */
104 struct arm_cm_exception_frame_fpu {
105 float s[16];
106 uint32_t fpscr;
107 };
108
109 #if ARM_CM_DYNAMIC_PRIORITY_SIZE
110 extern unsigned int arm_cm_num_irq_pri_bits;
111 extern unsigned int arm_cm_irq_pri_mask;
112 #else
113 /* if we don't want to calculate the number of priority bits, then assume
114 * the cpu implements 3 (8 priority levels), which is the minimum according to spec.
115 */
116 #ifndef __NVIC_PRIO_BITS
117 #define __NVIC_PRIO_BITS 3
118 #endif
119 static const unsigned int arm_cm_num_irq_pri_bits = __NVIC_PRIO_BITS;
120 static const unsigned int arm_cm_irq_pri_mask = ~((1 << __NVIC_PRIO_BITS) - 1) & 0xff;
121 #endif
122
123 #if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
124
125 void _arm_cm_set_irqpri(uint32_t pri);
126
arm_cm_set_irqpri(uint32_t pri)127 static void arm_cm_set_irqpri(uint32_t pri)
128 {
129 if (__ISCONSTANT(pri)) {
130 if (pri == 0) {
131 __disable_irq(); // cpsid i
132 __set_BASEPRI(0);
133 } else if (pri >= 256) {
134 __set_BASEPRI(0);
135 __enable_irq();
136 } else {
137 uint32_t _pri = pri & arm_cm_irq_pri_mask;
138
139 if (_pri == 0)
140 __set_BASEPRI(1 << (8 - arm_cm_num_irq_pri_bits));
141 else
142 __set_BASEPRI(_pri);
143 __enable_irq(); // cpsie i
144 }
145 } else {
146 _arm_cm_set_irqpri(pri);
147 }
148 }
149 #endif
150
arm_cm_highest_priority(void)151 static inline uint32_t arm_cm_highest_priority(void)
152 {
153 return 0;
154 }
155
arm_cm_lowest_priority(void)156 static inline uint32_t arm_cm_lowest_priority(void)
157 {
158 return (1 << arm_cm_num_irq_pri_bits) - 1;
159 }
160
arm_cm_medium_priority(void)161 static inline uint32_t arm_cm_medium_priority(void)
162 {
163 return (1 << (arm_cm_num_irq_pri_bits - 1));
164 }
165
166 #if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
arm_cm_trigger_interrupt(int vector)167 static inline void arm_cm_trigger_interrupt(int vector)
168 {
169 NVIC->STIR = vector;
170 }
171 #endif
172
173
arm_cm_trigger_preempt(void)174 static inline void arm_cm_trigger_preempt(void)
175 {
176 SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
177 }
178
179
180
181 /* systick */
182 void arm_cm_systick_init(uint32_t mhz);
183 /* extern void _systick(void); // override this */
184
185 /* interrupt glue */
186 /*
187 * Platform code should put this as the first and last line of their irq handlers.
188 * Pass true to reschedule to request a preempt.
189 */
190 void arm_cm_irq_entry(void);
191 void arm_cm_irq_exit(bool reschedule);
192
193 #endif
194
195