0
|
1 // ARM dual-timer module support (SP804)
|
|
2 #include "types.h"
|
|
3 #include "param.h"
|
|
4 #include "arm.h"
|
|
5 #include "mmu.h"
|
|
6 #include "defs.h"
|
|
7 #include "memlayout.h"
|
|
8 #include "spinlock.h"
|
|
9
|
|
10 // A SP804 has two timers, we only use the first one, and as perodic timer
|
|
11
|
|
12 // define registers (in units of 4-bytes)
|
|
13 #define TIMER_LOAD 0 // load register, for perodic timer
|
|
14 #define TIMER_CURVAL 1 // current value of the counter
|
|
15 #define TIMER_CONTROL 2 // control register
|
|
16 #define TIMER_INTCLR 3 // clear (ack) the interrupt (any write clear it)
|
|
17 #define TIMER_MIS 5 // masked interrupt status
|
|
18
|
|
19 // control register bit definitions
|
|
20 #define TIMER_ONESHOT 0x01 // wrap or one shot
|
|
21 #define TIMER_32BIT 0x02 // 16-bit/32-bit counter
|
|
22 #define TIMER_INTEN 0x20 // enable/disable interrupt
|
|
23 #define TIMER_PERIODIC 0x40 // enable periodic mode
|
|
24 #define TIMER_EN 0x80 // enable the timer
|
|
25
|
|
26 void isr_timer (struct trapframe *tp, int irq_idx);
|
|
27
|
|
28 struct spinlock tickslock;
|
|
29 uint ticks;
|
|
30
|
|
31 // acknowledge the timer, write any value to TIMER_INTCLR should do
|
|
32 static void ack_timer ()
|
|
33 {
|
|
34 volatile uint * timer0 = P2V(TIMER0);
|
|
35 timer0[TIMER_INTCLR] = 1;
|
|
36 }
|
|
37
|
|
38 // initialize the timer: perodical and interrupt based
|
|
39 void timer_init(int hz)
|
|
40 {
|
|
41 volatile uint * timer0 = P2V(TIMER0);
|
|
42
|
|
43 initlock(&tickslock, "time");
|
|
44
|
|
45 timer0[TIMER_LOAD] = CLK_HZ / hz;
|
|
46 timer0[TIMER_CONTROL] = TIMER_EN|TIMER_PERIODIC|TIMER_32BIT|TIMER_INTEN;
|
|
47
|
|
48 pic_enable (PIC_TIMER01, isr_timer);
|
|
49 }
|
|
50
|
|
51 // interrupt service routine for the timer
|
|
52 void isr_timer (struct trapframe *tp, int irq_idx)
|
|
53 {
|
|
54 acquire(&tickslock);
|
|
55 ticks++;
|
|
56 wakeup(&ticks);
|
|
57 release(&tickslock);
|
|
58 ack_timer();
|
|
59 }
|
|
60
|
|
61 // a short delay, use timer 1 as the source
|
|
62 void micro_delay (int us)
|
|
63 {
|
|
64 volatile uint * timer1 = P2V(TIMER1);
|
|
65
|
|
66 // load the initial value to timer1, and configure it to be freerun
|
|
67 timer1[TIMER_CONTROL] = TIMER_EN | TIMER_32BIT;
|
|
68 timer1[TIMER_LOAD] = us;
|
|
69
|
|
70 // the register will wrap to 0xFFFFFFFF after decrement to 0
|
|
71 while ((int)timer1[TIMER_CURVAL] > 0) {
|
|
72
|
|
73 }
|
|
74
|
|
75 // disable timer
|
|
76 timer1[TIMER_CONTROL] = 0;
|
|
77 }
|