summaryrefslogtreecommitdiff
path: root/sys/src/9/omap4/clock.c
blob: 3aa56467fb6a09943c6b0f2871ce9906f0ee41c1 (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
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
#include "u.h"
#include "ureg.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

extern uchar *periph;
ulong *global, *local;
enum {
	PERIPHCLK = 506965000,
	MaxPeriod = PERIPHCLK / (256 * 100),
	MinPeriod = MaxPeriod / 100,
} ;

void
globalclockinit(void)
{
	global = (ulong*) (periph + 0x200);
	local = (ulong*) (periph + 0x600);
	global[2] &= 0xFFFF00F0;
	global[0] = 0;
	global[1] = 0;
	global[2] |= 1;
}

void
cycles(uvlong *x)
{
	ulong hi, newhi, lo, *y;
	
	newhi = global[1];
	do{
		hi = newhi;
		lo = global[0];
	}while((newhi = global[1]) != hi);
	y = (ulong *) x;
	y[0] = lo;
	y[1] = hi;
}

uvlong
fastticks(uvlong *hz)
{
	uvlong ret;

	if(hz != nil)
		*hz = PERIPHCLK;
	cycles(&ret);
	return ret;
}

ulong
µs(void)
{
	return fastticks2us(fastticks(nil));
}


ulong
perfticks(void)
{
	return global[0];
}

void
clocktick(Ureg* ureg, void *)
{
	timerintr(ureg, 0);
}

void
localclockinit(void)
{
	local[2] = 0xFF06;
	intenable(29, clocktick, nil);
	timerset(0);
}

void
timerset(uvlong val)
{
	uvlong now, ticks;

	if(val == 0)
		ticks = MaxPeriod;
	else{
		cycles(&now);
		ticks = (val - now) / 256;
		if(ticks < MinPeriod)
			ticks = MinPeriod;
		if(ticks > MaxPeriod)
			ticks = MaxPeriod;
	}
	local[2] &= ~1;
	local[0] = local[1] = ticks;
	local[2] |= 1;
}

static void
waituntil(uvlong n)
{
	uvlong now, then;
	
	cycles(&now);
	then = now + n;
	while(now < then)
		cycles(&now);
}

void
microdelay(int n)
{
	waituntil(((uvlong)n) * PERIPHCLK / 1000000);
}

void
delay(int n)
{
	waituntil(((uvlong)n) * PERIPHCLK / 1000);
}