summaryrefslogtreecommitdiff
path: root/sys/src/9/ppc/saturntimer.c
blob: 2b9ef66ccef8873e2d3c61cf7a07b043151cfe08 (plain)
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
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "msaturn.h"

enum {
	Timer_ctrl = Saturn + 0x0106,
	Timer0_load = Saturn + 0x0200,
	Timer0_cnt = Saturn + 0x0204,
	Timer1_load = Saturn + 0x0300,
	Timer1_cnt = Saturn + 0x0304,
	
	T0_event = RBIT(13, ushort),
	T0_ie = RBIT(14, ushort),
	T0_cen = RBIT(15, ushort),
	T1_event = RBIT(5, ushort),
	T1_ie = RBIT(6, ushort),
	T1_cen = RBIT(7, ushort),
};

static ulong ticks;
static Lock tlock;
static ushort timer_ctl;

void
saturntimerintr(Ureg *u, void*)
{
	ushort ctl = *(ushort*)Timer_ctrl, v = 0;

	if(ctl&T1_event){
		v = T1_event;
		ticks++;
	}
		
	*(ushort*)Timer_ctrl = timer_ctl|T0_event|v;
	intack();
	timerintr(u, 0);
}

void
timerinit(void)
{
	*(ushort*)Timer_ctrl = 0;
	*(ulong*)Timer0_load = m->bushz  / HZ;
	*(ulong*)Timer0_cnt = m->bushz / HZ;
	*(ulong*)Timer1_load = m->bushz;
	*(ulong*)Timer1_cnt = m->bushz;

	intrenable(Vectimer0, saturntimerintr, nil, "timer");

	timer_ctl = T0_cen|T0_ie|T1_cen;
	*(ushort*)Timer_ctrl = timer_ctl;
}

uvlong
fastticks(uvlong *hz)
{
	assert(*(ushort*)Timer_ctrl&T1_cen);
	if(*(ushort*)Timer_ctrl&T1_event){
		*(ushort*)Timer_ctrl = timer_ctl|T1_event;
		ticks++;
	}
		
	if (hz)
		*hz = m->bushz;

	return (uvlong)ticks*m->bushz+(uvlong)(m->bushz-*(ulong*)Timer1_cnt);
}

void
timerset(uvlong next)
{
	ulong offset;
	uvlong now;

	ilock(&tlock);
	*(ushort*)Timer_ctrl = T1_cen;

	now = fastticks(nil);
	offset = next - now;
	if((long)offset < 10000)
		offset = 10000;
	else if(offset > m->bushz)
		offset = m->bushz;

	*(ulong*)Timer0_cnt = offset;
	*(ushort*)Timer_ctrl = timer_ctl;
	assert(*(ushort*)Timer_ctrl & T1_cen);
	iunlock(&tlock);
}