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