xref: /freebsd-12.1/sys/sparc64/pci/sbbc.c (revision 381388b9)
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 <[email protected]>
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
sbbc_pci_probe(device_t dev)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
sbbc_pci_attach(device_t dev)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 *
sbbc_bus_alloc_resource(device_t dev,device_t child __unused,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)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
sbbc_bus_activate_resource(device_t bus,device_t child,int type,int rid,struct resource * res)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
sbbc_bus_deactivate_resource(device_t bus,device_t child,int type,int rid,struct resource * res)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
sbbc_bus_adjust_resource(device_t bus __unused,device_t child __unused,int type __unused,struct resource * res __unused,rman_res_t start __unused,rman_res_t end __unused)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
sbbc_bus_release_resource(device_t dev,device_t child __unused,int type,int rid,struct resource * res)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 *
sbbc_bus_get_resource_list(device_t dev,device_t child __unused)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
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)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
sbbc_bus_teardown_intr(device_t dev,device_t child __unused,struct resource * res,void * cookie)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
sbbc_parse_toc(bus_space_tag_t bst,bus_space_handle_t bsh)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 *
sbbc_serengeti_set_console_input(char * new)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
sbbc_send_intr(bus_space_tag_t bst,bus_space_handle_t bsh)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
sbbc_tod_gettime(device_t dev,struct timespec * ts)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
sbbc_tod_settime(device_t dev,struct timespec * ts)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
sbbc_uart_sbbc_probe(device_t dev)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, 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
sbbc_uart_probe(struct uart_bas * bas)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
sbbc_uart_init(struct uart_bas * bas,int baudrate __unused,int databits __unused,int stopbits __unused,int parity __unused)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
sbbc_uart_term(struct uart_bas * bas __unused)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
sbbc_uart_putc(struct uart_bas * bas,int c)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
sbbc_uart_rxready(struct uart_bas * bas)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
sbbc_uart_getc(struct uart_bas * bas,struct mtx * hwmtx)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
sbbc_uart_bus_attach(struct uart_softc * sc)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
sbbc_uart_bus_detach(struct uart_softc * sc)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
sbbc_uart_bus_flush(struct uart_softc * sc,int what)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
sbbc_uart_bus_getsig(struct uart_softc * sc)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
sbbc_uart_bus_ioctl(struct uart_softc * sc,int request,intptr_t data)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
sbbc_uart_bus_ipend(struct uart_softc * sc)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
sbbc_uart_bus_param(struct uart_softc * sc __unused,int baudrate __unused,int databits __unused,int stopbits __unused,int parity __unused)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
sbbc_uart_bus_probe(struct uart_softc * sc)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
sbbc_uart_bus_receive(struct uart_softc * sc)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
sbbc_uart_bus_setsig(struct uart_softc * sc,int sig)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
sbbc_uart_bus_transmit(struct uart_softc * sc)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 }
1114