]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sparc64/pci/sbbc.c
MFV r329799, r329800:
[FreeBSD/FreeBSD.git] / sys / sparc64 / pci / sbbc.c
1 /*      $OpenBSD: sbbc.c,v 1.7 2009/11/09 17:53:39 nicm Exp $   */
2 /*-
3  * SPDX-License-Identifier: (ISC AND BSD-2-Clause-FreeBSD)
4  *
5  * Copyright (c) 2008 Mark Kettenis
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 /*-
20  * Copyright (c) 2010 Marius Strobl <marius@FreeBSD.org>
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/bus.h>
51 #include <sys/clock.h>
52 #include <sys/endian.h>
53 #include <sys/kernel.h>
54 #include <sys/lock.h>
55 #include <sys/module.h>
56 #include <sys/mutex.h>
57 #include <sys/resource.h>
58 #include <sys/rman.h>
59
60 #include <dev/ofw/ofw_bus.h>
61 #include <dev/ofw/openfirm.h>
62
63 #include <machine/bus.h>
64 #include <machine/cpu.h>
65 #include <machine/resource.h>
66
67 #include <dev/pci/pcireg.h>
68 #include <dev/pci/pcivar.h>
69 #include <dev/uart/uart.h>
70 #include <dev/uart/uart_cpu.h>
71 #include <dev/uart/uart_bus.h>
72
73 #include "clock_if.h"
74 #include "uart_if.h"
75
76 #define SBBC_PCI_BAR            PCIR_BAR(0)
77 #define SBBC_PCI_VENDOR         0x108e
78 #define SBBC_PCI_PRODUCT        0xc416
79
80 #define SBBC_REGS_OFFSET        0x800000
81 #define SBBC_REGS_SIZE          0x6230
82 #define SBBC_EPLD_OFFSET        0x8e0000
83 #define SBBC_EPLD_SIZE          0x20
84 #define SBBC_SRAM_OFFSET        0x900000
85 #define SBBC_SRAM_SIZE          0x20000 /* 128KB SRAM */
86
87 #define SBBC_PCI_INT_STATUS     0x2320
88 #define SBBC_PCI_INT_ENABLE     0x2330
89 #define SBBC_PCI_ENABLE_INT_A   0x11
90
91 #define SBBC_EPLD_INTERRUPT     0x13
92 #define SBBC_EPLD_INTERRUPT_ON  0x01
93
94 #define SBBC_SRAM_CONS_IN               0x00000001
95 #define SBBC_SRAM_CONS_OUT              0x00000002
96 #define SBBC_SRAM_CONS_BRK              0x00000004
97 #define SBBC_SRAM_CONS_SPACE_IN         0x00000008
98 #define SBBC_SRAM_CONS_SPACE_OUT        0x00000010
99
100 #define SBBC_TAG_KEY_SIZE       8
101 #define SBBC_TAG_KEY_SCSOLIE    "SCSOLIE"       /* SC -> OS int. enable */
102 #define SBBC_TAG_KEY_SCSOLIR    "SCSOLIR"       /* SC -> OS int. reason */
103 #define SBBC_TAG_KEY_SOLCONS    "SOLCONS"       /* OS console buffer */
104 #define SBBC_TAG_KEY_SOLSCIE    "SOLSCIE"       /* OS -> SC int. enable */
105 #define SBBC_TAG_KEY_SOLSCIR    "SOLSCIR"       /* OS -> SC int. reason */
106 #define SBBC_TAG_KEY_TODDATA    "TODDATA"       /* OS TOD struct */
107 #define SBBC_TAG_OFF(x)         offsetof(struct sbbc_sram_tag, x)
108
109 struct sbbc_sram_tag {
110         char            tag_key[SBBC_TAG_KEY_SIZE];
111         uint32_t        tag_size;
112         uint32_t        tag_offset;
113 } __packed;
114
115 #define SBBC_TOC_MAGIC          "TOCSRAM"
116 #define SBBC_TOC_MAGIC_SIZE     8
117 #define SBBC_TOC_TAGS_MAX       32
118 #define SBBC_TOC_OFF(x)         offsetof(struct sbbc_sram_toc, x)
119
120 struct sbbc_sram_toc {
121         char                    toc_magic[SBBC_TOC_MAGIC_SIZE];
122         uint8_t                 toc_reserved;
123         uint8_t                 toc_type;
124         uint16_t                toc_version;
125         uint32_t                toc_ntags;
126         struct sbbc_sram_tag    toc_tag[SBBC_TOC_TAGS_MAX];
127 } __packed;
128
129 #define SBBC_TOD_MAGIC          0x54443100      /* "TD1" */
130 #define SBBC_TOD_VERSION        1
131 #define SBBC_TOD_OFF(x)         offsetof(struct sbbc_sram_tod, x)
132
133 struct sbbc_sram_tod {
134         uint32_t        tod_magic;
135         uint32_t        tod_version;
136         uint64_t        tod_time;
137         uint64_t        tod_skew;
138         uint32_t        tod_reserved;
139         uint32_t        tod_heartbeat;
140         uint32_t        tod_timeout;
141 } __packed;
142
143 #define SBBC_CONS_MAGIC         0x434f4e00      /* "CON" */
144 #define SBBC_CONS_VERSION       1
145 #define SBBC_CONS_OFF(x)        offsetof(struct sbbc_sram_cons, x)
146
147 struct sbbc_sram_cons {
148         uint32_t cons_magic;
149         uint32_t cons_version;
150         uint32_t cons_size;
151
152         uint32_t cons_in_begin;
153         uint32_t cons_in_end;
154         uint32_t cons_in_rdptr;
155         uint32_t cons_in_wrptr;
156
157         uint32_t cons_out_begin;
158         uint32_t cons_out_end;
159         uint32_t cons_out_rdptr;
160         uint32_t cons_out_wrptr;
161 } __packed;
162
163 struct sbbc_softc {
164         struct resource *sc_res;
165 };
166
167 #define SBBC_READ_N(wdth, offs)                                         \
168         bus_space_read_ ## wdth((bst), (bsh), (offs))
169 #define SBBC_WRITE_N(wdth, offs, val)                                   \
170         bus_space_write_ ## wdth((bst), (bsh), (offs), (val))
171
172 #define SBBC_READ_1(offs)                                               \
173         SBBC_READ_N(1, (offs))
174 #define SBBC_READ_2(offs)                                               \
175         bswap16(SBBC_READ_N(2, (offs)))
176 #define SBBC_READ_4(offs)                                               \
177         bswap32(SBBC_READ_N(4, (offs)))
178 #define SBBC_READ_8(offs)                                               \
179         bswap64(SBBC_READ_N(8, (offs)))
180 #define SBBC_WRITE_1(offs, val)                                         \
181         SBBC_WRITE_N(1, (offs), (val))
182 #define SBBC_WRITE_2(offs, val)                                         \
183         SBBC_WRITE_N(2, (offs), bswap16(val))
184 #define SBBC_WRITE_4(offs, val)                                         \
185         SBBC_WRITE_N(4, (offs), bswap32(val))
186 #define SBBC_WRITE_8(offs, val)                                         \
187         SBBC_WRITE_N(8, (offs), bswap64(val))
188
189 #define SBBC_REGS_READ_1(offs)                                          \
190         SBBC_READ_1((offs) + SBBC_REGS_OFFSET)
191 #define SBBC_REGS_READ_2(offs)                                          \
192         SBBC_READ_2((offs) + SBBC_REGS_OFFSET)
193 #define SBBC_REGS_READ_4(offs)                                          \
194         SBBC_READ_4((offs) + SBBC_REGS_OFFSET)
195 #define SBBC_REGS_READ_8(offs)                                          \
196         SBBC_READ_8((offs) + SBBC_REGS_OFFSET)
197 #define SBBC_REGS_WRITE_1(offs, val)                                    \
198         SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val))
199 #define SBBC_REGS_WRITE_2(offs, val)                                    \
200         SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val))
201 #define SBBC_REGS_WRITE_4(offs, val)                                    \
202         SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val))
203 #define SBBC_REGS_WRITE_8(offs, val)                                    \
204         SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val))
205
206 #define SBBC_EPLD_READ_1(offs)                                          \
207         SBBC_READ_1((offs) + SBBC_EPLD_OFFSET)
208 #define SBBC_EPLD_READ_2(offs)                                          \
209         SBBC_READ_2((offs) + SBBC_EPLD_OFFSET)
210 #define SBBC_EPLD_READ_4(offs)                                          \
211         SBBC_READ_4((offs) + SBBC_EPLD_OFFSET)
212 #define SBBC_EPLD_READ_8(offs)                                          \
213         SBBC_READ_8((offs) + SBBC_EPLD_OFFSET)
214 #define SBBC_EPLD_WRITE_1(offs, val)                                    \
215         SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val))
216 #define SBBC_EPLD_WRITE_2(offs, val)                                    \
217         SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val))
218 #define SBBC_EPLD_WRITE_4(offs, val)                                    \
219         SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val))
220 #define SBBC_EPLD_WRITE_8(offs, val)                                    \
221         SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val))
222
223 #define SBBC_SRAM_READ_1(offs)                                          \
224         SBBC_READ_1((offs) + SBBC_SRAM_OFFSET)
225 #define SBBC_SRAM_READ_2(offs)                                          \
226         SBBC_READ_2((offs) + SBBC_SRAM_OFFSET)
227 #define SBBC_SRAM_READ_4(offs)                                          \
228         SBBC_READ_4((offs) + SBBC_SRAM_OFFSET)
229 #define SBBC_SRAM_READ_8(offs)                                          \
230         SBBC_READ_8((offs) + SBBC_SRAM_OFFSET)
231 #define SBBC_SRAM_WRITE_1(offs, val)                                    \
232         SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val))
233 #define SBBC_SRAM_WRITE_2(offs, val)                                    \
234         SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val))
235 #define SBBC_SRAM_WRITE_4(offs, val)                                    \
236         SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val))
237 #define SBBC_SRAM_WRITE_8(offs, val)                                    \
238         SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val))
239
240 #define SUNW_SETCONSINPUT       "SUNW,set-console-input"
241 #define SUNW_SETCONSINPUT_CLNT  "CON_CLNT"
242 #define SUNW_SETCONSINPUT_OBP   "CON_OBP"
243
244 static u_int sbbc_console;
245
246 static uint32_t sbbc_scsolie;
247 static uint32_t sbbc_scsolir;
248 static uint32_t sbbc_solcons;
249 static uint32_t sbbc_solscie;
250 static uint32_t sbbc_solscir;
251 static uint32_t sbbc_toddata;
252
253 /*
254  * internal helpers
255  */
256 static int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh);
257 static inline void sbbc_send_intr(bus_space_tag_t bst,
258     bus_space_handle_t bsh);
259 static const char *sbbc_serengeti_set_console_input(char *new);
260
261 /*
262  * SBBC PCI interface
263  */
264 static bus_activate_resource_t sbbc_bus_activate_resource;
265 static bus_adjust_resource_t sbbc_bus_adjust_resource;
266 static bus_deactivate_resource_t sbbc_bus_deactivate_resource;
267 static bus_alloc_resource_t sbbc_bus_alloc_resource;
268 static bus_release_resource_t sbbc_bus_release_resource;
269 static bus_get_resource_list_t sbbc_bus_get_resource_list;
270 static bus_setup_intr_t sbbc_bus_setup_intr;
271 static bus_teardown_intr_t sbbc_bus_teardown_intr;
272
273 static device_attach_t sbbc_pci_attach;
274 static device_probe_t sbbc_pci_probe;
275
276 static clock_gettime_t sbbc_tod_gettime;
277 static clock_settime_t sbbc_tod_settime;
278
279 static device_method_t sbbc_pci_methods[] = {
280         /* Device interface */
281         DEVMETHOD(device_probe,         sbbc_pci_probe),
282         DEVMETHOD(device_attach,        sbbc_pci_attach),
283
284         DEVMETHOD(bus_alloc_resource,   sbbc_bus_alloc_resource),
285         DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource),
286         DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource),
287         DEVMETHOD(bus_adjust_resource,  sbbc_bus_adjust_resource),
288         DEVMETHOD(bus_release_resource, sbbc_bus_release_resource),
289         DEVMETHOD(bus_setup_intr,       sbbc_bus_setup_intr),
290         DEVMETHOD(bus_teardown_intr,    sbbc_bus_teardown_intr),
291         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
292         DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list),
293
294         /* clock interface */
295         DEVMETHOD(clock_gettime,        sbbc_tod_gettime),
296         DEVMETHOD(clock_settime,        sbbc_tod_settime),
297
298         DEVMETHOD_END
299 };
300
301 static devclass_t sbbc_devclass;
302
303 DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc));
304 DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL);
305
306 static int
307 sbbc_pci_probe(device_t dev)
308 {
309
310         if (pci_get_vendor(dev) == SBBC_PCI_VENDOR &&
311             pci_get_device(dev) == SBBC_PCI_PRODUCT) {
312                 device_set_desc(dev, "Sun BootBus controller");
313                 return (BUS_PROBE_DEFAULT);
314         }
315         return (ENXIO);
316 }
317
318 static int
319 sbbc_pci_attach(device_t dev)
320 {
321         struct sbbc_softc *sc;
322         struct timespec ts;
323         device_t child;
324         bus_space_tag_t bst;
325         bus_space_handle_t bsh;
326         phandle_t node;
327         int error, rid;
328         uint32_t val;
329
330         /* Nothing to do if we're not the chosen one. */
331         if ((node = OF_finddevice("/chosen")) == -1) {
332                 device_printf(dev, "failed to find /chosen\n");
333                 return (ENXIO);
334         }
335         if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) {
336                 device_printf(dev, "failed to get iosram\n");
337                 return (ENXIO);
338         }
339         if (node != ofw_bus_get_node(dev))
340                 return (0);
341
342         sc = device_get_softc(dev);
343         rid = SBBC_PCI_BAR;
344         sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
345             RF_ACTIVE);
346         if (sc->sc_res == NULL) {
347                 device_printf(dev, "failed to allocate resources\n");
348                 return (ENXIO);
349         }
350         bst = rman_get_bustag(sc->sc_res);
351         bsh = rman_get_bushandle(sc->sc_res);
352         if (sbbc_console != 0) {
353                 /* Once again the interrupt pin isn't set. */
354                 if (pci_get_intpin(dev) == 0)
355                         pci_set_intpin(dev, 1);
356                 child = device_add_child(dev, NULL, -1);
357                 if (child == NULL)
358                         device_printf(dev, "failed to add UART device\n");
359                 error = bus_generic_attach(dev);
360                 if (error != 0)
361                         device_printf(dev, "failed to attach UART device\n");
362         } else {
363                 error = sbbc_parse_toc(bst, bsh);
364                 if (error != 0) {
365                         device_printf(dev, "failed to parse TOC\n");
366                         if (sbbc_console != 0) {
367                                 bus_release_resource(dev, SYS_RES_MEMORY, rid,
368                                     sc->sc_res);
369                                 return (error);
370                         }
371                 }
372         }
373         if (sbbc_toddata != 0) {
374                 if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
375                     SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC)
376                         device_printf(dev, "invalid TOD magic %#x\n", val);
377                 else if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
378                     SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION)
379                         device_printf(dev, "invalid TOD version %#x\n", val);
380                 else {
381                         clock_register(dev, 1000000); /* 1 sec. resolution */
382                         if (bootverbose) {
383                                 sbbc_tod_gettime(dev, &ts);
384                                 device_printf(dev,
385                                     "current time: %ld.%09ld\n",
386                                     (long)ts.tv_sec, ts.tv_nsec);
387                         }
388                 }
389         }
390         return (0);
391 }
392
393 /*
394  * Note that the bus methods don't pass-through the uart(4) requests but act
395  * as if they would come from sbbc(4) in order to avoid complications with
396  * pci(4) (actually, uart(4) isn't a real child but rather a function of
397  * sbbc(4) anyway).
398  */
399
400 static struct resource *
401 sbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type,
402     int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
403 {
404         struct sbbc_softc *sc;
405
406         sc = device_get_softc(dev);
407         switch (type) {
408         case SYS_RES_IRQ:
409                 return (bus_generic_alloc_resource(dev, dev, type, rid, start,
410                     end, count, flags));
411         case SYS_RES_MEMORY:
412                 return (sc->sc_res);
413         default:
414                 return (NULL);
415         }
416 }
417
418 static int
419 sbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid,
420     struct resource *res)
421 {
422
423         if (type == SYS_RES_MEMORY)
424                 return (0);
425         return (bus_generic_activate_resource(bus, child, type, rid, res));
426 }
427
428 static int
429 sbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid,
430     struct resource *res)
431 {
432
433         if (type == SYS_RES_MEMORY)
434                 return (0);
435         return (bus_generic_deactivate_resource(bus, child, type, rid, res));
436 }
437
438 static int
439 sbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused,
440     int type __unused, struct resource *res __unused, rman_res_t start __unused,
441     rman_res_t end __unused)
442 {
443
444         return (ENXIO);
445 }
446
447 static int
448 sbbc_bus_release_resource(device_t dev, device_t child __unused, int type,
449     int rid, struct resource *res)
450 {
451
452         if (type == SYS_RES_IRQ)
453                 return (bus_generic_release_resource(dev, dev, type, rid,
454                     res));
455         return (0);
456 }
457
458 static struct resource_list *
459 sbbc_bus_get_resource_list(device_t dev, device_t child __unused)
460 {
461
462         return (bus_generic_get_resource_list(dev, dev));
463 }
464
465 static int
466 sbbc_bus_setup_intr(device_t dev, device_t child __unused,
467     struct resource *res, int flags, driver_filter_t *filt,
468     driver_intr_t *intr, void *arg, void **cookiep)
469 {
470
471         return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg,
472             cookiep));
473 }
474
475 static int
476 sbbc_bus_teardown_intr(device_t dev, device_t child __unused,
477     struct resource *res, void *cookie)
478 {
479
480         return (bus_generic_teardown_intr(dev, dev, res, cookie));
481 }
482
483 /*
484  * internal helpers
485  */
486 static int
487 sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh)
488 {
489         char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)];
490         bus_size_t tag;
491         phandle_t node;
492         uint32_t off, sram_toc;
493         u_int i, tags;
494
495         if ((node = OF_finddevice("/chosen")) == -1)
496                 return (ENXIO);
497         /* SRAM TOC offset defaults to 0. */
498         if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0)
499                 sram_toc = 0;
500
501         bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc +
502             SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE);
503         buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0';
504         if (strcmp(buf, SBBC_TOC_MAGIC) != 0)
505                 return (ENXIO);
506
507         tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags));
508         for (i = 0; i < tags; i++) {
509                 tag = sram_toc + SBBC_TOC_OFF(toc_tag) +
510                     i * sizeof(struct sbbc_sram_tag);
511                 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag +
512                     SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE);
513                 buf[SBBC_TAG_KEY_SIZE - 1] = '\0';
514                 off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset));
515                 if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0)
516                         sbbc_scsolie = off;
517                 else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0)
518                         sbbc_scsolir = off;
519                 else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0)
520                         sbbc_solcons = off;
521                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0)
522                         sbbc_solscie = off;
523                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0)
524                         sbbc_solscir = off;
525                 else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0)
526                         sbbc_toddata = off;
527         }
528         return (0);
529 }
530
531 static const char *
532 sbbc_serengeti_set_console_input(char *new)
533 {
534         struct {
535                 cell_t name;
536                 cell_t nargs;
537                 cell_t nreturns;
538                 cell_t new;
539                 cell_t old;
540         } args = {
541                 (cell_t)SUNW_SETCONSINPUT,
542                 1,
543                 1,
544         };
545
546         args.new = (cell_t)new;
547         if (ofw_entry(&args) == -1)
548                 return (NULL);
549         return ((const char *)args.old);
550 }
551
552 static inline void
553 sbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh)
554 {
555
556         SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
557         bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1,
558             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
559 }
560
561 /*
562  * TOD interface
563  */
564 static int
565 sbbc_tod_gettime(device_t dev, struct timespec *ts)
566 {
567         struct sbbc_softc *sc;
568         bus_space_tag_t bst;
569         bus_space_handle_t bsh;
570
571         sc = device_get_softc(dev);
572         bst = rman_get_bustag(sc->sc_res);
573         bsh = rman_get_bushandle(sc->sc_res);
574
575         ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) +
576             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew));
577         ts->tv_nsec = 0;
578         return (0);
579 }
580
581 static int
582 sbbc_tod_settime(device_t dev, struct timespec *ts)
583 {
584         struct sbbc_softc *sc;
585         bus_space_tag_t bst;
586         bus_space_handle_t bsh;
587
588         sc = device_get_softc(dev);
589         bst = rman_get_bustag(sc->sc_res);
590         bsh = rman_get_bushandle(sc->sc_res);
591
592         SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec -
593             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)));
594         return (0);
595 }
596
597 /*
598  * UART bus front-end
599  */
600 static device_probe_t sbbc_uart_sbbc_probe;
601
602 static device_method_t sbbc_uart_sbbc_methods[] = {
603         /* Device interface */
604         DEVMETHOD(device_probe,         sbbc_uart_sbbc_probe),
605         DEVMETHOD(device_attach,        uart_bus_attach),
606         DEVMETHOD(device_detach,        uart_bus_detach),
607
608         DEVMETHOD_END
609 };
610
611 DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods,
612     sizeof(struct uart_softc));
613 DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL);
614
615 static int
616 sbbc_uart_sbbc_probe(device_t dev)
617 {
618         struct uart_softc *sc;
619
620         sc = device_get_softc(dev);
621         sc->sc_class = &uart_sbbc_class;
622         device_set_desc(dev, "Serengeti console");
623         return (uart_bus_probe(dev, 0, 0, 0, SBBC_PCI_BAR, 0));
624 }
625
626 /*
627  * Low-level UART interface
628  */
629 static int sbbc_uart_probe(struct uart_bas *bas);
630 static void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits,
631     int stopbits, int parity);
632 static void sbbc_uart_term(struct uart_bas *bas);
633 static void sbbc_uart_putc(struct uart_bas *bas, int c);
634 static int sbbc_uart_rxready(struct uart_bas *bas);
635 static int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx);
636
637 static struct uart_ops sbbc_uart_ops = {
638         .probe = sbbc_uart_probe,
639         .init = sbbc_uart_init,
640         .term = sbbc_uart_term,
641         .putc = sbbc_uart_putc,
642         .rxready = sbbc_uart_rxready,
643         .getc = sbbc_uart_getc,
644 };
645
646 static int
647 sbbc_uart_probe(struct uart_bas *bas)
648 {
649         bus_space_tag_t bst;
650         bus_space_handle_t bsh;
651         int error;
652
653         sbbc_console = 1;
654         bst = bas->bst;
655         bsh = bas->bsh;
656         error = sbbc_parse_toc(bst, bsh);
657         if (error != 0)
658                 return (error);
659
660         if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 ||
661             sbbc_solscie == 0 || sbbc_solscir == 0)
662                 return (ENXIO);
663
664         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) !=
665             SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons +
666             SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION)
667                 return (ENXIO);
668         return (0);
669 }
670
671 static void
672 sbbc_uart_init(struct uart_bas *bas, int baudrate __unused,
673     int databits __unused, int stopbits __unused, int parity __unused)
674 {
675         bus_space_tag_t bst;
676         bus_space_handle_t bsh;
677
678         bst = bas->bst;
679         bsh = bas->bsh;
680
681         /* Enable output to and space in from the SC interrupts. */
682         SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) |
683             SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN);
684         uart_barrier(bas);
685
686         /* Take over the console input. */
687         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT);
688 }
689
690 static void
691 sbbc_uart_term(struct uart_bas *bas __unused)
692 {
693
694         /* Give back the console input. */
695         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
696 }
697
698 static void
699 sbbc_uart_putc(struct uart_bas *bas, int c)
700 {
701         bus_space_tag_t bst;
702         bus_space_handle_t bsh;
703         uint32_t wrptr;
704
705         bst = bas->bst;
706         bsh = bas->bsh;
707
708         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
709             SBBC_CONS_OFF(cons_out_wrptr));
710         SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c);
711         uart_barrier(bas);
712         if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons +
713             SBBC_CONS_OFF(cons_out_end)))
714                 wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
715                     SBBC_CONS_OFF(cons_out_begin));
716         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
717             wrptr);
718         uart_barrier(bas);
719
720         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
721             SBBC_SRAM_CONS_OUT);
722         uart_barrier(bas);
723         sbbc_send_intr(bst, bsh);
724 }
725
726 static int
727 sbbc_uart_rxready(struct uart_bas *bas)
728 {
729         bus_space_tag_t bst;
730         bus_space_handle_t bsh;
731
732         bst = bas->bst;
733         bsh = bas->bsh;
734
735         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) ==
736             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr)))
737                 return (0);
738         return (1);
739 }
740
741 static int
742 sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
743 {
744         bus_space_tag_t bst;
745         bus_space_handle_t bsh;
746         int c;
747         uint32_t rdptr;
748
749         bst = bas->bst;
750         bsh = bas->bsh;
751
752         uart_lock(hwmtx);
753
754         while (sbbc_uart_rxready(bas) == 0) {
755                 uart_unlock(hwmtx);
756                 DELAY(4);
757                 uart_lock(hwmtx);
758         }
759
760         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
761         c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
762         uart_barrier(bas);
763         if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons +
764             SBBC_CONS_OFF(cons_in_end)))
765                 rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
766                     SBBC_CONS_OFF(cons_in_begin));
767         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
768             rdptr);
769         uart_barrier(bas);
770         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
771             SBBC_SRAM_CONS_SPACE_IN);
772         uart_barrier(bas);
773         sbbc_send_intr(bst, bsh);
774
775         uart_unlock(hwmtx);
776         return (c);
777 }
778
779 /*
780  * High-level UART interface
781  */
782 static int sbbc_uart_bus_attach(struct uart_softc *sc);
783 static int sbbc_uart_bus_detach(struct uart_softc *sc);
784 static int sbbc_uart_bus_flush(struct uart_softc *sc, int what);
785 static int sbbc_uart_bus_getsig(struct uart_softc *sc);
786 static int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request,
787     intptr_t data);
788 static int sbbc_uart_bus_ipend(struct uart_softc *sc);
789 static int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate,
790     int databits, int stopbits, int parity);
791 static int sbbc_uart_bus_probe(struct uart_softc *sc);
792 static int sbbc_uart_bus_receive(struct uart_softc *sc);
793 static int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig);
794 static int sbbc_uart_bus_transmit(struct uart_softc *sc);
795
796 static kobj_method_t sbbc_uart_methods[] = {
797         KOBJMETHOD(uart_attach,         sbbc_uart_bus_attach),
798         KOBJMETHOD(uart_detach,         sbbc_uart_bus_detach),
799         KOBJMETHOD(uart_flush,          sbbc_uart_bus_flush),
800         KOBJMETHOD(uart_getsig,         sbbc_uart_bus_getsig),
801         KOBJMETHOD(uart_ioctl,          sbbc_uart_bus_ioctl),
802         KOBJMETHOD(uart_ipend,          sbbc_uart_bus_ipend),
803         KOBJMETHOD(uart_param,          sbbc_uart_bus_param),
804         KOBJMETHOD(uart_probe,          sbbc_uart_bus_probe),
805         KOBJMETHOD(uart_receive,        sbbc_uart_bus_receive),
806         KOBJMETHOD(uart_setsig,         sbbc_uart_bus_setsig),
807         KOBJMETHOD(uart_transmit,       sbbc_uart_bus_transmit),
808
809         DEVMETHOD_END
810 };
811
812 struct uart_class uart_sbbc_class = {
813         "sbbc",
814         sbbc_uart_methods,
815         sizeof(struct uart_softc),
816         .uc_ops = &sbbc_uart_ops,
817         .uc_range = 1,
818         .uc_rclk = 0x5bbc,      /* arbitrary */
819         .uc_rshift = 0
820 };
821
822 #define SIGCHG(c, i, s, d)                                              \
823         if ((c) != 0) {                                                 \
824                 i |= (((i) & (s)) != 0) ? (s) : (s) | (d);              \
825         } else {                                                        \
826                 i = (((i) & (s)) != 0) ? ((i) & ~(s)) | (d) : (i);      \
827         }
828
829 static int
830 sbbc_uart_bus_attach(struct uart_softc *sc)
831 {
832         struct uart_bas *bas;
833         bus_space_tag_t bst;
834         bus_space_handle_t bsh;
835         uint32_t wrptr;
836
837         bas = &sc->sc_bas;
838         bst = bas->bst;
839         bsh = bas->bsh;
840
841         uart_lock(sc->sc_hwmtx);
842
843         /*
844          * Let the current output drain before enabling interrupts.  Not
845          * doing so tends to cause lost output when turning them on.
846          */
847         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
848             SBBC_CONS_OFF(cons_out_wrptr));
849         while (SBBC_SRAM_READ_4(sbbc_solcons +
850             SBBC_CONS_OFF(cons_out_rdptr)) != wrptr);
851                 cpu_spinwait();
852
853         /* Clear and acknowledge possibly outstanding interrupts. */
854         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
855         uart_barrier(bas);
856         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS,
857             SBBC_SRAM_READ_4(sbbc_scsolir));
858         uart_barrier(bas);
859         /* Enable PCI interrupts. */
860         SBBC_REGS_WRITE_4(SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
861         uart_barrier(bas);
862         /* Enable input from and output to SC as well as break interrupts. */
863         SBBC_SRAM_WRITE_4(sbbc_scsolie, SBBC_SRAM_READ_4(sbbc_scsolie) |
864             SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK |
865             SBBC_SRAM_CONS_SPACE_OUT);
866         uart_barrier(bas);
867
868         uart_unlock(sc->sc_hwmtx);
869         return (0);
870 }
871
872 static int
873 sbbc_uart_bus_detach(struct uart_softc *sc)
874 {
875
876         /* Give back the console input. */
877         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
878         return (0);
879 }
880
881 static int
882 sbbc_uart_bus_flush(struct uart_softc *sc, int what)
883 {
884         struct uart_bas *bas;
885         bus_space_tag_t bst;
886         bus_space_handle_t bsh;
887
888         bas = &sc->sc_bas;
889         bst = bas->bst;
890         bsh = bas->bsh;
891
892         if ((what & UART_FLUSH_TRANSMITTER) != 0)
893                 return (ENODEV);
894         if ((what & UART_FLUSH_RECEIVER) != 0) {
895                 SBBC_SRAM_WRITE_4(sbbc_solcons +
896                     SBBC_CONS_OFF(cons_in_rdptr),
897                     SBBC_SRAM_READ_4(sbbc_solcons +
898                     SBBC_CONS_OFF(cons_in_wrptr)));
899                 uart_barrier(bas);
900         }
901         return (0);
902 }
903
904 static int
905 sbbc_uart_bus_getsig(struct uart_softc *sc)
906 {
907         uint32_t dummy, new, old, sig;
908
909         do {
910                 old = sc->sc_hwsig;
911                 sig = old;
912                 dummy = 0;
913                 SIGCHG(dummy, sig, SER_CTS, SER_DCTS);
914                 SIGCHG(dummy, sig, SER_DCD, SER_DDCD);
915                 SIGCHG(dummy, sig, SER_DSR, SER_DDSR);
916                 new = sig & ~SER_MASK_DELTA;
917         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
918         return (sig);
919 }
920
921 static int
922 sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
923 {
924         int error;
925
926         error = 0;
927         uart_lock(sc->sc_hwmtx);
928         switch (request) {
929         case UART_IOCTL_BAUD:
930                 *(int*)data = 9600;     /* arbitrary */
931                 break;
932         default:
933                 error = EINVAL;
934                 break;
935         }
936         uart_unlock(sc->sc_hwmtx);
937         return (error);
938 }
939
940 static int
941 sbbc_uart_bus_ipend(struct uart_softc *sc)
942 {
943         struct uart_bas *bas;
944         bus_space_tag_t bst;
945         bus_space_handle_t bsh;
946         int ipend;
947         uint32_t reason, status;
948
949         bas = &sc->sc_bas;
950         bst = bas->bst;
951         bsh = bas->bsh;
952
953         uart_lock(sc->sc_hwmtx);
954         status = SBBC_REGS_READ_4(SBBC_PCI_INT_STATUS);
955         if (status == 0) {
956                 uart_unlock(sc->sc_hwmtx);
957                 return (0);
958         }
959
960         /*
961          * Unfortunately, we can't use compare and swap for non-cachable
962          * memory.
963          */
964         reason = SBBC_SRAM_READ_4(sbbc_scsolir);
965         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
966         uart_barrier(bas);
967         /* Acknowledge the interrupt. */
968         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, status);
969         uart_barrier(bas);
970
971         uart_unlock(sc->sc_hwmtx);
972
973         ipend = 0;
974         if ((reason & SBBC_SRAM_CONS_IN) != 0)
975                 ipend |= SER_INT_RXREADY;
976         if ((reason & SBBC_SRAM_CONS_BRK) != 0)
977                 ipend |= SER_INT_BREAK;
978         if ((reason & SBBC_SRAM_CONS_SPACE_OUT) != 0 &&
979             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_rdptr)) ==
980             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr)))
981                 ipend |= SER_INT_TXIDLE;
982         return (ipend);
983 }
984
985 static int
986 sbbc_uart_bus_param(struct uart_softc *sc __unused, int baudrate __unused,
987     int databits __unused, int stopbits __unused, int parity __unused)
988 {
989
990         return (0);
991 }
992
993 static int
994 sbbc_uart_bus_probe(struct uart_softc *sc)
995 {
996         struct uart_bas *bas;
997         bus_space_tag_t bst;
998         bus_space_handle_t bsh;
999
1000         if (sbbc_console != 0) {
1001                 bas = &sc->sc_bas;
1002                 bst = bas->bst;
1003                 bsh = bas->bsh;
1004                 sc->sc_rxfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
1005                     SBBC_CONS_OFF(cons_in_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
1006                     SBBC_CONS_OFF(cons_in_begin)) - 1;
1007                 sc->sc_txfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
1008                     SBBC_CONS_OFF(cons_out_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
1009                     SBBC_CONS_OFF(cons_out_begin)) - 1;
1010                 return (0);
1011         }
1012         return (ENXIO);
1013 }
1014
1015 static int
1016 sbbc_uart_bus_receive(struct uart_softc *sc)
1017 {
1018         struct uart_bas *bas;
1019         bus_space_tag_t bst;
1020         bus_space_handle_t bsh;
1021         int c;
1022         uint32_t end, rdptr, wrptr;
1023
1024         bas = &sc->sc_bas;
1025         bst = bas->bst;
1026         bsh = bas->bsh;
1027
1028         uart_lock(sc->sc_hwmtx);
1029
1030         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_end));
1031         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
1032         wrptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr));
1033         while (rdptr != wrptr) {
1034                 if (uart_rx_full(sc) != 0) {
1035                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
1036                         break;
1037                 }
1038                 c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
1039                 uart_rx_put(sc, c);
1040                 if (++rdptr == end)
1041                         rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
1042                             SBBC_CONS_OFF(cons_in_begin));
1043         }
1044         uart_barrier(bas);
1045         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
1046             rdptr);
1047         uart_barrier(bas);
1048         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
1049             SBBC_SRAM_CONS_SPACE_IN);
1050         uart_barrier(bas);
1051         sbbc_send_intr(bst, bsh);
1052
1053         uart_unlock(sc->sc_hwmtx);
1054         return (0);
1055 }
1056
1057 static int
1058 sbbc_uart_bus_setsig(struct uart_softc *sc, int sig)
1059 {
1060         struct uart_bas *bas;
1061         uint32_t new, old;
1062
1063         bas = &sc->sc_bas;
1064         do {
1065                 old = sc->sc_hwsig;
1066                 new = old;
1067                 if ((sig & SER_DDTR) != 0) {
1068                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
1069                 }
1070                 if ((sig & SER_DRTS) != 0) {
1071                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
1072                 }
1073         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
1074         return (0);
1075 }
1076
1077 static int
1078 sbbc_uart_bus_transmit(struct uart_softc *sc)
1079 {
1080         struct uart_bas *bas;
1081         bus_space_tag_t bst;
1082         bus_space_handle_t bsh;
1083         int i;
1084         uint32_t end, wrptr;
1085
1086         bas = &sc->sc_bas;
1087         bst = bas->bst;
1088         bsh = bas->bsh;
1089
1090         uart_lock(sc->sc_hwmtx);
1091
1092         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_end));
1093         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
1094             SBBC_CONS_OFF(cons_out_wrptr));
1095         for (i = 0; i < sc->sc_txdatasz; i++) {
1096                 SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, sc->sc_txbuf[i]);
1097                 if (++wrptr == end)
1098                         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
1099                             SBBC_CONS_OFF(cons_out_begin));
1100         }
1101         uart_barrier(bas);
1102         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
1103             wrptr);
1104         uart_barrier(bas);
1105         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
1106             SBBC_SRAM_CONS_OUT);
1107         uart_barrier(bas);
1108         sbbc_send_intr(bst, bsh);
1109         sc->sc_txbusy = 1;
1110
1111         uart_unlock(sc->sc_hwmtx);
1112         return (0);
1113 }