-/* $OpenBSD: sbbc.c,v 1.2 2008/07/07 14:46:18 kettenis Exp $ */
+/* $OpenBSD: sbbc.c,v 1.3 2008/07/10 20:27:36 kettenis Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
*
#define SBBC_SRAM_OFFSET 0x900000
#define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */
+#define SBBC_PCI_INT_STATUS 0x2320
+#define SBBC_PCI_INT_ENABLE 0x2330
+#define SBBC_PCI_ENABLE_INT_A 0x11
+
#define SBBC_EPLD_INTERRUPT 0x13
#define SBBC_EPLD_INTERRUPT_ON 0x01
bus_space_handle_t sc_sram_ioh;
caddr_t sc_sram;
uint32_t sc_sram_toc;
+ void * sc_ih;
struct sparc_bus_space_tag sc_bbt;
struct tty *sc_tty;
struct timeout sc_to;
caddr_t sc_sram_cons;
- uint32_t *sc_sram_intr_enabled;
- uint32_t *sc_sram_intr_reason;
+ uint32_t *sc_sram_solscie;
+ uint32_t *sc_sram_solscir;
+ uint32_t *sc_sram_scsolie;
+ uint32_t *sc_sram_scsolir;
};
struct sbbc_softc *sbbc_cons_input;
NULL, "sbbc", DV_DULL
};
+int sbbc_intr(void *);
void sbbc_send_intr(struct sbbc_softc *sc);
void sbbc_attach_tod(struct sbbc_softc *, uint32_t);
struct sbbc_sram_toc *toc;
bus_addr_t base;
bus_size_t size;
+ pci_intr_handle_t ih;
int chosen, iosram;
int i;
return;
}
+ if (bus_space_map(sc->sc_iot, base + SBBC_REGS_OFFSET,
+ SBBC_REGS_SIZE, 0, &sc->sc_regs_ioh)) {
+ printf(": can't map register space\n");
+ return;
+ }
+
if (bus_space_map(sc->sc_iot, base + SBBC_EPLD_OFFSET,
SBBC_EPLD_SIZE, 0, &sc->sc_epld_ioh)) {
printf(": can't map EPLD registers\n");
- return;
+ goto unmap_regs;
}
if (bus_space_map(sc->sc_iot, base + SBBC_SRAM_OFFSET,
SBBC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
printf(": can't map SRAM\n");
- return;
+ goto unmap_epld;
+ }
+
+ if (pci_intr_map(pa, &ih)) {
+ printf(": unable to map interrupt\n");
+ goto unmap_sram;
}
+ printf(": %s\n", pci_intr_string(pa->pa_pc, ih));
+
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
+ sbbc_intr, sc, sc->sc_dv.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf("%s: unable to establish interrupt\n");
+ goto unmap_sram;
+ }
+
+ bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
+ SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
/* Check if we are the chosen one. */
chosen = OF_finddevice("/chosen");
if (OF_getprop(chosen, "iosram", &iosram, sizeof(iosram)) <= 0 ||
- PCITAG_NODE(pa->pa_tag) != iosram) {
- printf("\n");
+ PCITAG_NODE(pa->pa_tag) != iosram)
return;
- }
/* SRAM TOC offset defaults to 0. */
if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc,
for (i = 0; i < toc->toc_ntags; i++) {
if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIE") == 0)
- sc->sc_sram_intr_enabled = (uint32_t *)
+ sc->sc_sram_solscie = (uint32_t *)
(sc->sc_sram + toc->toc_tag[i].tag_offset);
if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIR") == 0)
- sc->sc_sram_intr_reason = (uint32_t *)
+ sc->sc_sram_solscir = (uint32_t *)
+ (sc->sc_sram + toc->toc_tag[i].tag_offset);
+ if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIE") == 0)
+ sc->sc_sram_scsolie = (uint32_t *)
+ (sc->sc_sram + toc->toc_tag[i].tag_offset);
+ if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIR") == 0)
+ sc->sc_sram_scsolir = (uint32_t *)
(sc->sc_sram + toc->toc_tag[i].tag_offset);
}
- *sc->sc_sram_intr_enabled |= SBBC_SRAM_CONS_OUT;
-
for (i = 0; i < toc->toc_ntags; i++) {
if (strcmp(toc->toc_tag[i].tag_key, "TODDATA") == 0)
sbbc_attach_tod(sc, toc->toc_tag[i].tag_offset);
sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset);
}
- printf("\n");
+ return;
+
+ unmap_sram:
+ bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_SRAM_SIZE);
+ unmap_epld:
+ bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_EPLD_SIZE);
+ unmap_regs:
+ bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_REGS_SIZE);
+}
+
+int
+sbbc_intr(void *arg)
+{
+ struct sbbc_softc *sc = arg;
+ uint32_t status, reason;
+
+ status = bus_space_read_4(sc->sc_iot, sc->sc_regs_ioh,
+ SBBC_PCI_INT_STATUS);
+ if (status == 0)
+ return (0);
+
+ /* Sigh, we cannot use compare and swap for non-cachable memory. */
+ reason = *sc->sc_sram_scsolir;
+ *sc->sc_sram_scsolir = 0;
+
+#ifdef DDB
+ if (reason & SBBC_SRAM_CONS_BRK && sc == sbbc_cons_input) {
+ if (db_console)
+ Debugger();
+ }
+#endif
+
+ /* Ack interrupt. */
+ bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
+ SBBC_PCI_INT_STATUS, status);
+ return (1);
}
void
int sgcn_is_input, sgcn_is_output, node, maj;
char buf[32];
+ if (sc->sc_sram_solscie == NULL || sc->sc_sram_solscir == NULL ||
+ sc->sc_sram_scsolie == NULL || sc->sc_sram_scsolir == NULL)
+ return;
+
cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset);
if (cons->cons_magic != SBBC_CONS_MAGIC ||
cons->cons_version < SBBC_CONS_VERSION)
timeout_set(&sc->sc_to, sbbctimeout, sc);
+ *sc->sc_sram_solscie |= SBBC_SRAM_CONS_OUT;
+ *sc->sc_sram_scsolie |= SBBC_SRAM_CONS_BRK;
+
/* Take over console input. */
prom_serengeti_set_console_input("CON_CLNT");
/* Let current output drain. */
DELAY(2000000);
- printf(": console");
+ printf("%s: console\n", sc->sc_dv.dv_xname);
}
}
wrptr = cons->cons_out_begin;
cons->cons_out_wrptr = wrptr;
- *sc->sc_sram_intr_reason |= SBBC_SRAM_CONS_OUT;
+ *sc->sc_sram_solscir |= SBBC_SRAM_CONS_OUT;
sbbc_send_intr(sc);
}