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

static uvlong freq;

enum {
	Enable	= 1<<0,
	Imask	= 1<<1,
	Istatus = 1<<2,
};

void
clockshutdown(void)
{
}

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

void
clockinit(void)
{
	syswr(PMCR_EL0, 1<<6 | 7);
	syswr(PMCNTENSET, 1<<31);
	syswr(PMUSERENR_EL0, 1<<2);
	syswr(CNTKCTL_EL1, 1<<1);

	syswr(CNTP_TVAL_EL0, ~0UL);
	syswr(CNTP_CTL_EL0, Enable);

	if(m->machno == 0){
		freq = sysrd(CNTFRQ_EL0);
		print("timer frequency %lld Hz\n", freq);
	}
	m->cpuhz = freq;
	m->cpumhz = (freq + Mhz/2 - 1) / Mhz;
	m->cyclefreq = freq;

	intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
}

void
timerset(uvlong next)
{
	uvlong now;
	long period;

	now = fastticks(nil);
	period = next - now;
	syswr(CNTP_TVAL_EL0, period);
}

uvlong
fastticks(uvlong *hz)
{
	if(hz)
		*hz = freq;
	return sysrd(CNTPCT_EL0);
}

ulong
perfticks(void)
{
	return fastticks(nil);
}

ulong
µs(void)
{
	uvlong hz;
	uvlong t = fastticks(&hz);
	return (t * 1000000ULL) / hz;
}

void
microdelay(int n)
{
	ulong now;

	now = µs();
	while(µs() - now < n);
}

void
delay(int n)
{
	while(--n >= 0)
		microdelay(1000);
}

void
synccycles(void)
{
	static Ref r1, r2;
	int s;

	s = splhi();
	r2.ref = 0;
	incref(&r1);
	while(r1.ref != conf.nmach)
		;
//	syswr(PMCR_EL0, 1<<6 | 7);
	incref(&r2);
	while(r2.ref != conf.nmach)
		;
	r1.ref = 0;
	splx(s);
}