summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2008-07-07 14:46:19 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2008-07-07 14:46:19 +0000
commit6e50ae7a4e877fe7e5f98f2da779e291c0e9a628 (patch)
tree8be82b42bef8b558839f6731ae9f91b678f03a4b /sys/arch/sparc64
parent21292843744298b122392609d93a6fe47a2b3dad (diff)
Extend sbbc(4) to provide a console driver for the v1280.
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/conf/files.sparc644
-rw-r--r--sys/arch/sparc64/dev/sbbc.c398
-rw-r--r--sys/arch/sparc64/include/conf.h3
-rw-r--r--sys/arch/sparc64/include/sparc64.h3
-rw-r--r--sys/arch/sparc64/sparc64/conf.c6
-rw-r--r--sys/arch/sparc64/sparc64/ofw_machdep.c24
6 files changed, 425 insertions, 13 deletions
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64
index e39ba327fec..365e017abbb 100644
--- a/sys/arch/sparc64/conf/files.sparc64
+++ b/sys/arch/sparc64/conf/files.sparc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc64,v 1.108 2008/07/06 08:52:26 kettenis Exp $
+# $OpenBSD: files.sparc64,v 1.109 2008/07/07 14:46:18 kettenis Exp $
# $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $
# maxpartitions must be first item in files.${ARCH}
@@ -123,7 +123,7 @@ file arch/sparc64/dev/ifb.c ifb
device sbbc
attach sbbc at pci
-file arch/sparc64/dev/sbbc.c sbbc
+file arch/sparc64/dev/sbbc.c sbbc needs-flag
# IOMMU is for both sbus and pci
file arch/sparc64/dev/iommu.c sbus | psycho | schizo | pyro | vpci
diff --git a/sys/arch/sparc64/dev/sbbc.c b/sys/arch/sparc64/dev/sbbc.c
index 9bc9e033def..092ad24c8c9 100644
--- a/sys/arch/sparc64/dev/sbbc.c
+++ b/sys/arch/sparc64/dev/sbbc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sbbc.c,v 1.1 2008/07/06 07:27:43 kettenis Exp $ */
+/* $OpenBSD: sbbc.c,v 1.2 2008/07/07 14:46:18 kettenis Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
*
@@ -16,12 +16,24 @@
*/
#include <sys/param.h>
+#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/timeout.h>
+#include <sys/tty.h>
#include <sys/systm.h>
+#ifdef DDB
+#include <ddb/db_var.h>
+#endif
+
#include <machine/autoconf.h>
+#include <machine/conf.h>
#include <machine/openfirm.h>
+#include <machine/sparc64.h>
+
+#include <dev/cons.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcireg.h>
@@ -35,9 +47,20 @@ extern todr_chip_handle_t todr_handle;
#define SBBC_REGS_OFFSET 0x800000
#define SBBC_REGS_SIZE 0x6230
+#define SBBC_EPLD_OFFSET 0x8e0000
+#define SBBC_EPLD_SIZE 0x20
#define SBBC_SRAM_OFFSET 0x900000
#define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */
+#define SBBC_EPLD_INTERRUPT 0x13
+#define SBBC_EPLD_INTERRUPT_ON 0x01
+
+#define SBBC_SRAM_CONS_IN 0x00000001
+#define SBBC_SRAM_CONS_OUT 0x00000002
+#define SBBC_SRAM_CONS_BRK 0x00000004
+#define SBBC_SRAM_CONS_SPACE_IN 0x00000008
+#define SBBC_SRAM_CONS_SPACE_OUT 0x00000010
+
#define SBBC_MAX_TAGS 32
struct sbbc_sram_tag {
@@ -66,20 +89,50 @@ struct sbbc_sram_tod {
uint32_t tod_timeout;
};
-#define SBBC_TOD_MAGIC 0x54443100
+#define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */
#define SBBC_TOD_VERSION 1
+/* Console service. */
+struct sbbc_sram_cons {
+ uint32_t cons_magic;
+ uint32_t cons_version;
+ uint32_t cons_size;
+
+ uint32_t cons_in_begin;
+ uint32_t cons_in_end;
+ uint32_t cons_in_rdptr;
+ uint32_t cons_in_wrptr;
+
+ uint32_t cons_out_begin;
+ uint32_t cons_out_end;
+ uint32_t cons_out_rdptr;
+ uint32_t cons_out_wrptr;
+};
+
+#define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */
+#define SBBC_CONS_VERSION 1
+
struct sbbc_softc {
struct device sc_dv;
bus_space_tag_t sc_iot;
- bus_space_handle_t sc_reg_ioh;
+ bus_space_handle_t sc_regs_ioh;
+ bus_space_handle_t sc_epld_ioh;
bus_space_handle_t sc_sram_ioh;
caddr_t sc_sram;
uint32_t sc_sram_toc;
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;
};
+struct sbbc_softc *sbbc_cons_input;
+struct sbbc_softc *sbbc_cons_output;
+
int sbbc_match(struct device *, void *, void *);
void sbbc_attach(struct device *, struct device *, void *);
@@ -91,10 +144,20 @@ struct cfdriver sbbc_cd = {
NULL, "sbbc", DV_DULL
};
+void sbbc_send_intr(struct sbbc_softc *sc);
+
void sbbc_attach_tod(struct sbbc_softc *, uint32_t);
int sbbc_tod_gettime(todr_chip_handle_t, struct timeval *);
int sbbc_tod_settime(todr_chip_handle_t, struct timeval *);
+void sbbc_attach_cons(struct sbbc_softc *, uint32_t);
+int sbbc_cnlookc(dev_t, int *);
+int sbbc_cngetc(dev_t);
+void sbbc_cnputc(dev_t, int);
+void sbbcstart(struct tty *);
+int sbbcparam(struct tty *, struct termios *);
+void sbbctimeout(void *);
+
int
sbbc_match(struct device *parent, void *match, void *aux)
{
@@ -129,19 +192,25 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
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;
+ }
+
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;
}
- printf("\n");
-
/* 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)
+ PCITAG_NODE(pa->pa_tag) != iosram) {
+ printf("\n");
return;
+ }
/* SRAM TOC offset defaults to 0. */
if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc,
@@ -152,9 +221,31 @@ sbbc_attach(struct device *parent, struct device *self, void *aux)
toc = (struct sbbc_sram_toc *)(sc->sc_sram + 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 + 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 + 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);
+ if (strcmp(toc->toc_tag[i].tag_key, "SOLCONS") == 0)
+ sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset);
}
+
+ printf("\n");
+}
+
+void
+sbbc_send_intr(struct sbbc_softc *sc)
+{
+ bus_space_write_1(sc->sc_iot, sc->sc_epld_ioh,
+ SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
}
void
@@ -199,3 +290,298 @@ sbbc_tod_settime(todr_chip_handle_t handle, struct timeval *tv)
tod->tod_skew = tv->tv_sec - tod->tod_time;
return (0);
}
+
+void
+sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
+{
+ struct sbbc_sram_cons *cons;
+ int sgcn_is_input, sgcn_is_output, node, maj;
+ char buf[32];
+
+ cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset);
+ if (cons->cons_magic != SBBC_CONS_MAGIC ||
+ cons->cons_version < SBBC_CONS_VERSION)
+ return;
+
+ sc->sc_sram_cons = sc->sc_sram + offset;
+ sbbc_cons_input = sbbc_cons_output = sc;
+ sgcn_is_input = sgcn_is_output = 0;
+
+ timeout_set(&sc->sc_to, sbbctimeout, sc);
+
+ /* Take over console input. */
+ prom_serengeti_set_console_input("CON_CLNT");
+
+ /* Check for console input. */
+ node = OF_instance_to_package(OF_stdin());
+ if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
+ sgcn_is_input = (strcmp(buf, "sgcn") == 0);
+
+ /* Check for console output. */
+ node = OF_instance_to_package(OF_stdout());
+ if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
+ sgcn_is_output = (strcmp(buf, "sgcn") == 0);
+
+ if (sgcn_is_input) {
+ cn_tab->cn_pollc = nullcnpollc;
+ cn_tab->cn_getc = sbbc_cngetc;
+ }
+
+ if (sgcn_is_output)
+ cn_tab->cn_putc = sbbc_cnputc;
+
+ if (sgcn_is_input || sgcn_is_output) {
+ /* Locate the major number. */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == sbbcopen)
+ break;
+ cn_tab->cn_dev = makedev(maj, sc->sc_dv.dv_unit);
+
+ /* Let current output drain. */
+ DELAY(2000000);
+
+ printf(": console");
+ }
+}
+
+int
+sbbc_cnlookc(dev_t dev, int *cp)
+{
+ struct sbbc_softc *sc = sbbc_cons_input;
+ struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
+ uint32_t rdptr = cons->cons_in_rdptr;
+
+ if (rdptr == cons->cons_in_wrptr)
+ return (0);
+
+ *cp = *(sc->sc_sram_cons + rdptr);
+ if (++rdptr == cons->cons_in_end)
+ rdptr = cons->cons_in_begin;
+ cons->cons_in_rdptr = rdptr;
+
+ return (1);
+}
+
+int
+sbbc_cngetc(dev_t dev)
+{
+ int c;
+
+ while(!sbbc_cnlookc(dev, &c))
+ ;
+
+ return (c);
+}
+
+void
+sbbc_cnputc(dev_t dev, int c)
+{
+ struct sbbc_softc *sc = sbbc_cons_output;
+ struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
+ uint32_t wrptr = cons->cons_out_wrptr;
+
+ *(sc->sc_sram_cons + wrptr) = c;
+ if (++wrptr == cons->cons_out_end)
+ wrptr = cons->cons_out_begin;
+ cons->cons_out_wrptr = wrptr;
+
+ *sc->sc_sram_intr_reason |= SBBC_SRAM_CONS_OUT;
+ sbbc_send_intr(sc);
+}
+
+int
+sbbcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct sbbc_softc *sc;
+ struct tty *tp;
+ int unit = minor(dev);
+ int error, setuptimeout;
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (ENXIO);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (ENXIO);
+
+ if (sc->sc_tty)
+ tp = sc->sc_tty;
+ else
+ tp = sc->sc_tty = ttymalloc();
+
+ tp->t_oproc = sbbcstart;
+ tp->t_param = sbbcparam;
+ tp->t_dev = dev;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ ttsetwater(tp);
+
+ setuptimeout = 1;
+ } else if ((tp->t_state & TS_XCLUDE) && suser(p, 0))
+ return (EBUSY);
+ tp->t_state |= TS_CARR_ON;
+
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ if (error == 0 && setuptimeout)
+ sbbctimeout(sc);
+
+ return (error);
+}
+
+int
+sbbcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct sbbc_softc *sc;
+ struct tty *tp;
+ int unit = minor(dev);
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (ENXIO);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (ENXIO);
+
+ tp = sc->sc_tty;
+ timeout_del(&sc->sc_to);
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return (0);
+}
+
+int
+sbbcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct sbbc_softc *sc;
+ struct tty *tp;
+ int unit = minor(dev);
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (ENXIO);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (ENXIO);
+
+ tp = sc->sc_tty;
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+sbbcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct sbbc_softc *sc;
+ struct tty *tp;
+ int unit = minor(dev);
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (ENXIO);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (ENXIO);
+
+ tp = sc->sc_tty;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+int
+sbbcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct sbbc_softc *sc;
+ struct tty *tp;
+ int unit = minor(dev);
+ int error;
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (ENXIO);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (ENXIO);
+
+ tp = sc->sc_tty;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ return (ENOTTY);
+}
+
+void
+sbbcstart(struct tty *tp)
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
+ splx(s);
+ return;
+ }
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ tp->t_state |= TS_BUSY;
+ while (tp->t_outq.c_cc != 0)
+ sbbc_cnputc(tp->t_dev, getc(&tp->t_outq));
+ tp->t_state &= ~TS_BUSY;
+ splx(s);
+}
+
+int
+sbbcstop(struct tty *tp, int flag)
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ splx(s);
+ return (0);
+}
+
+struct tty *
+sbbctty(dev_t dev)
+{
+ struct sbbc_softc *sc;
+ int unit = minor(dev);
+
+ if (unit > sbbc_cd.cd_ndevs)
+ return (NULL);
+ sc = sbbc_cd.cd_devs[unit];
+ if (sc == NULL)
+ return (NULL);
+
+ return sc->sc_tty;
+}
+
+int
+sbbcparam(struct tty *tp, struct termios *t)
+{
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+ return (0);
+}
+
+void
+sbbctimeout(void *v)
+{
+ struct sbbc_softc *sc = v;
+ struct tty *tp = sc->sc_tty;
+ int c;
+
+ while (sbbc_cnlookc(tp->t_dev, &c)) {
+ if (tp->t_state & TS_ISOPEN)
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ timeout_add(&sc->sc_to, 1);
+}
diff --git a/sys/arch/sparc64/include/conf.h b/sys/arch/sparc64/include/conf.h
index baaf21cb424..358e74b792c 100644
--- a/sys/arch/sparc64/include/conf.h
+++ b/sys/arch/sparc64/include/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.17 2008/06/26 05:42:13 ray Exp $ */
+/* $OpenBSD: conf.h,v 1.18 2008/07/07 14:46:18 kettenis Exp $ */
/* $NetBSD: conf.h,v 1.9 2001/03/26 12:33:26 lukem Exp $ */
/*-
@@ -99,6 +99,7 @@ cdev_decl(sabtty);
cdev_decl(pcons);
cdev_decl(vcons);
+cdev_decl(sbbc);
cdev_decl(com);
diff --git a/sys/arch/sparc64/include/sparc64.h b/sys/arch/sparc64/include/sparc64.h
index 021de61cfee..3e1ec936893 100644
--- a/sys/arch/sparc64/include/sparc64.h
+++ b/sys/arch/sparc64/include/sparc64.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sparc64.h,v 1.9 2008/03/19 20:21:01 kettenis Exp $ */
+/* $OpenBSD: sparc64.h,v 1.10 2008/07/07 14:46:18 kettenis Exp $ */
/* $NetBSD: sparc64.h,v 1.3 2000/10/20 05:47:03 mrg Exp $ */
/*
@@ -54,6 +54,7 @@ int prom_itlb_load(int index, u_int64_t data, vaddr_t vaddr);
int prom_dtlb_load(int index, u_int64_t data, vaddr_t vaddr);
void prom_start_cpu(int cpu, void *func, long arg);
void prom_start_cpu_by_cpuid(int cpu, void *func, long arg);
+const char *prom_serengeti_set_console_input(const char *);
/*
* Debug
diff --git a/sys/arch/sparc64/sparc64/conf.c b/sys/arch/sparc64/sparc64/conf.c
index a4fc477ece2..c05932f5fc5 100644
--- a/sys/arch/sparc64/sparc64/conf.c
+++ b/sys/arch/sparc64/sparc64/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.47 2008/06/12 20:03:48 mglocker Exp $ */
+/* $OpenBSD: conf.c,v 1.48 2008/07/07 14:46:18 kettenis Exp $ */
/* $NetBSD: conf.c,v 1.17 2001/03/26 12:33:26 lukem Exp $ */
/*
@@ -75,6 +75,7 @@
#include "sab.h"
#include "pcons.h"
#include "vcons.h"
+#include "sbbc.h"
#include "com.h"
#include "lpt.h"
#include "bpp.h"
@@ -284,7 +285,8 @@ struct cdevsw cdevsw[] =
cdev_tty_init(NPCONS,pcons), /* 122: PROM console */
cdev_ptm_init(NPTY,ptm), /* 123: pseudo-tty ptm device */
cdev_hotplug_init(NHOTPLUG,hotplug), /* 124: devices hot plugging */
- cdev_tty_init(NVCONS,vcons) /* 125: virtual console */
+ cdev_tty_init(NVCONS,vcons), /* 125: virtual console */
+ cdev_tty_init(NSBBC,sbbc) /* 126: SBBC console */
};
int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
diff --git a/sys/arch/sparc64/sparc64/ofw_machdep.c b/sys/arch/sparc64/sparc64/ofw_machdep.c
index caa46315a46..c0f829d1da6 100644
--- a/sys/arch/sparc64/sparc64/ofw_machdep.c
+++ b/sys/arch/sparc64/sparc64/ofw_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofw_machdep.c,v 1.26 2008/07/05 22:17:21 kettenis Exp $ */
+/* $OpenBSD: ofw_machdep.c,v 1.27 2008/07/07 14:46:18 kettenis Exp $ */
/* $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $ */
/*
@@ -740,6 +740,28 @@ prom_printf(const char *fmt, ...)
OF_write(OF_stdout(), buf, len);
}
+const char *
+prom_serengeti_set_console_input(const char *new)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t new;
+ cell_t old;
+ } args;
+
+ args.name = ADR2CELL("SUNW,set-console-input");
+ args.nargs = 1;
+ args.nreturns = 1;
+ args.new = ADR2CELL(new);
+
+ if (openfirmware(&args) == -1)
+ return NULL;
+
+ return (const char *)args.old;
+}
+
#ifdef DEBUG
int ofmapintrdebug = 0;
#define DPRINTF(x) do { if (ofmapintrdebug) printf x; } while (0)