xref: /plan9/sys/src/9/ppc/saturntimer.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "io.h"
7458db832SDavid du Colombier #include "../port/error.h"
8458db832SDavid du Colombier #include "msaturn.h"
9458db832SDavid du Colombier 
10458db832SDavid du Colombier enum {
11458db832SDavid du Colombier 	Timer_ctrl = Saturn + 0x0106,
12458db832SDavid du Colombier 	Timer0_load = Saturn + 0x0200,
13458db832SDavid du Colombier 	Timer0_cnt = Saturn + 0x0204,
14458db832SDavid du Colombier 	Timer1_load = Saturn + 0x0300,
15458db832SDavid du Colombier 	Timer1_cnt = Saturn + 0x0304,
16458db832SDavid du Colombier 
17458db832SDavid du Colombier 	T0_event = RBIT(13, ushort),
18458db832SDavid du Colombier 	T0_ie = RBIT(14, ushort),
19458db832SDavid du Colombier 	T0_cen = RBIT(15, ushort),
20458db832SDavid du Colombier 	T1_event = RBIT(5, ushort),
21458db832SDavid du Colombier 	T1_ie = RBIT(6, ushort),
22458db832SDavid du Colombier 	T1_cen = RBIT(7, ushort),
23458db832SDavid du Colombier };
24458db832SDavid du Colombier 
25458db832SDavid du Colombier static ulong ticks;
26458db832SDavid du Colombier static Lock tlock;
27458db832SDavid du Colombier static ushort timer_ctl;
28458db832SDavid du Colombier 
29*5d9de2d3SDavid du Colombier ulong multiplier;
30*5d9de2d3SDavid du Colombier 
31*5d9de2d3SDavid du Colombier ulong
s(void)32*5d9de2d3SDavid du Colombier µs(void)
33*5d9de2d3SDavid du Colombier {
34*5d9de2d3SDavid du Colombier 	uvlong x;
35*5d9de2d3SDavid du Colombier 
36*5d9de2d3SDavid du Colombier 	if(multiplier == 0){
37*5d9de2d3SDavid du Colombier 		multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq;
38*5d9de2d3SDavid du Colombier 		print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16);
39*5d9de2d3SDavid du Colombier 	}
40*5d9de2d3SDavid du Colombier 	cycles(&x);
41*5d9de2d3SDavid du Colombier 	return (x*multiplier) >> 16;
42*5d9de2d3SDavid du Colombier }
43*5d9de2d3SDavid du Colombier 
44458db832SDavid du Colombier void
saturntimerintr(Ureg * u,void *)45458db832SDavid du Colombier saturntimerintr(Ureg *u, void*)
46458db832SDavid du Colombier {
47458db832SDavid du Colombier 	ushort ctl = *(ushort*)Timer_ctrl, v = 0;
48458db832SDavid du Colombier 
49458db832SDavid du Colombier 	if(ctl&T1_event){
50458db832SDavid du Colombier 		v = T1_event;
51458db832SDavid du Colombier 		ticks++;
52458db832SDavid du Colombier 	}
53458db832SDavid du Colombier 
54458db832SDavid du Colombier 	*(ushort*)Timer_ctrl = timer_ctl|T0_event|v;
55458db832SDavid du Colombier 	intack();
56458db832SDavid du Colombier 	timerintr(u, 0);
57458db832SDavid du Colombier }
58458db832SDavid du Colombier 
59458db832SDavid du Colombier void
timerinit(void)60458db832SDavid du Colombier timerinit(void)
61458db832SDavid du Colombier {
62458db832SDavid du Colombier 	*(ushort*)Timer_ctrl = 0;
63458db832SDavid du Colombier 	*(ulong*)Timer0_load = m->bushz  / HZ;
64458db832SDavid du Colombier 	*(ulong*)Timer0_cnt = m->bushz / HZ;
65458db832SDavid du Colombier 	*(ulong*)Timer1_load = m->bushz;
66458db832SDavid du Colombier 	*(ulong*)Timer1_cnt = m->bushz;
67fe853e23SDavid du Colombier 
68458db832SDavid du Colombier 	intrenable(Vectimer0, saturntimerintr, nil, "timer");
69458db832SDavid du Colombier 
70458db832SDavid du Colombier 	timer_ctl = T0_cen|T0_ie|T1_cen;
71458db832SDavid du Colombier 	*(ushort*)Timer_ctrl = timer_ctl;
72458db832SDavid du Colombier }
73458db832SDavid du Colombier 
74458db832SDavid du Colombier uvlong
fastticks(uvlong * hz)75458db832SDavid du Colombier fastticks(uvlong *hz)
76458db832SDavid du Colombier {
77458db832SDavid du Colombier 	assert(*(ushort*)Timer_ctrl&T1_cen);
78458db832SDavid du Colombier 	if(*(ushort*)Timer_ctrl&T1_event){
79458db832SDavid du Colombier 		*(ushort*)Timer_ctrl = timer_ctl|T1_event;
80458db832SDavid du Colombier 		ticks++;
81458db832SDavid du Colombier 	}
82458db832SDavid du Colombier 
83458db832SDavid du Colombier 	if (hz)
84458db832SDavid du Colombier 		*hz = m->bushz;
85458db832SDavid du Colombier 
86458db832SDavid du Colombier 	return (uvlong)ticks*m->bushz+(uvlong)(m->bushz-*(ulong*)Timer1_cnt);
87458db832SDavid du Colombier }
88458db832SDavid du Colombier 
89458db832SDavid du Colombier void
timerset(Tval next)90*5d9de2d3SDavid du Colombier timerset(Tval next)
91458db832SDavid du Colombier {
92458db832SDavid du Colombier 	ulong offset;
93458db832SDavid du Colombier 	uvlong now;
94458db832SDavid du Colombier 
95458db832SDavid du Colombier 	ilock(&tlock);
96458db832SDavid du Colombier 	*(ushort*)Timer_ctrl = T1_cen;
97458db832SDavid du Colombier 
98458db832SDavid du Colombier 	now = fastticks(nil);
99458db832SDavid du Colombier 	offset = next - now;
100fe853e23SDavid du Colombier 	if((long)offset < 10000)
101fe853e23SDavid du Colombier 		offset = 10000;
102458db832SDavid du Colombier 	else if(offset > m->bushz)
103458db832SDavid du Colombier 		offset = m->bushz;
104458db832SDavid du Colombier 
105458db832SDavid du Colombier 	*(ulong*)Timer0_cnt = offset;
106458db832SDavid du Colombier 	*(ushort*)Timer_ctrl = timer_ctl;
107458db832SDavid du Colombier 	assert(*(ushort*)Timer_ctrl & T1_cen);
108458db832SDavid du Colombier 	iunlock(&tlock);
109458db832SDavid du Colombier }
110458db832SDavid du Colombier 
111