/* ppc440 clock */
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

void
delay(int l)
{
	ulong i, j;

	j = m->delayloop;
	while(l-- > 0)
		for(i=0; i < j; i++)
			;
}

void
microdelay(int l)
{
	ulong i;

	l *= m->delayloop;
	l /= 1000;
	if(l <= 0)
		l = 1;
	for(i = 0; i < l; i++)
		;
}

enum {
	Timebase = 1,	/* system clock cycles per time base cycle */

	Wp21=	0<<30,	/* watchdog period (2^x clocks) */
	Wp25=	1<<30,
	Wp29=	2<<30,
	Wp33=	3<<30,
	Wrnone=	0<<28,	/* no watchdog reset */
	Wrcore=	1<<28,	/* core reset */
	Wrchip=	2<<28,	/* chip reset */
	Wrsys=	3<<28,	/* system reset */
	Wie=		1<<27,	/* watchdog interrupt enable */
	Pie=		1<<26,	/* enable PIT interrupt */
	Fit13=	0<<24,	/* fit period (2^x clocks) */
	Fit17=	1<<24,
	Fit21=	2<<24,
	Fit25=	3<<24,
	Fie=		1<<23,	/* fit interrupt enable */
	Are=		1<<22,	/* auto reload enable */

	/* dcr */
	Boot=	0x0F1,
	Epctl=	0x0F3,
	Pllmr0=	0x0F0,
	Pllmr1=	0x0F4,
	Ucr=		0x0F5,
};

void	(*archclocktick)(void);	/* set by arch*.c if used */

void
clockinit(void)
{
	long x;

	m->delayloop = m->cpuhz/1000;	/* initial estimate */
	do {
		x = gettbl();
		delay(10);
		x = gettbl() - x;
	} while(x < 0);

	/*
	 *  fix count
	 */
	m->delayloop = ((vlong)m->delayloop * (10*(vlong)m->clockgen/1000)) /
		(x*Timebase);
	if((int)m->delayloop <= 0)
		m->delayloop = 20000;

	x = (m->clockgen/Timebase)/HZ;
	putpit(x);
	puttsr(~0);
	/* not sure if we want Wrnone or Wrcore */
//	puttcr(Pie|Are|Wie|Wrcore|Wp29);
	puttcr(Pie|Are|Wrnone);
}

void
clockintr(Ureg *ureg)
{
	/* PIT was set to reload automatically */
	puttsr(~0);
	m->fastclock++;
	timerintr(ureg, 0);
	if(archclocktick != nil)
		archclocktick();
}

uvlong
fastticks(uvlong *hz)
{
	if(hz)
		*hz = HZ;
	return m->fastclock;
}

ulong
µs(void)
{
	return fastticks2us(m->fastclock);
}

void
timerset(uvlong)
{
}

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

long
lcycles(void)
{
	return perfticks();
}
