1*0701a158Skettenis /* $OpenBSD: sbbc.c,v 1.15 2022/10/12 13:39:50 kettenis Exp $ */
2323f3eccSkettenis /*
3323f3eccSkettenis * Copyright (c) 2008 Mark Kettenis
4323f3eccSkettenis *
5323f3eccSkettenis * Permission to use, copy, modify, and distribute this software for any
6323f3eccSkettenis * purpose with or without fee is hereby granted, provided that the above
7323f3eccSkettenis * copyright notice and this permission notice appear in all copies.
8323f3eccSkettenis *
9323f3eccSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10323f3eccSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11323f3eccSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12323f3eccSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13323f3eccSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14323f3eccSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15323f3eccSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16323f3eccSkettenis */
17323f3eccSkettenis
18323f3eccSkettenis #include <sys/param.h>
1937344b84Skettenis #include <sys/conf.h>
20323f3eccSkettenis #include <sys/device.h>
21323f3eccSkettenis #include <sys/malloc.h>
2237344b84Skettenis #include <sys/proc.h>
2337344b84Skettenis #include <sys/timeout.h>
2437344b84Skettenis #include <sys/tty.h>
25323f3eccSkettenis #include <sys/systm.h>
26323f3eccSkettenis
2737344b84Skettenis #ifdef DDB
2837344b84Skettenis #include <ddb/db_var.h>
2937344b84Skettenis #endif
3037344b84Skettenis
31323f3eccSkettenis #include <machine/autoconf.h>
3237344b84Skettenis #include <machine/conf.h>
33323f3eccSkettenis #include <machine/openfirm.h>
3437344b84Skettenis #include <machine/sparc64.h>
3537344b84Skettenis
3637344b84Skettenis #include <dev/cons.h>
37323f3eccSkettenis
38323f3eccSkettenis #include <dev/pci/pcidevs.h>
39323f3eccSkettenis #include <dev/pci/pcireg.h>
40323f3eccSkettenis #include <dev/pci/pcivar.h>
41323f3eccSkettenis
42323f3eccSkettenis #include <dev/clock_subr.h>
43323f3eccSkettenis
44323f3eccSkettenis extern todr_chip_handle_t todr_handle;
45323f3eccSkettenis
46323f3eccSkettenis #define SBBC_PCI_BAR PCI_MAPREG_START
47323f3eccSkettenis
48323f3eccSkettenis #define SBBC_REGS_OFFSET 0x800000
49323f3eccSkettenis #define SBBC_REGS_SIZE 0x6230
5037344b84Skettenis #define SBBC_EPLD_OFFSET 0x8e0000
5137344b84Skettenis #define SBBC_EPLD_SIZE 0x20
52323f3eccSkettenis #define SBBC_SRAM_OFFSET 0x900000
53323f3eccSkettenis #define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */
54323f3eccSkettenis
5584706f18Skettenis #define SBBC_PCI_INT_STATUS 0x2320
5684706f18Skettenis #define SBBC_PCI_INT_ENABLE 0x2330
5784706f18Skettenis #define SBBC_PCI_ENABLE_INT_A 0x11
5884706f18Skettenis
5937344b84Skettenis #define SBBC_EPLD_INTERRUPT 0x13
6037344b84Skettenis #define SBBC_EPLD_INTERRUPT_ON 0x01
6137344b84Skettenis
6237344b84Skettenis #define SBBC_SRAM_CONS_IN 0x00000001
6337344b84Skettenis #define SBBC_SRAM_CONS_OUT 0x00000002
6437344b84Skettenis #define SBBC_SRAM_CONS_BRK 0x00000004
6537344b84Skettenis #define SBBC_SRAM_CONS_SPACE_IN 0x00000008
6637344b84Skettenis #define SBBC_SRAM_CONS_SPACE_OUT 0x00000010
6737344b84Skettenis
68323f3eccSkettenis #define SBBC_MAX_TAGS 32
69323f3eccSkettenis
70323f3eccSkettenis struct sbbc_sram_tag {
71323f3eccSkettenis char tag_key[8];
72323f3eccSkettenis uint32_t tag_size;
73323f3eccSkettenis uint32_t tag_offset;
74323f3eccSkettenis };
75323f3eccSkettenis
76323f3eccSkettenis struct sbbc_sram_toc {
77323f3eccSkettenis char toc_magic[8];
78323f3eccSkettenis uint8_t toc_reserved;
79323f3eccSkettenis uint8_t toc_type;
80323f3eccSkettenis uint16_t toc_version;
81323f3eccSkettenis uint32_t toc_ntags;
82323f3eccSkettenis struct sbbc_sram_tag toc_tag[SBBC_MAX_TAGS];
83323f3eccSkettenis };
84323f3eccSkettenis
85323f3eccSkettenis /* Time of day service. */
86323f3eccSkettenis struct sbbc_sram_tod {
87323f3eccSkettenis uint32_t tod_magic;
88323f3eccSkettenis uint32_t tod_version;
89323f3eccSkettenis uint64_t tod_time;
90323f3eccSkettenis uint64_t tod_skew;
91323f3eccSkettenis uint32_t tod_reserved;
92323f3eccSkettenis uint32_t tod_heartbeat;
93323f3eccSkettenis uint32_t tod_timeout;
94323f3eccSkettenis };
95323f3eccSkettenis
9637344b84Skettenis #define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */
97323f3eccSkettenis #define SBBC_TOD_VERSION 1
98323f3eccSkettenis
9937344b84Skettenis /* Console service. */
10037344b84Skettenis struct sbbc_sram_cons {
10137344b84Skettenis uint32_t cons_magic;
10237344b84Skettenis uint32_t cons_version;
10337344b84Skettenis uint32_t cons_size;
10437344b84Skettenis
10537344b84Skettenis uint32_t cons_in_begin;
10637344b84Skettenis uint32_t cons_in_end;
10737344b84Skettenis uint32_t cons_in_rdptr;
10837344b84Skettenis uint32_t cons_in_wrptr;
10937344b84Skettenis
11037344b84Skettenis uint32_t cons_out_begin;
11137344b84Skettenis uint32_t cons_out_end;
11237344b84Skettenis uint32_t cons_out_rdptr;
11337344b84Skettenis uint32_t cons_out_wrptr;
11437344b84Skettenis };
11537344b84Skettenis
11637344b84Skettenis #define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */
11737344b84Skettenis #define SBBC_CONS_VERSION 1
11837344b84Skettenis
119323f3eccSkettenis struct sbbc_softc {
120323f3eccSkettenis struct device sc_dv;
121323f3eccSkettenis bus_space_tag_t sc_iot;
12237344b84Skettenis bus_space_handle_t sc_regs_ioh;
12337344b84Skettenis bus_space_handle_t sc_epld_ioh;
124323f3eccSkettenis bus_space_handle_t sc_sram_ioh;
125323f3eccSkettenis caddr_t sc_sram;
126323f3eccSkettenis uint32_t sc_sram_toc;
12784706f18Skettenis void * sc_ih;
128323f3eccSkettenis
129323f3eccSkettenis struct sparc_bus_space_tag sc_bbt;
13037344b84Skettenis
13137344b84Skettenis struct tty *sc_tty;
13237344b84Skettenis caddr_t sc_sram_cons;
13384706f18Skettenis uint32_t *sc_sram_solscie;
13484706f18Skettenis uint32_t *sc_sram_solscir;
13584706f18Skettenis uint32_t *sc_sram_scsolie;
13684706f18Skettenis uint32_t *sc_sram_scsolir;
1378baf2ce4Skettenis void *sc_cons_si;
138323f3eccSkettenis };
139323f3eccSkettenis
14037344b84Skettenis struct sbbc_softc *sbbc_cons_input;
14137344b84Skettenis struct sbbc_softc *sbbc_cons_output;
14237344b84Skettenis
143323f3eccSkettenis int sbbc_match(struct device *, void *, void *);
144323f3eccSkettenis void sbbc_attach(struct device *, struct device *, void *);
145323f3eccSkettenis
146eb7eaf8dSmpi const struct cfattach sbbc_ca = {
147323f3eccSkettenis sizeof(struct sbbc_softc), sbbc_match, sbbc_attach
148323f3eccSkettenis };
149323f3eccSkettenis
150323f3eccSkettenis struct cfdriver sbbc_cd = {
151323f3eccSkettenis NULL, "sbbc", DV_DULL
152323f3eccSkettenis };
153323f3eccSkettenis
15484706f18Skettenis int sbbc_intr(void *);
15537344b84Skettenis void sbbc_send_intr(struct sbbc_softc *sc);
15637344b84Skettenis
157323f3eccSkettenis void sbbc_attach_tod(struct sbbc_softc *, uint32_t);
158323f3eccSkettenis int sbbc_tod_gettime(todr_chip_handle_t, struct timeval *);
159323f3eccSkettenis int sbbc_tod_settime(todr_chip_handle_t, struct timeval *);
160323f3eccSkettenis
16137344b84Skettenis void sbbc_attach_cons(struct sbbc_softc *, uint32_t);
1628baf2ce4Skettenis void sbbc_intr_cons(struct sbbc_softc *, uint32_t);
1638baf2ce4Skettenis void sbbc_softintr_cons(void *);
16437344b84Skettenis int sbbc_cnlookc(dev_t, int *);
16537344b84Skettenis int sbbc_cngetc(dev_t);
16637344b84Skettenis void sbbc_cnputc(dev_t, int);
16737344b84Skettenis void sbbcstart(struct tty *);
16837344b84Skettenis int sbbcparam(struct tty *, struct termios *);
16937344b84Skettenis
170323f3eccSkettenis int
sbbc_match(struct device * parent,void * match,void * aux)171323f3eccSkettenis sbbc_match(struct device *parent, void *match, void *aux)
172323f3eccSkettenis {
173323f3eccSkettenis struct pci_attach_args *pa = aux;
174323f3eccSkettenis
175323f3eccSkettenis if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
176323f3eccSkettenis (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_SBBC))
177323f3eccSkettenis return (1);
178323f3eccSkettenis
179323f3eccSkettenis return (0);
180323f3eccSkettenis }
181323f3eccSkettenis
182323f3eccSkettenis void
sbbc_attach(struct device * parent,struct device * self,void * aux)183323f3eccSkettenis sbbc_attach(struct device *parent, struct device *self, void *aux)
184323f3eccSkettenis {
185323f3eccSkettenis struct sbbc_softc *sc = (void *)self;
186323f3eccSkettenis struct pci_attach_args *pa = aux;
187323f3eccSkettenis struct sbbc_sram_toc *toc;
188323f3eccSkettenis bus_addr_t base;
189323f3eccSkettenis bus_size_t size;
19084706f18Skettenis pci_intr_handle_t ih;
191323f3eccSkettenis int chosen, iosram;
192323f3eccSkettenis int i;
193323f3eccSkettenis
194323f3eccSkettenis /* XXX Don't byteswap. */
195323f3eccSkettenis sc->sc_bbt = *pa->pa_memt;
196323f3eccSkettenis sc->sc_bbt.sasi = ASI_PRIMARY;
197323f3eccSkettenis sc->sc_iot = &sc->sc_bbt;
198323f3eccSkettenis
199323f3eccSkettenis if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, SBBC_PCI_BAR,
200323f3eccSkettenis PCI_MAPREG_TYPE_MEM, &base, &size, NULL)) {
201323f3eccSkettenis printf(": can't find register space\n");
202323f3eccSkettenis return;
203323f3eccSkettenis }
204323f3eccSkettenis
20584706f18Skettenis if (bus_space_map(sc->sc_iot, base + SBBC_REGS_OFFSET,
20684706f18Skettenis SBBC_REGS_SIZE, 0, &sc->sc_regs_ioh)) {
20784706f18Skettenis printf(": can't map register space\n");
20884706f18Skettenis return;
20984706f18Skettenis }
21084706f18Skettenis
21137344b84Skettenis if (bus_space_map(sc->sc_iot, base + SBBC_EPLD_OFFSET,
21237344b84Skettenis SBBC_EPLD_SIZE, 0, &sc->sc_epld_ioh)) {
21337344b84Skettenis printf(": can't map EPLD registers\n");
21484706f18Skettenis goto unmap_regs;
21537344b84Skettenis }
21637344b84Skettenis
217323f3eccSkettenis if (bus_space_map(sc->sc_iot, base + SBBC_SRAM_OFFSET,
218323f3eccSkettenis SBBC_SRAM_SIZE, 0, &sc->sc_sram_ioh)) {
219323f3eccSkettenis printf(": can't map SRAM\n");
22084706f18Skettenis goto unmap_epld;
221323f3eccSkettenis }
222323f3eccSkettenis
22384706f18Skettenis if (pci_intr_map(pa, &ih)) {
22484706f18Skettenis printf(": unable to map interrupt\n");
22584706f18Skettenis goto unmap_sram;
22684706f18Skettenis }
22784706f18Skettenis printf(": %s\n", pci_intr_string(pa->pa_pc, ih));
22884706f18Skettenis
22984706f18Skettenis sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY,
23084706f18Skettenis sbbc_intr, sc, sc->sc_dv.dv_xname);
23184706f18Skettenis if (sc->sc_ih == NULL) {
232c7fa4ef3Skettenis printf("%s: unable to establish interrupt\n", sc->sc_dv.dv_xname);
23384706f18Skettenis goto unmap_sram;
23484706f18Skettenis }
23584706f18Skettenis
23684706f18Skettenis bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
23784706f18Skettenis SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
23884706f18Skettenis
239323f3eccSkettenis /* Check if we are the chosen one. */
240323f3eccSkettenis chosen = OF_finddevice("/chosen");
241323f3eccSkettenis if (OF_getprop(chosen, "iosram", &iosram, sizeof(iosram)) <= 0 ||
24284706f18Skettenis PCITAG_NODE(pa->pa_tag) != iosram)
243323f3eccSkettenis return;
244323f3eccSkettenis
245323f3eccSkettenis /* SRAM TOC offset defaults to 0. */
246323f3eccSkettenis if (OF_getprop(chosen, "iosram-toc", &sc->sc_sram_toc,
247323f3eccSkettenis sizeof(sc->sc_sram_toc)) <= 0)
248323f3eccSkettenis sc->sc_sram_toc = 0;
249323f3eccSkettenis
250323f3eccSkettenis sc->sc_sram = bus_space_vaddr(sc->sc_iot, sc->sc_sram_ioh);
251323f3eccSkettenis toc = (struct sbbc_sram_toc *)(sc->sc_sram + sc->sc_sram_toc);
252323f3eccSkettenis
253323f3eccSkettenis for (i = 0; i < toc->toc_ntags; i++) {
25437344b84Skettenis if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIE") == 0)
25584706f18Skettenis sc->sc_sram_solscie = (uint32_t *)
25637344b84Skettenis (sc->sc_sram + toc->toc_tag[i].tag_offset);
25737344b84Skettenis if (strcmp(toc->toc_tag[i].tag_key, "SOLSCIR") == 0)
25884706f18Skettenis sc->sc_sram_solscir = (uint32_t *)
25984706f18Skettenis (sc->sc_sram + toc->toc_tag[i].tag_offset);
26084706f18Skettenis if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIE") == 0)
26184706f18Skettenis sc->sc_sram_scsolie = (uint32_t *)
26284706f18Skettenis (sc->sc_sram + toc->toc_tag[i].tag_offset);
26384706f18Skettenis if (strcmp(toc->toc_tag[i].tag_key, "SCSOLIR") == 0)
26484706f18Skettenis sc->sc_sram_scsolir = (uint32_t *)
26537344b84Skettenis (sc->sc_sram + toc->toc_tag[i].tag_offset);
26637344b84Skettenis }
26737344b84Skettenis
26837344b84Skettenis for (i = 0; i < toc->toc_ntags; i++) {
269323f3eccSkettenis if (strcmp(toc->toc_tag[i].tag_key, "TODDATA") == 0)
270323f3eccSkettenis sbbc_attach_tod(sc, toc->toc_tag[i].tag_offset);
27137344b84Skettenis if (strcmp(toc->toc_tag[i].tag_key, "SOLCONS") == 0)
27237344b84Skettenis sbbc_attach_cons(sc, toc->toc_tag[i].tag_offset);
273323f3eccSkettenis }
27437344b84Skettenis
27584706f18Skettenis return;
27684706f18Skettenis
27784706f18Skettenis unmap_sram:
27884706f18Skettenis bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_SRAM_SIZE);
27984706f18Skettenis unmap_epld:
28084706f18Skettenis bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_EPLD_SIZE);
28184706f18Skettenis unmap_regs:
28284706f18Skettenis bus_space_unmap(sc->sc_iot, sc->sc_sram_ioh, SBBC_REGS_SIZE);
28384706f18Skettenis }
28484706f18Skettenis
28584706f18Skettenis int
sbbc_intr(void * arg)28684706f18Skettenis sbbc_intr(void *arg)
28784706f18Skettenis {
28884706f18Skettenis struct sbbc_softc *sc = arg;
28984706f18Skettenis uint32_t status, reason;
29084706f18Skettenis
29184706f18Skettenis status = bus_space_read_4(sc->sc_iot, sc->sc_regs_ioh,
29284706f18Skettenis SBBC_PCI_INT_STATUS);
29384706f18Skettenis if (status == 0)
29484706f18Skettenis return (0);
29584706f18Skettenis
29684706f18Skettenis /* Sigh, we cannot use compare and swap for non-cachable memory. */
29784706f18Skettenis reason = *sc->sc_sram_scsolir;
29884706f18Skettenis *sc->sc_sram_scsolir = 0;
29984706f18Skettenis
3008baf2ce4Skettenis sbbc_intr_cons(sc, reason);
30184706f18Skettenis
30284706f18Skettenis /* Ack interrupt. */
30384706f18Skettenis bus_space_write_4(sc->sc_iot, sc->sc_regs_ioh,
30484706f18Skettenis SBBC_PCI_INT_STATUS, status);
30584706f18Skettenis return (1);
30637344b84Skettenis }
30737344b84Skettenis
30837344b84Skettenis void
sbbc_send_intr(struct sbbc_softc * sc)30937344b84Skettenis sbbc_send_intr(struct sbbc_softc *sc)
31037344b84Skettenis {
31137344b84Skettenis bus_space_write_1(sc->sc_iot, sc->sc_epld_ioh,
31237344b84Skettenis SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
313323f3eccSkettenis }
314323f3eccSkettenis
315323f3eccSkettenis void
sbbc_attach_tod(struct sbbc_softc * sc,uint32_t offset)316323f3eccSkettenis sbbc_attach_tod(struct sbbc_softc *sc, uint32_t offset)
317323f3eccSkettenis {
318323f3eccSkettenis struct sbbc_sram_tod *tod;
319323f3eccSkettenis todr_chip_handle_t handle;
320323f3eccSkettenis
321323f3eccSkettenis tod = (struct sbbc_sram_tod *)(sc->sc_sram + offset);
322323f3eccSkettenis if (tod->tod_magic != SBBC_TOD_MAGIC ||
323323f3eccSkettenis tod->tod_version < SBBC_TOD_VERSION)
324323f3eccSkettenis return;
325323f3eccSkettenis
326323f3eccSkettenis handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF, M_NOWAIT);
327323f3eccSkettenis if (handle == NULL)
328323f3eccSkettenis panic("couldn't allocate todr_handle");
329323f3eccSkettenis
330323f3eccSkettenis handle->cookie = tod;
331323f3eccSkettenis handle->todr_gettime = sbbc_tod_gettime;
332323f3eccSkettenis handle->todr_settime = sbbc_tod_settime;
333323f3eccSkettenis handle->bus_cookie = NULL;
334323f3eccSkettenis handle->todr_setwen = NULL;
335*0701a158Skettenis handle->todr_quality = 0;
336323f3eccSkettenis todr_handle = handle;
337323f3eccSkettenis }
338323f3eccSkettenis
339323f3eccSkettenis int
sbbc_tod_gettime(todr_chip_handle_t handle,struct timeval * tv)340323f3eccSkettenis sbbc_tod_gettime(todr_chip_handle_t handle, struct timeval *tv)
341323f3eccSkettenis {
342323f3eccSkettenis struct sbbc_sram_tod *tod = handle->cookie;
343323f3eccSkettenis
344323f3eccSkettenis tv->tv_sec = tod->tod_time + tod->tod_skew;
345323f3eccSkettenis tv->tv_usec = 0;
346323f3eccSkettenis return (0);
347323f3eccSkettenis }
348323f3eccSkettenis
349323f3eccSkettenis int
sbbc_tod_settime(todr_chip_handle_t handle,struct timeval * tv)350323f3eccSkettenis sbbc_tod_settime(todr_chip_handle_t handle, struct timeval *tv)
351323f3eccSkettenis {
352323f3eccSkettenis struct sbbc_sram_tod *tod = handle->cookie;
353323f3eccSkettenis
354323f3eccSkettenis tod->tod_skew = tv->tv_sec - tod->tod_time;
355323f3eccSkettenis return (0);
356323f3eccSkettenis }
35737344b84Skettenis
35837344b84Skettenis void
sbbc_attach_cons(struct sbbc_softc * sc,uint32_t offset)35937344b84Skettenis sbbc_attach_cons(struct sbbc_softc *sc, uint32_t offset)
36037344b84Skettenis {
36137344b84Skettenis struct sbbc_sram_cons *cons;
36237344b84Skettenis int sgcn_is_input, sgcn_is_output, node, maj;
36337344b84Skettenis char buf[32];
36437344b84Skettenis
36584706f18Skettenis if (sc->sc_sram_solscie == NULL || sc->sc_sram_solscir == NULL ||
36684706f18Skettenis sc->sc_sram_scsolie == NULL || sc->sc_sram_scsolir == NULL)
36784706f18Skettenis return;
36884706f18Skettenis
36937344b84Skettenis cons = (struct sbbc_sram_cons *)(sc->sc_sram + offset);
37037344b84Skettenis if (cons->cons_magic != SBBC_CONS_MAGIC ||
37137344b84Skettenis cons->cons_version < SBBC_CONS_VERSION)
37237344b84Skettenis return;
37337344b84Skettenis
37437344b84Skettenis sc->sc_sram_cons = sc->sc_sram + offset;
37537344b84Skettenis sbbc_cons_input = sbbc_cons_output = sc;
37637344b84Skettenis sgcn_is_input = sgcn_is_output = 0;
37737344b84Skettenis
3788baf2ce4Skettenis sc->sc_cons_si = softintr_establish(IPL_TTY, sbbc_softintr_cons, sc);
3798baf2ce4Skettenis if (sc->sc_cons_si == NULL)
3808baf2ce4Skettenis panic("%s: can't establish soft interrupt",
3818baf2ce4Skettenis sc->sc_dv.dv_xname);
38237344b84Skettenis
38384706f18Skettenis *sc->sc_sram_solscie |= SBBC_SRAM_CONS_OUT;
3848baf2ce4Skettenis *sc->sc_sram_scsolie |= SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK;
38584706f18Skettenis
38637344b84Skettenis /* Take over console input. */
38737344b84Skettenis prom_serengeti_set_console_input("CON_CLNT");
38837344b84Skettenis
38937344b84Skettenis /* Check for console input. */
39037344b84Skettenis node = OF_instance_to_package(OF_stdin());
39137344b84Skettenis if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
39237344b84Skettenis sgcn_is_input = (strcmp(buf, "sgcn") == 0);
39337344b84Skettenis
39437344b84Skettenis /* Check for console output. */
39537344b84Skettenis node = OF_instance_to_package(OF_stdout());
39637344b84Skettenis if (OF_getprop(node, "name", buf, sizeof(buf)) > 0)
39737344b84Skettenis sgcn_is_output = (strcmp(buf, "sgcn") == 0);
39837344b84Skettenis
39937344b84Skettenis if (sgcn_is_input) {
40037344b84Skettenis cn_tab->cn_pollc = nullcnpollc;
40137344b84Skettenis cn_tab->cn_getc = sbbc_cngetc;
40237344b84Skettenis }
40337344b84Skettenis
40437344b84Skettenis if (sgcn_is_output)
40537344b84Skettenis cn_tab->cn_putc = sbbc_cnputc;
40637344b84Skettenis
40737344b84Skettenis if (sgcn_is_input || sgcn_is_output) {
40837344b84Skettenis /* Locate the major number. */
40937344b84Skettenis for (maj = 0; maj < nchrdev; maj++)
41037344b84Skettenis if (cdevsw[maj].d_open == sbbcopen)
41137344b84Skettenis break;
41237344b84Skettenis cn_tab->cn_dev = makedev(maj, sc->sc_dv.dv_unit);
41337344b84Skettenis
41437344b84Skettenis /* Let current output drain. */
41537344b84Skettenis DELAY(2000000);
41637344b84Skettenis
41784706f18Skettenis printf("%s: console\n", sc->sc_dv.dv_xname);
41837344b84Skettenis }
41937344b84Skettenis }
42037344b84Skettenis
4218baf2ce4Skettenis void
sbbc_intr_cons(struct sbbc_softc * sc,uint32_t reason)4228baf2ce4Skettenis sbbc_intr_cons(struct sbbc_softc *sc, uint32_t reason)
4238baf2ce4Skettenis {
4248baf2ce4Skettenis #ifdef DDB
4258baf2ce4Skettenis if ((reason & SBBC_SRAM_CONS_BRK) && sc == sbbc_cons_input) {
4268baf2ce4Skettenis if (db_console)
427e97088d6Smpi db_enter();
4288baf2ce4Skettenis }
4298baf2ce4Skettenis #endif
4308baf2ce4Skettenis
4318baf2ce4Skettenis if ((reason & SBBC_SRAM_CONS_IN) && sc->sc_tty)
4328baf2ce4Skettenis softintr_schedule(sc->sc_cons_si);
4338baf2ce4Skettenis }
4348baf2ce4Skettenis
4358baf2ce4Skettenis void
sbbc_softintr_cons(void * arg)4368baf2ce4Skettenis sbbc_softintr_cons(void *arg)
4378baf2ce4Skettenis {
4388baf2ce4Skettenis struct sbbc_softc *sc = arg;
4398baf2ce4Skettenis struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
4408baf2ce4Skettenis uint32_t rdptr = cons->cons_in_rdptr;
4418baf2ce4Skettenis struct tty *tp = sc->sc_tty;
4428baf2ce4Skettenis int c;
4438baf2ce4Skettenis
4448baf2ce4Skettenis while (rdptr != cons->cons_in_wrptr) {
4458baf2ce4Skettenis if (tp->t_state & TS_ISOPEN) {
4468baf2ce4Skettenis c = *(sc->sc_sram_cons + rdptr);
4478baf2ce4Skettenis (*linesw[tp->t_line].l_rint)(c, tp);
4488baf2ce4Skettenis }
4498baf2ce4Skettenis
4508baf2ce4Skettenis if (++rdptr == cons->cons_in_end)
4518baf2ce4Skettenis rdptr = cons->cons_in_begin;
4528baf2ce4Skettenis }
4538baf2ce4Skettenis
4548baf2ce4Skettenis cons->cons_in_rdptr = rdptr;
4558baf2ce4Skettenis }
4568baf2ce4Skettenis
45737344b84Skettenis int
sbbc_cnlookc(dev_t dev,int * cp)45837344b84Skettenis sbbc_cnlookc(dev_t dev, int *cp)
45937344b84Skettenis {
46037344b84Skettenis struct sbbc_softc *sc = sbbc_cons_input;
46137344b84Skettenis struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
46237344b84Skettenis uint32_t rdptr = cons->cons_in_rdptr;
46337344b84Skettenis
46437344b84Skettenis if (rdptr == cons->cons_in_wrptr)
46537344b84Skettenis return (0);
46637344b84Skettenis
46737344b84Skettenis *cp = *(sc->sc_sram_cons + rdptr);
46837344b84Skettenis if (++rdptr == cons->cons_in_end)
46937344b84Skettenis rdptr = cons->cons_in_begin;
47037344b84Skettenis cons->cons_in_rdptr = rdptr;
47137344b84Skettenis
47237344b84Skettenis return (1);
47337344b84Skettenis }
47437344b84Skettenis
47537344b84Skettenis int
sbbc_cngetc(dev_t dev)47637344b84Skettenis sbbc_cngetc(dev_t dev)
47737344b84Skettenis {
47837344b84Skettenis int c;
47937344b84Skettenis
48037344b84Skettenis while(!sbbc_cnlookc(dev, &c))
48137344b84Skettenis ;
48237344b84Skettenis
48337344b84Skettenis return (c);
48437344b84Skettenis }
48537344b84Skettenis
48637344b84Skettenis void
sbbc_cnputc(dev_t dev,int c)48737344b84Skettenis sbbc_cnputc(dev_t dev, int c)
48837344b84Skettenis {
48937344b84Skettenis struct sbbc_softc *sc = sbbc_cons_output;
49037344b84Skettenis struct sbbc_sram_cons *cons = (void *)sc->sc_sram_cons;
49137344b84Skettenis uint32_t wrptr = cons->cons_out_wrptr;
49237344b84Skettenis
49337344b84Skettenis *(sc->sc_sram_cons + wrptr) = c;
49437344b84Skettenis if (++wrptr == cons->cons_out_end)
49537344b84Skettenis wrptr = cons->cons_out_begin;
49637344b84Skettenis cons->cons_out_wrptr = wrptr;
49737344b84Skettenis
49884706f18Skettenis *sc->sc_sram_solscir |= SBBC_SRAM_CONS_OUT;
49937344b84Skettenis sbbc_send_intr(sc);
50037344b84Skettenis }
50137344b84Skettenis
50237344b84Skettenis int
sbbcopen(dev_t dev,int flag,int mode,struct proc * p)50337344b84Skettenis sbbcopen(dev_t dev, int flag, int mode, struct proc *p)
50437344b84Skettenis {
50537344b84Skettenis struct sbbc_softc *sc;
50637344b84Skettenis struct tty *tp;
50737344b84Skettenis int unit = minor(dev);
50837344b84Skettenis
509e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
51037344b84Skettenis return (ENXIO);
51137344b84Skettenis sc = sbbc_cd.cd_devs[unit];
51237344b84Skettenis if (sc == NULL)
51337344b84Skettenis return (ENXIO);
51437344b84Skettenis
51537344b84Skettenis if (sc->sc_tty)
51637344b84Skettenis tp = sc->sc_tty;
51737344b84Skettenis else
518197ff252Sderaadt tp = sc->sc_tty = ttymalloc(0);
51937344b84Skettenis
52037344b84Skettenis tp->t_oproc = sbbcstart;
52137344b84Skettenis tp->t_param = sbbcparam;
52237344b84Skettenis tp->t_dev = dev;
52337344b84Skettenis if ((tp->t_state & TS_ISOPEN) == 0) {
52437344b84Skettenis ttychars(tp);
52537344b84Skettenis tp->t_iflag = TTYDEF_IFLAG;
52637344b84Skettenis tp->t_oflag = TTYDEF_OFLAG;
52737344b84Skettenis tp->t_cflag = TTYDEF_CFLAG;
52837344b84Skettenis tp->t_lflag = TTYDEF_LFLAG;
52937344b84Skettenis tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
53037344b84Skettenis ttsetwater(tp);
5313e676399Smpi } else if ((tp->t_state & TS_XCLUDE) && suser(p))
53237344b84Skettenis return (EBUSY);
53337344b84Skettenis tp->t_state |= TS_CARR_ON;
53437344b84Skettenis
53579f6c33aStedu return ((*linesw[tp->t_line].l_open)(dev, tp, p));
53637344b84Skettenis }
53737344b84Skettenis
53837344b84Skettenis int
sbbcclose(dev_t dev,int flag,int mode,struct proc * p)53937344b84Skettenis sbbcclose(dev_t dev, int flag, int mode, struct proc *p)
54037344b84Skettenis {
54137344b84Skettenis struct sbbc_softc *sc;
54237344b84Skettenis struct tty *tp;
54337344b84Skettenis int unit = minor(dev);
54437344b84Skettenis
545e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
54637344b84Skettenis return (ENXIO);
54737344b84Skettenis sc = sbbc_cd.cd_devs[unit];
54837344b84Skettenis if (sc == NULL)
54937344b84Skettenis return (ENXIO);
55037344b84Skettenis
55137344b84Skettenis tp = sc->sc_tty;
55279f6c33aStedu (*linesw[tp->t_line].l_close)(tp, flag, p);
55337344b84Skettenis ttyclose(tp);
55437344b84Skettenis return (0);
55537344b84Skettenis }
55637344b84Skettenis
55737344b84Skettenis int
sbbcread(dev_t dev,struct uio * uio,int flag)55837344b84Skettenis sbbcread(dev_t dev, struct uio *uio, int flag)
55937344b84Skettenis {
56037344b84Skettenis struct sbbc_softc *sc;
56137344b84Skettenis struct tty *tp;
56237344b84Skettenis int unit = minor(dev);
56337344b84Skettenis
564e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
56537344b84Skettenis return (ENXIO);
56637344b84Skettenis sc = sbbc_cd.cd_devs[unit];
56737344b84Skettenis if (sc == NULL)
56837344b84Skettenis return (ENXIO);
56937344b84Skettenis
57037344b84Skettenis tp = sc->sc_tty;
57137344b84Skettenis return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
57237344b84Skettenis }
57337344b84Skettenis
57437344b84Skettenis int
sbbcwrite(dev_t dev,struct uio * uio,int flag)57537344b84Skettenis sbbcwrite(dev_t dev, struct uio *uio, int flag)
57637344b84Skettenis {
57737344b84Skettenis struct sbbc_softc *sc;
57837344b84Skettenis struct tty *tp;
57937344b84Skettenis int unit = minor(dev);
58037344b84Skettenis
581e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
58237344b84Skettenis return (ENXIO);
58337344b84Skettenis sc = sbbc_cd.cd_devs[unit];
58437344b84Skettenis if (sc == NULL)
58537344b84Skettenis return (ENXIO);
58637344b84Skettenis
58737344b84Skettenis tp = sc->sc_tty;
58837344b84Skettenis return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
58937344b84Skettenis }
59037344b84Skettenis
59137344b84Skettenis int
sbbcioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)59237344b84Skettenis sbbcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
59337344b84Skettenis {
59437344b84Skettenis struct sbbc_softc *sc;
59537344b84Skettenis struct tty *tp;
59637344b84Skettenis int unit = minor(dev);
59737344b84Skettenis int error;
59837344b84Skettenis
599e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
60037344b84Skettenis return (ENXIO);
60137344b84Skettenis sc = sbbc_cd.cd_devs[unit];
60237344b84Skettenis if (sc == NULL)
60337344b84Skettenis return (ENXIO);
60437344b84Skettenis
60537344b84Skettenis tp = sc->sc_tty;
60637344b84Skettenis error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
60737344b84Skettenis if (error >= 0)
60837344b84Skettenis return error;
60937344b84Skettenis error = ttioctl(tp, cmd, data, flag, p);
61037344b84Skettenis if (error >= 0)
61137344b84Skettenis return (error);
61237344b84Skettenis
61337344b84Skettenis return (ENOTTY);
61437344b84Skettenis }
61537344b84Skettenis
61637344b84Skettenis void
sbbcstart(struct tty * tp)61737344b84Skettenis sbbcstart(struct tty *tp)
61837344b84Skettenis {
61937344b84Skettenis int s;
62037344b84Skettenis
62137344b84Skettenis s = spltty();
62237344b84Skettenis if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
62337344b84Skettenis splx(s);
62437344b84Skettenis return;
62537344b84Skettenis }
6264cc8800eSnicm ttwakeupwr(tp);
62737344b84Skettenis tp->t_state |= TS_BUSY;
62837344b84Skettenis while (tp->t_outq.c_cc != 0)
62937344b84Skettenis sbbc_cnputc(tp->t_dev, getc(&tp->t_outq));
63037344b84Skettenis tp->t_state &= ~TS_BUSY;
63137344b84Skettenis splx(s);
63237344b84Skettenis }
63337344b84Skettenis
63437344b84Skettenis int
sbbcstop(struct tty * tp,int flag)63537344b84Skettenis sbbcstop(struct tty *tp, int flag)
63637344b84Skettenis {
63737344b84Skettenis int s;
63837344b84Skettenis
63937344b84Skettenis s = spltty();
64037344b84Skettenis if (tp->t_state & TS_BUSY)
64137344b84Skettenis if ((tp->t_state & TS_TTSTOP) == 0)
64237344b84Skettenis tp->t_state |= TS_FLUSH;
64337344b84Skettenis splx(s);
64437344b84Skettenis return (0);
64537344b84Skettenis }
64637344b84Skettenis
64737344b84Skettenis struct tty *
sbbctty(dev_t dev)64837344b84Skettenis sbbctty(dev_t dev)
64937344b84Skettenis {
65037344b84Skettenis struct sbbc_softc *sc;
65137344b84Skettenis int unit = minor(dev);
65237344b84Skettenis
653e7c7aa84Smiod if (unit >= sbbc_cd.cd_ndevs)
65437344b84Skettenis return (NULL);
65537344b84Skettenis sc = sbbc_cd.cd_devs[unit];
65637344b84Skettenis if (sc == NULL)
65737344b84Skettenis return (NULL);
65837344b84Skettenis
65937344b84Skettenis return sc->sc_tty;
66037344b84Skettenis }
66137344b84Skettenis
66237344b84Skettenis int
sbbcparam(struct tty * tp,struct termios * t)66337344b84Skettenis sbbcparam(struct tty *tp, struct termios *t)
66437344b84Skettenis {
66537344b84Skettenis tp->t_ispeed = t->c_ispeed;
66637344b84Skettenis tp->t_ospeed = t->c_ospeed;
66737344b84Skettenis tp->t_cflag = t->c_cflag;
66837344b84Skettenis return (0);
66937344b84Skettenis }
670