1 /*
2  * Copyright (c) 2012-2013 Travis Geiselbrecht
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 #ifndef __ARCH_ARM_CM_H
9 #define __ARCH_ARM_CM_H
10 
11 /* support header for all cortex-m class cpus */
12 
13 #include <lk/compiler.h>
14 #include <stdint.h>
15 #include <stdbool.h>
16 #include <sys/types.h>
17 #include <platform/platform_cm.h>
18 
19 #if ARM_CPU_CORTEX_M0
20 #include <core_cm0.h>
21 #elif ARM_CPU_CORTEX_M0_PLUS
22 #include <core_cm0plus.h>
23 #elif ARM_CPU_CORTEX_M3
24 #include <core_cm3.h>
25 #elif ARM_CPU_CORTEX_M4
26 #include <core_cm4.h>
27 #elif ARM_CPU_CORTEX_M7
28 #include <core_cm7.h>
29 #else
30 #error "unknown cortex-m core"
31 #endif
32 
33 /* registers dealing with the cycle counter */
34 #define DWT_CTRL (0xE0001000)
35 #define DWT_CYCCNT (0xE0001004)
36 #define SCB_DEMCR (0xE000EDFC)
37 
38 struct arm_cm_exception_frame {
39     uint32_t r4;
40     uint32_t r5;
41     uint32_t r6;
42     uint32_t r7;
43     uint32_t r8;
44     uint32_t r9;
45     uint32_t r10;
46     uint32_t r11;
47     uint32_t r0;
48     uint32_t r1;
49     uint32_t r2;
50     uint32_t r3;
51     uint32_t r12;
52     uint32_t lr;
53     uint32_t pc;
54     uint32_t psr;
55 };
56 
57 struct arm_cm_exception_frame_short {
58     uint32_t r0;
59     uint32_t r1;
60     uint32_t r2;
61     uint32_t r3;
62     uint32_t r12;
63     uint32_t lr;
64     uint32_t pc;
65     uint32_t psr;
66 };
67 
68 struct arm_cm_exception_frame_long {
69     uint32_t r4;
70     uint32_t r5;
71     uint32_t r6;
72     uint32_t r7;
73     uint32_t r8;
74     uint32_t r9;
75     uint32_t r10;
76     uint32_t r11;
77     uint32_t lr;
78     uint32_t r0;
79     uint32_t r1;
80     uint32_t r2;
81     uint32_t r3;
82     uint32_t r12;
83     uint32_t exc_lr;
84     uint32_t pc;
85     uint32_t psr;
86 };
87 
88 /* when fpu context save is enabled, this goes just above psr in the previous structs */
89 struct arm_cm_exception_frame_fpu {
90     float    s[16];
91     uint32_t fpscr;
92 };
93 
94 #if ARM_CM_DYNAMIC_PRIORITY_SIZE
95 extern unsigned int arm_cm_num_irq_pri_bits;
96 extern unsigned int arm_cm_irq_pri_mask;
97 #else
98 /* if we don't want to calculate the number of priority bits, then assume
99  * the cpu implements 3 (8 priority levels), which is the minimum according to spec.
100  */
101 #ifndef __NVIC_PRIO_BITS
102 #define __NVIC_PRIO_BITS 3
103 #endif
104 static const unsigned int arm_cm_num_irq_pri_bits = __NVIC_PRIO_BITS;
105 static const unsigned int arm_cm_irq_pri_mask = ~((1 << __NVIC_PRIO_BITS) - 1) & 0xff;
106 #endif
107 
108 #if     (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
109 
110 void _arm_cm_set_irqpri(uint32_t pri);
111 
arm_cm_set_irqpri(uint32_t pri)112 static void arm_cm_set_irqpri(uint32_t pri) {
113     if (__ISCONSTANT(pri)) {
114         if (pri == 0) {
115             __disable_irq(); // cpsid i
116             __set_BASEPRI(0);
117         } else if (pri >= 256) {
118             __set_BASEPRI(0);
119             __enable_irq();
120         } else {
121             uint32_t _pri = pri & arm_cm_irq_pri_mask;
122 
123             if (_pri == 0)
124                 __set_BASEPRI(1 << (8 - arm_cm_num_irq_pri_bits));
125             else
126                 __set_BASEPRI(_pri);
127             __enable_irq(); // cpsie i
128         }
129     } else {
130         _arm_cm_set_irqpri(pri);
131     }
132 }
133 #endif
134 
arm_cm_highest_priority(void)135 static inline uint32_t arm_cm_highest_priority(void) {
136     return 0;
137 }
138 
arm_cm_lowest_priority(void)139 static inline uint32_t arm_cm_lowest_priority(void) {
140     return (1 << arm_cm_num_irq_pri_bits) - 1;
141 }
142 
arm_cm_medium_priority(void)143 static inline uint32_t arm_cm_medium_priority(void) {
144     return (1 << (arm_cm_num_irq_pri_bits - 1));
145 }
146 
147 #if     (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
arm_cm_trigger_interrupt(int vector)148 static inline void arm_cm_trigger_interrupt(int vector) {
149     NVIC->STIR = vector;
150 }
151 #endif
152 
153 
arm_cm_trigger_preempt(void)154 static inline void arm_cm_trigger_preempt(void) {
155     SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
156 }
157 
158 
159 
160 /* systick */
161 void arm_cm_systick_init(uint32_t mhz);
162 
163 /* interrupt glue */
164 /*
165  * Platform code should put this as the first and last line of their irq handlers.
166  * Pass true to reschedule to request a preempt.
167  */
168 void arm_cm_irq_entry(void);
169 void arm_cm_irq_exit(bool reschedule);
170 
171 /* built in exception vectors */
172 void _start(void);
173 void _nmi(void);
174 void _hardfault(void);
175 void _memmanage(void);
176 void _busfault(void);
177 void _usagefault(void);
178 void _svc(void);
179 void _debugmonitor(void);
180 void _pendsv(void);
181 void _systick(void);
182 
183 #endif
184 
185