From 37344b84ca95c4acc6c1ecc7f5b56e91668b86cf Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 7 Jul 2008 14:46:18 +0000 Subject: [PATCH] Extend sbbc(4) to provide a console driver for the v1280. --- sys/arch/sparc64/conf/files.sparc64 | 4 +- sys/arch/sparc64/dev/sbbc.c | 398 ++++++++++++++++++++++++- sys/arch/sparc64/include/conf.h | 3 +- sys/arch/sparc64/include/sparc64.h | 3 +- sys/arch/sparc64/sparc64/conf.c | 6 +- sys/arch/sparc64/sparc64/ofw_machdep.c | 24 +- 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 +#include #include #include +#include +#include +#include #include +#ifdef DDB +#include +#endif + #include +#include #include +#include + +#include #include #include @@ -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, @@ -151,10 +220,32 @@ sbbc_attach(struct device *parent, struct device *self, void *aux) sc->sc_sram = bus_space_vaddr(sc->sc_iot, sc->sc_sram_ioh); 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) -- 2.20.1