Home | History | Annotate | Line # | Download | only in mpc5200
      1 /*	$NetBSD: psc.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008, 2026 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Radoslaw Kujawa and Robert Swindells.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Driver for the MPC5200B Programmable Serial Controller (PSC) in UART mode.
     34  *
     35  * The interrupt-driven ttyback end is adapted from the MPC5200B PSC
     36  * driver by Robert Swindells, simplified onto the mpcobio attachment and
     37  * reduced to the subset the console needs.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: psc.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $");
     42 
     43 #include <sys/param.h>
     44 #include <sys/device.h>
     45 #include <sys/systm.h>
     46 #include <sys/proc.h>
     47 #include <sys/conf.h>
     48 #include <sys/tty.h>
     49 #include <sys/file.h>
     50 #include <sys/kauth.h>
     51 #include <sys/intr.h>
     52 #include <sys/kmem.h>
     53 #include <sys/bus.h>
     54 
     55 #include <dev/cons.h>
     56 #include <dev/ofw/openfirm.h>
     57 
     58 #include <machine/autoconf.h>
     59 
     60 #include <powerpc/mpc5200/obiovar.h>
     61 #include <powerpc/mpc5200/mpc5200reg.h>
     62 #include <powerpc/mpc5200/pscreg.h>
     63 #include <powerpc/mpc5200/pscvar.h>
     64 #include <powerpc/mpc5200/cdmvar.h>
     65 
     66 #ifndef PSC_CONSOLE_SPEED
     67 #define PSC_CONSOLE_SPEED	115200	/* console baud, programmed from IPB */
     68 #endif
     69 
     70 #define PSCUNIT(x)	minor(x)
     71 
     72 #define PSC_READ_1(sc, r)	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))
     73 #define PSC_READ_2(sc, r)	bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (r))
     74 #define PSC_WRITE_1(sc, r, v)	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
     75 #define PSC_WRITE_2(sc, r, v)	bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
     76 
     77 static int	psc_match(device_t, cfdata_t, void *);
     78 static void	psc_attach(device_t, device_t, void *);
     79 static u_int	psc_baud_divisor(uint32_t, int);
     80 static void	psc_set_baud(bus_space_tag_t, bus_space_handle_t, int);
     81 
     82 static int	pscintr(void *);
     83 static void	pscsoft(void *);
     84 static void	psc_rxsoft(struct psc_softc *, struct tty *);
     85 
     86 CFATTACH_DECL_NEW(psc, sizeof(struct psc_softc),
     87     psc_match, psc_attach, NULL, NULL);
     88 
     89 extern struct cfdriver psc_cd;
     90 
     91 dev_type_open(pscopen);
     92 dev_type_close(pscclose);
     93 dev_type_read(pscread);
     94 dev_type_write(pscwrite);
     95 dev_type_ioctl(pscioctl);
     96 dev_type_stop(pscstop);
     97 dev_type_tty(psctty);
     98 dev_type_poll(pscpoll);
     99 
    100 const struct cdevsw psc_cdevsw = {
    101 	.d_open = pscopen,
    102 	.d_close = pscclose,
    103 	.d_read = pscread,
    104 	.d_write = pscwrite,
    105 	.d_ioctl = pscioctl,
    106 	.d_stop = pscstop,
    107 	.d_tty = psctty,
    108 	.d_poll = pscpoll,
    109 	.d_mmap = nommap,
    110 	.d_kqfilter = ttykqfilter,
    111 	.d_discard = nodiscard,
    112 	.d_flag = D_TTY,
    113 };
    114 
    115 static int	pscparam(struct tty *, struct termios *);
    116 static void	pscstart(struct tty *);
    117 
    118 /*
    119  * Console state.
    120  */
    121 static struct {
    122 	bool			cs_mapped;
    123 	volatile uint8_t	*cs_base;
    124 } psc_console;
    125 
    126 #define PSC_CN_SR(cs)	(*(volatile uint16_t *)((cs)->cs_base + PSC_SR))
    127 #define PSC_CN_TB(cs)	(*((cs)->cs_base + PSC_TB))
    128 #define PSC_CN_RB(cs)	(*((cs)->cs_base + PSC_RB))
    129 
    130 static void	psccnprobe(struct consdev *);
    131 static void	psccninit(struct consdev *);
    132 static int	psccngetc(dev_t);
    133 static void	psccnputc(dev_t, int);
    134 static void	psccnpollc(dev_t, int);
    135 
    136 struct consdev psccons = {
    137 	.cn_probe = psccnprobe,
    138 	.cn_init = psccninit,
    139 	.cn_getc = psccngetc,
    140 	.cn_putc = psccnputc,
    141 	.cn_pollc = psccnpollc,
    142 	.cn_dev = NODEV,
    143 	.cn_pri = CN_REMOTE,
    144 };
    145 
    146 static bool
    147 psc_is_uart(int node)
    148 {
    149 	char compat[64];
    150 	int len;
    151 
    152 	len = OF_getprop(node, "compatible", compat, sizeof(compat));
    153 	if (len > 0 &&
    154 	    (strcmp(compat, "mpc5200-psc-uart") == 0 ||
    155 	     strcmp(compat, "mpc5200b-psc-uart") == 0))
    156 		return true;
    157 	return false;
    158 }
    159 
    160 static int
    161 psc_match(device_t parent, cfdata_t cf, void *aux)
    162 {
    163 	struct obio_attach_args *oba = aux;
    164 
    165 	if (strcmp(oba->obio_name, "serial") == 0)
    166 		return 1;
    167 	if (psc_is_uart(oba->obio_node))
    168 		return 1;
    169 	return 0;
    170 }
    171 
    172 static void
    173 psc_attach(device_t parent, device_t self, void *aux)
    174 {
    175 	struct psc_softc *sc = device_private(self);
    176 	struct obio_attach_args *oba = aux;
    177 	struct tty *tp;
    178 	bus_size_t size;
    179 	int ist;
    180 
    181 	sc->sc_dev = self;
    182 	sc->sc_iot = oba->obio_bst;
    183 	sc->sc_node = oba->obio_node;
    184 
    185 	size = oba->obio_size != 0 ? oba->obio_size : MPC5200_PSC_SIZE;
    186 	if (bus_space_map(sc->sc_iot, oba->obio_addr, size, 0,
    187 	    &sc->sc_ioh) != 0) {
    188 		aprint_error(": can't map registers\n");
    189 		return;
    190 	}
    191 
    192 	sc->sc_console = (sc->sc_node == console_node);
    193 
    194 	if (sc->sc_console) {
    195 		uint32_t ipb = mpc5200_cdm_get_ipb_freq();
    196 		u_int div = psc_baud_divisor(ipb, PSC_CONSOLE_SPEED);
    197 
    198 		/*
    199 		 * Announce the computed divisor through the firmware-inherited
    200 		 * console *before* reprogramming
    201 		 */
    202 		aprint_normal(": console, IPB %u.%u MHz, %d baud (divisor %u)",
    203 		    ipb / 1000000, (ipb / 100000) % 10, PSC_CONSOLE_SPEED, div);
    204 		psc_set_baud(sc->sc_iot, sc->sc_ioh, PSC_CONSOLE_SPEED);
    205 	}
    206 	aprint_normal("\n");
    207 
    208 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
    209 
    210 	/* Mask all PSC events and stop the line while reprogramming. */
    211 	sc->sc_imr = 0;
    212 	PSC_WRITE_2(sc, PSC_IMR, sc->sc_imr);
    213 	PSC_WRITE_1(sc, PSC_CR, CMD_TX_DISABLE | CMD_RX_DISABLE);
    214 
    215 	/*
    216 	 * Clear MR1[FFULL] so the RxRDY status
    217 	 */
    218 	{
    219 		uint8_t mr1, mr2;
    220 
    221 		PSC_WRITE_1(sc, PSC_CR, CMD_RESET_MR);
    222 		mr1 = PSC_READ_1(sc, PSC_MR1);
    223 		mr2 = PSC_READ_1(sc, PSC_MR2);
    224 		mr1 &= ~MR1_FFULL;
    225 		PSC_WRITE_1(sc, PSC_CR, CMD_RESET_MR);
    226 		PSC_WRITE_1(sc, PSC_MR1, mr1);
    227 		PSC_WRITE_1(sc, PSC_MR2, mr2);
    228 	}
    229 
    230 	/* Clear errors and bring the receiver and transmitter up. */
    231 	PSC_WRITE_1(sc, PSC_CR, CMD_RESET_ERR);
    232 	PSC_WRITE_1(sc, PSC_CR, CMD_TX_ENABLE | CMD_RX_ENABLE);
    233 
    234 	sc->sc_si = softint_establish(SOFTINT_SERIAL, pscsoft, sc);
    235 	if (sc->sc_si == NULL) {
    236 		aprint_error_dev(self, "can't establish soft interrupt\n");
    237 		return;
    238 	}
    239 
    240 	if (obio_decode_interrupt(oba->obio_node, 0, &sc->sc_irq, &ist)) {
    241 		sc->sc_ih = intr_establish(sc->sc_irq, ist, IPL_HIGH,
    242 		    pscintr, sc);
    243 		if (sc->sc_ih == NULL)
    244 			aprint_error_dev(self, "can't establish interrupt\n");
    245 	}
    246 
    247 	tp = tty_alloc();
    248 	tp->t_oproc = pscstart;
    249 	tp->t_param = pscparam;
    250 	sc->sc_tty = tp;
    251 	sc->sc_rbput = sc->sc_rbget = 0;
    252 	tty_attach(tp);
    253 
    254 	/*
    255 	 * Redirect /dev/console opens to this tty: cnopen() follows
    256 	 * cn_tab->cn_dev, which the polled console left as NODEV.
    257 	 */
    258 	if (sc->sc_console && cn_tab == &psccons) {
    259 		int maj = cdevsw_lookup_major(&psc_cdevsw);
    260 
    261 		tp->t_dev = cn_tab->cn_dev =
    262 		    makedev(maj, device_unit(self));
    263 	}
    264 }
    265 
    266 /*
    267  * Compute the 16-bit UART baud-rate divisor for a target rate from the IPB
    268  * clock.
    269  */
    270 static u_int
    271 psc_baud_divisor(uint32_t ipb, int baud)
    272 {
    273 	u_int div;
    274 
    275 	if (baud <= 0)
    276 		return 1;
    277 
    278 	div = (ipb + (PSC_BAUD_PRESCALE / 2) * baud) /
    279 	    (PSC_BAUD_PRESCALE * baud);
    280 	if (div < 1)
    281 		div = 1;
    282 	if (div > 0xffff)
    283 		div = 0xffff;
    284 	return div;
    285 }
    286 
    287 /*
    288  * Program the UART baud rate
    289  */
    290 static void
    291 psc_set_baud(bus_space_tag_t iot, bus_space_handle_t ioh, int baud)
    292 {
    293 	u_int div = psc_baud_divisor(mpc5200_cdm_get_ipb_freq(), baud);
    294 	int timo;
    295 
    296 	/* Let any queued console output drain before stopping the line. */
    297 	for (timo = 100000; timo > 0; timo--) {
    298 		if (bus_space_read_2(iot, ioh, PSC_SR) & SR_TXEMP)
    299 			break;
    300 	}
    301 
    302 	bus_space_write_1(iot, ioh, PSC_CR, CMD_TX_DISABLE | CMD_RX_DISABLE);
    303 	bus_space_write_2(iot, ioh, PSC_CSR, CSR_UART_CT);
    304 	bus_space_write_1(iot, ioh, PSC_CTUR, (div >> 8) & 0xff);
    305 	bus_space_write_1(iot, ioh, PSC_CTLR, div & 0xff);
    306 	bus_space_write_1(iot, ioh, PSC_CR, CMD_TX_ENABLE | CMD_RX_ENABLE);
    307 }
    308 
    309 /*
    310  * Hard interrupt
    311  */
    312 static int
    313 pscintr(void *arg)
    314 {
    315 	struct psc_softc *sc = arg;
    316 	uint16_t isr, sr;
    317 	int handled = 0;
    318 
    319 	mutex_spin_enter(&sc->sc_lock);
    320 	isr = PSC_READ_2(sc, PSC_ISR);
    321 
    322 	if (isr & (INT_RXRDY | INT_ERROR | INT_ORERR)) {
    323 		sr = PSC_READ_2(sc, PSC_SR);
    324 		while (sr & SR_RXRDY) {
    325 			uint8_t c = PSC_READ_1(sc, PSC_RB);
    326 			u_int next = (sc->sc_rbput + 1) & PSC_RING_MASK;
    327 
    328 			if (next != sc->sc_rbget) {
    329 				sc->sc_rbuf[sc->sc_rbput] = c;
    330 				sc->sc_rbput = next;
    331 			}
    332 			/* else ring full: drop, mirroring a silo overflow */
    333 			sr = PSC_READ_2(sc, PSC_SR);
    334 		}
    335 		if (sr & SR_ORERR)
    336 			PSC_WRITE_1(sc, PSC_CR, CMD_RESET_ERR);
    337 		sc->sc_rx_ready = true;
    338 		handled = 1;
    339 	}
    340 
    341 	sr = PSC_READ_2(sc, PSC_SR);
    342 	if (sr & SR_TXRDY) {
    343 		while (sc->sc_tbc > 0 && (PSC_READ_2(sc, PSC_SR) & SR_TXRDY)) {
    344 			PSC_WRITE_1(sc, PSC_TB, *sc->sc_tba);
    345 			sc->sc_tba++;
    346 			sc->sc_tbc--;
    347 		}
    348 		if (sc->sc_tbc == 0) {
    349 			if (sc->sc_imr & INT_TXRDY) {
    350 				sc->sc_imr &= ~INT_TXRDY;
    351 				PSC_WRITE_2(sc, PSC_IMR, sc->sc_imr);
    352 			}
    353 			if (sc->sc_tx_busy) {
    354 				sc->sc_tx_busy = false;
    355 				sc->sc_tx_done = true;
    356 				handled = 1;
    357 			}
    358 		}
    359 	}
    360 
    361 	mutex_spin_exit(&sc->sc_lock);
    362 
    363 	if (sc->sc_rx_ready || sc->sc_tx_done)
    364 		softint_schedule(sc->sc_si);
    365 
    366 	return handled;
    367 }
    368 
    369 /*
    370  * Soft interrupt (IPL_SOFTSERIAL / spltty)
    371  */
    372 static void
    373 psc_rxsoft(struct psc_softc *sc, struct tty *tp)
    374 {
    375 	int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
    376 
    377 	/*
    378 	 * Single-producer (pscintr at IPL_HIGH) / single-consumer ring, so
    379 	 * sc_rbput can be read without the lock; we only advance sc_rbget.
    380 	 */
    381 	while (sc->sc_rbget != sc->sc_rbput) {
    382 		uint8_t c = sc->sc_rbuf[sc->sc_rbget];
    383 
    384 		if ((*rint)(c, tp) == -1)
    385 			break;			/* tty buffer full; retry later */
    386 		sc->sc_rbget = (sc->sc_rbget + 1) & PSC_RING_MASK;
    387 	}
    388 }
    389 
    390 static void
    391 pscsoft(void *arg)
    392 {
    393 	struct psc_softc *sc = arg;
    394 	struct tty *tp = sc->sc_tty;
    395 
    396 	if (tp == NULL)
    397 		return;
    398 
    399 	if (sc->sc_rx_ready) {
    400 		sc->sc_rx_ready = false;
    401 		psc_rxsoft(sc, tp);
    402 	}
    403 
    404 	if (sc->sc_tx_done) {
    405 		sc->sc_tx_done = false;
    406 		CLR(tp->t_state, TS_BUSY);
    407 		if (ISSET(tp->t_state, TS_FLUSH))
    408 			CLR(tp->t_state, TS_FLUSH);
    409 		else
    410 			ndflush(&tp->t_outq,
    411 			    (int)(sc->sc_tba - tp->t_outq.c_cf));
    412 		(*tp->t_linesw->l_start)(tp);
    413 	}
    414 }
    415 
    416 /* tty oproc: queue the next contiguous output chunk and arm tx interrupts. */
    417 static void
    418 pscstart(struct tty *tp)
    419 {
    420 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(tp->t_dev));
    421 	int s;
    422 
    423 	if (sc == NULL)
    424 		return;
    425 
    426 	s = spltty();
    427 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
    428 		goto out;
    429 	if (!ttypull(tp))
    430 		goto out;
    431 
    432 	SET(tp->t_state, TS_BUSY);
    433 
    434 	mutex_spin_enter(&sc->sc_lock);
    435 	sc->sc_tba = tp->t_outq.c_cf;
    436 	sc->sc_tbc = ndqb(&tp->t_outq, 0);
    437 	sc->sc_tx_busy = true;
    438 	if (!(sc->sc_imr & INT_TXRDY)) {
    439 		sc->sc_imr |= INT_TXRDY;
    440 		PSC_WRITE_2(sc, PSC_IMR, sc->sc_imr);
    441 	}
    442 	mutex_spin_exit(&sc->sc_lock);
    443 out:
    444 	splx(s);
    445 }
    446 
    447 static int
    448 pscparam(struct tty *tp, struct termios *t)
    449 {
    450 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(tp->t_dev));
    451 
    452 	if (sc == NULL)
    453 		return ENXIO;
    454 
    455 	/*
    456 	 * XXX: accept the requested termios but do not reprogram the
    457 	 * bit clock here, so a stray speed change cannot make the console
    458 	 * unreadable.
    459 	 */
    460 	tp->t_ispeed = t->c_ispeed;
    461 	tp->t_ospeed = t->c_ospeed;
    462 	tp->t_cflag = t->c_cflag;
    463 
    464 	return 0;
    465 }
    466 
    467 int
    468 pscopen(dev_t dev, int flag, int mode, struct lwp *l)
    469 {
    470 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    471 	struct tty *tp;
    472 	int error, s;
    473 
    474 	if (sc == NULL)
    475 		return ENXIO;
    476 	tp = sc->sc_tty;
    477 
    478 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    479 		return EBUSY;
    480 
    481 	s = spltty();
    482 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    483 		struct termios t;
    484 
    485 		tp->t_dev = dev;
    486 
    487 		/* Enable receive (and break) interrupts. */
    488 		mutex_spin_enter(&sc->sc_lock);
    489 		sc->sc_imr |= INT_RXRDY;
    490 		PSC_WRITE_2(sc, PSC_IMR, sc->sc_imr);
    491 		mutex_spin_exit(&sc->sc_lock);
    492 
    493 		t.c_ospeed = t.c_ispeed = PSC_CONSOLE_SPEED;
    494 		t.c_cflag = (CREAD | CS8 | HUPCL | CLOCAL);
    495 		tp->t_ospeed = 0;
    496 		(void)pscparam(tp, &t);
    497 		tp->t_iflag = TTYDEF_IFLAG;
    498 		tp->t_oflag = TTYDEF_OFLAG;
    499 		tp->t_lflag = TTYDEF_LFLAG;
    500 		ttychars(tp);
    501 		ttsetwater(tp);
    502 	}
    503 	splx(s);
    504 
    505 	error = ttyopen(tp, 0, ISSET(flag, O_NONBLOCK));
    506 	if (error)
    507 		return error;
    508 
    509 	return (*tp->t_linesw->l_open)(dev, tp);
    510 }
    511 
    512 int
    513 pscclose(dev_t dev, int flag, int mode, struct lwp *l)
    514 {
    515 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    516 	struct tty *tp = sc->sc_tty;
    517 
    518 	if (!ISSET(tp->t_state, TS_ISOPEN))
    519 		return 0;
    520 
    521 	(*tp->t_linesw->l_close)(tp, flag);
    522 	ttyclose(tp);
    523 
    524 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    525 		/* Last close: leave RX interrupts on for the console. */
    526 		if (!sc->sc_console) {
    527 			mutex_spin_enter(&sc->sc_lock);
    528 			sc->sc_imr &= ~INT_RXRDY;
    529 			PSC_WRITE_2(sc, PSC_IMR, sc->sc_imr);
    530 			mutex_spin_exit(&sc->sc_lock);
    531 		}
    532 	}
    533 	return 0;
    534 }
    535 
    536 int
    537 pscread(dev_t dev, struct uio *uio, int flag)
    538 {
    539 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    540 	struct tty *tp = sc->sc_tty;
    541 
    542 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    543 }
    544 
    545 int
    546 pscwrite(dev_t dev, struct uio *uio, int flag)
    547 {
    548 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    549 	struct tty *tp = sc->sc_tty;
    550 
    551 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    552 }
    553 
    554 int
    555 pscpoll(dev_t dev, int events, struct lwp *l)
    556 {
    557 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    558 	struct tty *tp = sc->sc_tty;
    559 
    560 	return (*tp->t_linesw->l_poll)(tp, events, l);
    561 }
    562 
    563 struct tty *
    564 psctty(dev_t dev)
    565 {
    566 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    567 
    568 	return sc->sc_tty;
    569 }
    570 
    571 int
    572 pscioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    573 {
    574 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(dev));
    575 	struct tty *tp = sc->sc_tty;
    576 	int error;
    577 
    578 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    579 	if (error != EPASSTHROUGH)
    580 		return error;
    581 
    582 	return ttioctl(tp, cmd, data, flag, l);
    583 }
    584 
    585 void
    586 pscstop(struct tty *tp, int flag)
    587 {
    588 	struct psc_softc *sc = device_lookup_private(&psc_cd, PSCUNIT(tp->t_dev));
    589 
    590 	if (sc == NULL)
    591 		return;
    592 
    593 	mutex_spin_enter(&sc->sc_lock);
    594 	if (ISSET(tp->t_state, TS_BUSY)) {
    595 		sc->sc_tbc = 0;
    596 		if (!ISSET(tp->t_state, TS_TTSTOP))
    597 			SET(tp->t_state, TS_FLUSH);
    598 	}
    599 	mutex_spin_exit(&sc->sc_lock);
    600 }
    601 
    602 /*
    603  * Console interface.
    604  */
    605 
    606 static void
    607 psccnprobe(struct consdev *cp)
    608 {
    609 	/* Selection is performed by ofwoea_cnprobe(); nothing to do. */
    610 }
    611 
    612 static void
    613 psccninit(struct consdev *cp)
    614 {
    615 	/*
    616 	 * The board's console is PSC1, at a fixed MBAR offset.
    617 	 * XXX: This should be configurable.
    618 	 */
    619 	psc_console.cs_base =
    620 	    (volatile uint8_t *)(MPC5200_MBAR_DEFAULT + MPC5200_REG_PSC1);
    621 	psc_console.cs_mapped = true;
    622 }
    623 
    624 static int
    625 psccngetc(dev_t dev)
    626 {
    627 
    628 	if (!psc_console.cs_mapped)
    629 		return -1;
    630 	if ((PSC_CN_SR(&psc_console) & SR_RXRDY) == 0)
    631 		return -1;
    632 	return PSC_CN_RB(&psc_console);
    633 }
    634 
    635 static void
    636 psccnputc(dev_t dev, int c)
    637 {
    638 
    639 	if (!psc_console.cs_mapped)
    640 		return;
    641 	if (c == '\n')
    642 		psccnputc(dev, '\r');
    643 	while ((PSC_CN_SR(&psc_console) & SR_TXRDY) == 0)
    644 		continue;
    645 	PSC_CN_TB(&psc_console) = c;
    646 }
    647 
    648 static void
    649 psccnpollc(dev_t dev, int on)
    650 {
    651 	/* The low-level console path is always polled. */
    652 }
    653