#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hat.c,v 1.7 2021/04/30 02:11:37 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <arm/fiq.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/pio.h>
#include <arm/cpufunc.h>
#include <dev/ic/i8253reg.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include "isadma.h"
#include <shark/shark/shark_fiq.h>
#include <shark/shark/sequoia.h>
#include <shark/shark/hat.h>
static int hatOn = 0;
static void hatClkCount(int);
static void hatEnableSWTCH(void);
static void (*hatWedgeFn)(int);
extern struct fiqregs shark_fiqregs;
int
hatClkOff(void)
{
u_int16_t seqReg;
if (!hatOn) return -1;
hatOn = 0;
hatWedgeFn = NULL;
sequoiaLock();
sequoiaRead(PMC_PMCMCR2_REG, &seqReg);
sequoiaWrite(PMC_PMCMCR2_REG, seqReg | (PMCMCR2_M_SWTCHEN));
sequoiaUnlock();
outb(ATSR_REG1_REG,
inb(ATSR_REG1_REG) & ~((REG1_M_TMR2EN) | (REG1_M_SPKREN)));
fiq_getregs(&shark_fiqregs);
shark_fiqregs.fr_r9 = 0;
shark_fiqregs.fr_r13 = 0;
fiq_setregs(&shark_fiqregs);
#if (NISADMA > 0)
isa_dmathaw(&isa_chipset_tag);
#endif
return 0;
}
int
hatClkOn(int count, void (*hatFn)(int), int arg,
unsigned char *stack, void (*wedgeFn)(int))
{
u_int16_t seqReg;
if (hatOn)
return -1;
hatWedgeFn = wedgeFn;
#if (NISADMA > 0)
isa_dmafreeze(&isa_chipset_tag);
#endif
fiq_getregs(&shark_fiqregs);
shark_fiqregs.fr_r9 = (u_int)hatFn;
shark_fiqregs.fr_r10 = (u_int)arg;
shark_fiqregs.fr_r13 = (u_int)stack;
fiq_setregs(&shark_fiqregs);
sequoiaLock();
sequoiaRead(PMC_DBCR_REG, &seqReg);
sequoiaWrite(PMC_DBCR_REG, seqReg | DBCR_M_DBDIS0);
hatEnableSWTCH();
outb(ATSR_REG1_REG,
inb(ATSR_REG1_REG) | (REG1_M_TMR2EN) | (REG1_M_SPKREN));
hatClkCount(count);
sequoiaRead(PMC_PMCMCR2_REG, &seqReg);
sequoiaWrite(PMC_PMCMCR2_REG, seqReg | (PMCMCR2_M_SWTCHEN));
sequoiaUnlock();
hatOn = 1;
return 0;
}
int
hatClkAdjust(int count)
{
if (!hatOn)
return -1;
hatClkCount(count);
sequoiaLock();
hatEnableSWTCH();
sequoiaUnlock();
return 0;
}
static void
hatEnableSWTCH(void)
{
u_int16_t seqReg;
KASSERT(sequoiaIsLocked());
sequoiaRead(PMC_PMIMCR_REG, &seqReg);
sequoiaWrite(PMC_PMIMCR_REG, seqReg | (PMIMCR_M_IMSKSWSTBY));
sequoiaWrite(PMC_PMIMCR_REG, seqReg & ~(PMIMCR_M_IMSKSWSTBY));
}
void
hatUnwedge(void)
{
static int lastFiqsHappened = -1;
extern int fiqs_happened;
if (!hatOn)
return;
if (lastFiqsHappened == fiqs_happened) {
sequoiaLock();
hatEnableSWTCH();
sequoiaUnlock();
if (hatWedgeFn)
(*hatWedgeFn)(fiqs_happened);
} else {
lastFiqsHappened = fiqs_happened;
}
}
static void
hatClkCount(int count)
{
u_int savedints;
savedints = disable_interrupts(I32_bit);
outb(TIMER_MODE, TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT);
outb(TIMER_CNTR2, count % 256);
outb(TIMER_CNTR2, count / 256);
restore_interrupts(savedints);
}