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