#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: via.c,v 1.77 2024/02/28 13:05:40 thorpej Exp $");
#include "opt_mac68k.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/intr.h>
#include <machine/viareg.h>
void mrg_adbintr(void *);
void mrg_pmintr(void *);
void rtclock_intr(void *);
void profclock(void *);
void via1_intr(void *);
void via2_intr(void *);
void rbv_intr(void *);
void oss_intr(void *);
void via2_nubus_intr(void *);
void rbv_nubus_intr(void *);
static void via1_noint(void *);
static void via2_noint(void *);
static void slot_ignore(void *);
static void slot_noint(void *);
int VIA2 = VIA2OFF;
void (*via1itab[7])(void *) = {
via1_noint,
via1_noint,
mrg_adbintr,
via1_noint,
mrg_pmintr,
via1_noint,
rtclock_intr,
};
void *via1iarg[7] = {
(void *)0,
(void *)1,
(void *)2,
(void *)3,
(void *)4,
(void *)5,
(void *)6
};
void (*via2itab[7])(void *) = {
via2_noint,
via2_nubus_intr,
via2_noint,
via2_noint,
via2_noint,
via2_noint,
via2_noint,
};
void *via2iarg[7] = {
(void *)0,
(void *)1,
(void *)2,
(void *)3,
(void *)4,
(void *)5,
(void *)6
};
void (*slotitab[7])(void *) = {
slot_noint,
slot_noint,
slot_noint,
slot_noint,
slot_noint,
slot_noint,
slot_noint
};
void *slotptab[7] = {
(void *)0,
(void *)1,
(void *)2,
(void *)3,
(void *)4,
(void *)5,
(void *)6
};
static int nubus_intr_mask = 0;
void
via_init(void)
{
via_reg(VIA1, vT1L) = 0;
via_reg(VIA1, vT1LH) = 0;
via_reg(VIA1, vT1C) = 0;
via_reg(VIA1, vT1CH) = 0;
via_reg(VIA1, vT2C) = 0;
via_reg(VIA1, vT2CH) = 0;
via_reg(VIA1, vACR) &= 0x3f;
intr_establish((int (*)(void *)) via1_intr, NULL, mac68k_machine.via1_ipl);
if (VIA2 == VIA2OFF) {
via2_reg(vT1L) = 0;
via2_reg(vT1LH) = 0;
via2_reg(vT1C) = 0;
via2_reg(vT1CH) = 0;
via2_reg(vT2C) = 0;
via2_reg(vT2CH) = 0;
via2_reg(vACR) &= 0x3f;
if (mac68k_machine.machineid == MACH_MACSE30) {
via_reg(VIA1, vBufB) |= (0x40);
via_reg(VIA1, vDirB) |= (0x40);
}
via2_reg(vPCR) = 0x66;
switch(mac68k_machine.machineid) {
case MACH_MACPB140:
case MACH_MACPB145:
case MACH_MACPB150:
case MACH_MACPB160:
case MACH_MACPB165:
case MACH_MACPB165C:
case MACH_MACPB170:
case MACH_MACPB180:
case MACH_MACPB180C:
break;
default:
via2_reg(vBufB) |= 0x02;
via2_reg(vDirB) |= 0x02;
break;
}
intr_establish((int (*)(void*))via2_intr, NULL,
mac68k_machine.via2_ipl);
via2itab[1] = via2_nubus_intr;
} else if (current_mac_model->class == MACH_CLASSIIfx) {
volatile u_char *ossintr;
ossintr = (volatile u_char *)IOBase + 0x1a006;
*ossintr = 0;
intr_establish((int (*)(void*))oss_intr, NULL,
mac68k_machine.via2_ipl);
} else {
#ifdef DISABLE_EXT_CACHE
if (current_mac_model->class == MACH_CLASSIIci) {
via2_reg(rBufB) |= DB2O_CEnable;
}
#endif
intr_establish((int (*)(void*))rbv_intr, NULL,
mac68k_machine.via2_ipl);
via2itab[1] = rbv_nubus_intr;
add_nubus_intr(0, slot_ignore, NULL);
}
}
void
via_set_modem(int onoff)
{
via_reg(VIA1, vDirA) |= DA1O_vSync;
if (onoff)
via_reg(VIA1, vBufA) |= DA1O_vSync;
else
via_reg(VIA1, vBufA) &= ~DA1O_vSync;
}
void
via1_intr(void *intr_arg )
{
u_int8_t intbits, bitnum;
u_int mask;
intbits = via_reg(VIA1, vIFR);
intbits &= via_reg(VIA1, vIER);
if (intbits == 0)
return;
via_reg(VIA1, vIFR) = intbits;
intbits &= 0x7f;
mask = 1;
bitnum = 0;
do {
if (intbits & mask) {
void *arg = via1itab[bitnum] == rtclock_intr
? intr_arg : via1iarg[bitnum];
via1itab[bitnum](arg);
}
mask <<= 1;
++bitnum;
} while (intbits >= mask);
}
void
via2_intr(void *intr_arg)
{
u_int8_t intbits, bitnum;
u_int mask;
intbits = via2_reg(vIFR);
intbits &= via2_reg(vIER);
if (intbits == 0)
return;
via2_reg(vIFR) = intbits;
intbits &= 0x7f;
mask = 1;
bitnum = 0;
do {
if (intbits & mask)
via2itab[bitnum](via2iarg[bitnum]);
mask <<= 1;
++bitnum;
} while (intbits >= mask);
}
void
rbv_intr(void *intr_arg)
{
u_int8_t intbits, bitnum;
u_int mask;
intbits = (via2_reg(vIFR + rIFR) & via2_reg(vIER + rIER));
if (intbits == 0)
return;
via2_reg(rIFR) = intbits;
intbits &= 0x7f;
mask = 1;
bitnum = 0;
do {
if (intbits & mask)
via2itab[bitnum](via2iarg[bitnum]);
mask <<= 1;
++bitnum;
} while (intbits >= mask);
}
void
oss_intr(void *intr_arg)
{
u_int8_t intbits, bitnum;
u_int mask;
intbits = via2_reg(vIFR + rIFR);
if (intbits == 0)
return;
intbits &= 0x7f;
mask = 1;
bitnum = 0;
do {
if (intbits & mask) {
(*slotitab[bitnum])(slotptab[bitnum]);
via2_reg(rIFR) = mask;
}
mask <<= 1;
++bitnum;
} while (intbits >= mask);
}
static void
via1_noint(void *bitnum)
{
printf("via1_noint(%d)\n", (int)bitnum);
}
static void
via2_noint(void *bitnum)
{
printf("via2_noint(%d)\n", (int)bitnum);
}
int
add_nubus_intr(int slot, void (*func)(void *), void *client_data)
{
int s;
if (slot == 0)
slot = 15;
if (slot < 9 || slot > 15)
return 0;
s = splhigh();
if (func == NULL) {
slotitab[slot - 9] = slot_noint;
nubus_intr_mask &= ~(1 << (slot - 9));
} else {
slotitab[slot - 9] = func;
nubus_intr_mask |= (1 << (slot - 9));
}
if (client_data == NULL)
slotptab[slot - 9] = (void *)(slot - 9);
else
slotptab[slot - 9] = client_data;
splx(s);
return 1;
}
void
enable_nubus_intr(void)
{
if ((nubus_intr_mask & 0x3f) == 0)
return;
if (VIA2 == VIA2OFF)
via2_reg(vIER) = 0x80 | V2IF_SLOTINT;
else
via2_reg(rIER) = 0x80 | V2IF_SLOTINT;
}
void
via2_nubus_intr(void *bitarg)
{
u_int8_t i, intbits, mask;
via2_reg(vIFR) = V2IF_SLOTINT;
while ((intbits = (~via2_reg(vBufA)) & nubus_intr_mask)) {
i = 6;
mask = (1 << i);
do {
if (intbits & mask)
(*slotitab[i])(slotptab[i]);
i--;
mask >>= 1;
} while (mask);
via2_reg(vIFR) = V2IF_SLOTINT;
}
}
void
rbv_nubus_intr(void *bitarg)
{
u_int8_t i, intbits, mask;
via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
while ((intbits = (~via2_reg(rBufA)) & via2_reg(rSlotInt))) {
i = 6;
mask = (1 << i);
do {
if (intbits & mask)
(*slotitab[i])(slotptab[i]);
i--;
mask >>= 1;
} while (mask);
via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
}
}
static void
slot_ignore(void *client_data)
{
int mask = (1 << (int)client_data);
if (VIA2 == VIA2OFF) {
via2_reg(vDirA) |= mask;
via2_reg(vBufA) = mask;
via2_reg(vDirA) &= ~mask;
} else
via2_reg(rBufA) = mask;
}
static void
slot_noint(void *client_data)
{
int slot = (int)client_data + 9;
printf("slot_noint() slot %x\n", slot);
slot_ignore(client_data);
}
void
via_powerdown(void)
{
if (VIA2 == VIA2OFF) {
via2_reg(vDirB) |= 0x04;
via2_reg(vBufB) &= ~0x04;
} else if (VIA2 == RBVOFF) {
via2_reg(rBufB) &= ~0x04;
} else if (VIA2 == OSSOFF) {
via2_reg(OSS_oRCR) |= OSS_POWEROFF;
}
}
void
via1_register_irq(int irq, void (*irq_func)(void *), void *client_data)
{
if (irq_func) {
via1itab[irq] = irq_func;
via1iarg[irq] = client_data;
} else {
via1itab[irq] = via1_noint;
via1iarg[irq] = (void *)0;
}
}
void
via2_register_irq(int irq, void (*irq_func)(void *), void *client_data)
{
if (irq_func) {
via2itab[irq] = irq_func;
via2iarg[irq] = client_data;
} else {
via2itab[irq] = via2_noint;
via2iarg[irq] = (void *)0;
}
}