#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pioc.c,v 1.20 2021/08/07 16:18:40 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <arm/mainbus/mainbus.h>
#include <acorn32/mainbus/piocreg.h>
#include <acorn32/mainbus/piocvar.h>
#include "locators.h"
struct pioc_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_addr_t sc_iobase;
int sc_id;
int sc_config[PIOC_CM_REGS];
};
extern struct bus_space mainbus_bs_tag;
bus_space_tag_t comconstag = &mainbus_bs_tag;
static int piocmatch(device_t, cfdata_t, void *);
static void piocattach(device_t, device_t, void *);
static int piocprint(void *aux, const char *name);
#if 0
static int piocsearch(device_t, cfdata_t, void *);
#endif
static int piocsubmatch(device_t, cfdata_t,
const int *, void *);
static void piocgetid(bus_space_tag_t iot, bus_space_handle_t ioh,
int config_entry, int *id, int *revision);
CFATTACH_DECL_NEW(pioc, sizeof(struct pioc_softc),
piocmatch, piocattach, NULL, NULL);
static void
piocgetid(bus_space_tag_t iot, bus_space_handle_t ioh, int config_entry, int *id, int *revision)
{
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, config_entry);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, config_entry);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_CRD);
*id = bus_space_read_1(iot, ioh, PIOC_CM_DATA_REG);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_CRE);
*revision = bus_space_read_1(iot, ioh, PIOC_CM_DATA_REG);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_EXIT);
}
static int
piocmatch(device_t parent, cfdata_t cf, void *aux)
{
struct mainbus_attach_args *mb = aux;
bus_space_tag_t iot;
bus_space_handle_t ioh;
int id, rev;
int rv = 1;
if (mb->mb_iobase == MAINBUSCF_BASE_DEFAULT)
return(0);
iot = mb->mb_iot;
if (bus_space_map(iot, mb->mb_iobase, PIOC_SIZE, 0, &ioh))
return(0);
mb->mb_iosize = PIOC_SIZE;
piocgetid(iot, ioh, PIOC_CM_ENTER_665, &id, &rev);
if (id == PIOC_CM_ID_665)
goto out;
piocgetid(iot, ioh, PIOC_CM_ENTER_666, &id, &rev);
if (id == PIOC_CM_ID_666)
goto out;
rv = 0;
out:
bus_space_unmap(iot, ioh, PIOC_SIZE);
return(rv);
}
static int
piocprint(void *aux, const char *name)
{
struct pioc_attach_args *pa = aux;
if (!name) {
if (pa->pa_offset)
aprint_normal(" offset 0x%x", pa->pa_offset >> 2);
if (pa->pa_iosize > 1)
aprint_normal("-0x%x",
((pa->pa_offset >> 2) + pa->pa_iosize) - 1);
if (pa->pa_irq != -1)
aprint_normal(" irq %d", pa->pa_irq);
if (pa->pa_drq != -1)
aprint_normal(" drq 0x%08x", pa->pa_drq);
}
return (QUIET);
}
#if 0
static int
piocsearch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
{
struct pioc_softc *sc = device_private(parent);
struct pioc_attach_args pa;
int tryagain;
do {
pa.pa_name = NULL;
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = sc->sc_iot;
if (cf->cf_loc[PIOCCF_OFFSET] == PIOCCF_OFFSET_DEFAULT) {
pa.pa_offset = PIOCCF_OFFSET_DEFAULT;
pa.pa_drq = PIOCCF_DACK_DEFAULT;
pa.pa_irq = PIOCCF_IRQ_DEFAULT;
} else {
pa.pa_offset = (cf->cf_loc[PIOCCF_OFFSET] << 2);
pa.pa_drq = cf->cf_loc[PIOCCF_DACK];
pa.pa_irq = cf->cf_loc[PIOCCF_IRQ];
}
tryagain = 0;
if (config_probe(parent, cf, &pa)) {
config_attach(parent, cf, &pa, piocprint, CFARGS_NONE);
}
} while (tryagain);
return (0);
}
#endif
static int
piocsubmatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
{
struct pioc_attach_args *pa = aux;
int tryagain;
if ((pa->pa_offset >> 2) != cf->cf_loc[PIOCCF_OFFSET])
return(0);
do {
if (pa->pa_drq == -1)
pa->pa_drq = cf->cf_loc[PIOCCF_DACK];
if (pa->pa_irq == -1)
pa->pa_irq = cf->cf_loc[PIOCCF_IRQ];
tryagain = 0;
if (config_probe(parent, cf, pa)) {
config_attach(parent, cf, pa, piocprint, CFARGS_NONE);
}
} while (tryagain);
return (0);
}
static void
piocattach(device_t parent, device_t self, void *aux)
{
struct mainbus_attach_args *mb = aux;
struct pioc_softc *sc = device_private(self);
bus_space_tag_t iot;
bus_space_handle_t ioh;
int id, rev;
int loop;
struct pioc_attach_args pa;
sc->sc_iobase = mb->mb_iobase;
iot = sc->sc_iot = mb->mb_iot;
if (bus_space_map(iot, sc->sc_iobase, PIOC_SIZE, 0, &ioh))
panic("%s: couldn't map I/O space", device_xname(self));
sc->sc_ioh = ioh;
piocgetid(iot, ioh, PIOC_CM_ENTER_665, &id, &rev);
if (id != PIOC_CM_ID_665)
piocgetid(iot, ioh, PIOC_CM_ENTER_666, &id, &rev);
printf("\n%s: ", device_xname(self));
switch (id) {
case PIOC_CM_ID_665:
case PIOC_CM_ID_666:
printf("SMC FDC37C6%xGT peripheral controller rev %d\n", id, rev);
break;
default:
printf("Unrecognised peripheral controller id=%2x rev=%2x\n", id, rev);
return;
}
sc->sc_id = id;
switch (id) {
case PIOC_CM_ID_665:
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_ENTER_665);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_ENTER_665);
break;
case PIOC_CM_ID_666:
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_ENTER_666);
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_ENTER_666);
break;
}
for (loop = 0; loop < PIOC_CM_REGS; ++loop) {
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, loop);
sc->sc_config[loop] = bus_space_read_1(iot, ioh, PIOC_CM_DATA_REG);
}
bus_space_write_1(iot, ioh, PIOC_CM_SELECT_REG, PIOC_CM_EXIT);
#ifdef PIOC_DEBUG
printf("%s: ", device_xname(self));
for (loop = 0; loop < PIOC_CM_REGS; ++loop)
printf("%02x ", sc->sc_config[loop]);
printf("\n");
#endif
if (sc->sc_config[PIOC_CM_CR0] & PIOC_WDC_ENABLE) {
pa.pa_name = "wdc";
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = iot;
if (sc->sc_config[PIOC_CM_CR5] & PIOC_WDC_SECONDARY)
pa.pa_offset = (PIOC_WDC_SECONDARY_OFFSET << 2);
else
pa.pa_offset = (PIOC_WDC_PRIMARY_OFFSET << 2);
pa.pa_drq = -1;
pa.pa_irq = -1;
config_found(self, &pa, piocprint,
CFARGS(.submatch = piocsubmatch));
}
if (sc->sc_config[PIOC_CM_CR0] & PIOC_FDC_ENABLE) {
pa.pa_name = "fdc";
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = iot;
if (sc->sc_config[PIOC_CM_CR5] & PIOC_FDC_SECONDARY)
pa.pa_offset = (PIOC_FDC_SECONDARY_OFFSET << 2);
else
pa.pa_offset = (PIOC_FDC_PRIMARY_OFFSET << 2);
pa.pa_drq = -1;
pa.pa_irq = -1;
config_found(self, &pa, piocprint,
CFARGS(.submatch = piocsubmatch));
}
if (sc->sc_config[PIOC_CM_CR2] & PIOC_UART1_ENABLE) {
pa.pa_name = "com";
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = iot;
switch (sc->sc_config[PIOC_CM_CR2] & PIOC_UART1_ADDR_MASK) {
case PIOC_UART1_ADDR_COM1:
pa.pa_offset = (PIOC_COM1_OFFSET << 2);
break;
case PIOC_UART1_ADDR_COM2:
pa.pa_offset = (PIOC_COM2_OFFSET << 2);
break;
case PIOC_UART1_ADDR_COM3:
pa.pa_offset = (PIOC_COM3_OFFSET << 2);
break;
case PIOC_UART1_ADDR_COM4:
pa.pa_offset = (PIOC_COM4_OFFSET << 2);
break;
}
pa.pa_drq = -1;
pa.pa_irq = -1;
config_found(self, &pa, piocprint,
CFARGS(.submatch = piocsubmatch));
}
if (sc->sc_config[PIOC_CM_CR2] & PIOC_UART2_ENABLE) {
pa.pa_name = "com";
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = iot;
switch (sc->sc_config[PIOC_CM_CR2] & PIOC_UART2_ADDR_MASK) {
case PIOC_UART2_ADDR_COM1:
pa.pa_offset = (PIOC_COM1_OFFSET << 2);
break;
case PIOC_UART2_ADDR_COM2:
pa.pa_offset = (PIOC_COM2_OFFSET << 2);
break;
case PIOC_UART2_ADDR_COM3:
pa.pa_offset = (PIOC_COM3_OFFSET << 2);
break;
case PIOC_UART2_ADDR_COM4:
pa.pa_offset = (PIOC_COM4_OFFSET << 2);
break;
}
pa.pa_drq = -1;
pa.pa_irq = -1;
config_found(self, &pa, piocprint,
CFARGS(.submatch = piocsubmatch));
}
if ((sc->sc_config[PIOC_CM_CR1] & PIOC_LPT_ADDR_MASK) != PIOC_LPT_ADDR_DISABLE) {
pa.pa_name = "lpt";
pa.pa_iobase = sc->sc_iobase;
pa.pa_iosize = 0;
pa.pa_iot = iot;
switch (sc->sc_config[PIOC_CM_CR1] & PIOC_LPT_ADDR_MASK) {
case PIOC_LPT_ADDR_1:
pa.pa_offset = (PIOC_LPT1_OFFSET << 2);
break;
case PIOC_LPT_ADDR_2:
pa.pa_offset = (PIOC_LPT2_OFFSET << 2);
break;
case PIOC_LPT_ADDR_3:
pa.pa_offset = (PIOC_LPT3_OFFSET << 2);
break;
}
pa.pa_drq = -1;
pa.pa_irq = -1;
config_found(self, &pa, piocprint,
CFARGS(.submatch = piocsubmatch));
}
#if 0
config_search(self, NULL,
CFARGS(.search = piocsearch));
#endif
}