shithub: riscv

ref: 0d6a188ddea491e760361c45d9c9fd7ac2f06ffd
dir: /sys/src/9/omap4/clock.c/

View raw version
#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);
}