forked from NienfengYao/armv8-bare-metal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
timer.c
136 lines (118 loc) · 3.19 KB
/
timer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <stdint.h>
#include "aarch64.h"
#include "board.h"
#include "gic_v3.h"
#include "uart.h"
#include "timer.h"
#define TIMER_DEBUG 0
#define TIMER_WAIT 1 /* Assert Timer IRQ after n secs */
static uint32_t cntfrq; /* System frequency */
#if TIMER_DEBUG
void timer_handler(void){}
#else
/* Assert Timer IRQ after n secs */
void timer_handler(void)
{
uint64_t ticks, current_cnt;
uint32_t val;
uart_puts("timer_handler: \n");
// Disable the timer
disable_cntv();
uart_puts("\tDisable the timer, CNTV_CTL_EL0 = ");
val = raw_read_cntv_ctl();
uart_puthex(val);
gicd_clear_pending(TIMER_IRQ);
uart_puts("\n\tSystem Frequency: CNTFRQ_EL0 = ");
uart_puthex(cntfrq);
// Next timer IRQ is after n sec.
ticks = TIMER_WAIT * cntfrq;
// Get value of the current timer
current_cnt = raw_read_cntvct_el0();
uart_puts("\n\tCurrent counter: CNTVCT_EL0 = ");
uart_puthex(current_cnt);
// Set the interrupt in Current Time + TimerTick
raw_write_cntv_cval_el0(current_cnt + ticks);
uart_puts("\n\tAssert Timer IRQ after ");
uart_puthex(TIMER_WAIT);
uart_puts(" sec(s): CNTV_CVAL_EL0 = ");
val = raw_read_cntv_cval_el0();
uart_puthex(val);
// Enable the timer
enable_cntv();
uart_puts("\n\tEnable the timer, CNTV_CTL_EL0 = ");
val = raw_read_cntv_ctl();
uart_puthex(val);
uart_puts("\n");
}
#endif /* TIMER_DEBUG */
void timer_test(void)
{
uint32_t val;
uint64_t ticks, current_cnt;
uart_puts("timer_test\n");
// GIC Init
gic_v3_initialize();
uart_puts("CurrentEL = ");
val = raw_read_current_el();
uart_puthex(val);
uart_puts("\nRVBAR_EL1 = ");
val = raw_read_rvbar_el1();
uart_puthex(val);
uart_puts("\nVBAR_EL1 = ");
val = raw_read_vbar_el1();
uart_puthex(val);
uart_puts("\nDAIF = ");
val = raw_read_daif();
uart_puthex(val);
// Disable the timer
disable_cntv();
uart_puts("\nDisable the timer, CNTV_CTL_EL0 = ");
val = raw_read_cntv_ctl();
uart_puthex(val);
uart_puts("\nSystem Frequency: CNTFRQ_EL0 = ");
cntfrq = raw_read_cntfrq_el0();
uart_puthex(cntfrq);
// Next timer IRQ is after n sec(s).
ticks = TIMER_WAIT * cntfrq;
// Get value of the current timer
current_cnt = raw_read_cntvct_el0();
uart_puts("\nCurrent counter: CNTVCT_EL0 = ");
uart_puthex(current_cnt);
// Set the interrupt in Current Time + TimerTick
raw_write_cntv_cval_el0(current_cnt + ticks);
uart_puts("\nAssert Timer IRQ after 1 sec: CNTV_CVAL_EL0 = ");
val = raw_read_cntv_cval_el0();
uart_puthex(val);
// Enable the timer
enable_cntv();
uart_puts("\nEnable the timer, CNTV_CTL_EL0 = ");
val = raw_read_cntv_ctl();
uart_puthex(val);
// Enable IRQ
enable_irq();
uart_puts("\nEnable IRQ, DAIF = ");
val = raw_read_daif();
uart_puthex(val);
uart_puts("\n");
#if TIMER_DEBUG // Observe CNTP_CTL_EL0[2]: ISTATUS
while(1){
current_cnt = raw_read_cntvct_el0();
val = raw_read_cntv_ctl();
uart_puts("\nCNTVCT_EL0 = ");
uart_puthex(current_cnt);
uart_puts(", CNTV_CTL_EL0 = ");
uart_puthex(val);
val = raw_read_spsr_el1();
uart_puts(", SPSR_EL1 = ");
uart_puthex(val);
val = raw_read_isr_el1();
uart_puts(", ISR_EL1 = ");
uart_puthex(val);
uart_puts("\n");
}
#else
while(1){
wfi(); /* Wait for Interrupt */
}
#endif
}