From 4c5a9380ec0fb7c92a4bfd25db27bceb9c6eda51 Mon Sep 17 00:00:00 2001 From: skrll Date: Wed, 25 Jul 2012 07:26:17 +0000 Subject: [PATCH] Add support for the PL011 to plcom. Pull across a bunch of fixes from com(4) while I'm here and do some other tidyup. Tested on a RaspberryPi. PL010 not tested. --- sys/arch/evbarm/dev/plcom.c | 761 +++++++++++++----- sys/arch/evbarm/dev/plcomreg.h | 54 +- sys/arch/evbarm/dev/plcomvar.h | 54 +- sys/arch/evbarm/ifpga/ifpgareg.h | 3 +- sys/arch/evbarm/ifpga/plcom_ifpga.c | 19 +- .../evbarm/integrator/integrator_machdep.c | 60 +- 6 files changed, 704 insertions(+), 247 deletions(-) diff --git a/sys/arch/evbarm/dev/plcom.c b/sys/arch/evbarm/dev/plcom.c index de0ad14ddb5c..8b5a348b41b0 100644 --- a/sys/arch/evbarm/dev/plcom.c +++ b/sys/arch/evbarm/dev/plcom.c @@ -1,4 +1,4 @@ -/* $NetBSD: plcom.c,v 1.39 2012/07/05 10:56:52 skrll Exp $ */ +/* $NetBSD: plcom.c,v 1.40 2012/07/25 07:26:17 skrll Exp $ */ /*- * Copyright (c) 2001 ARM Ltd @@ -28,11 +28,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * Copyright (c) 1998, 1999, 2012 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Charles M. Hannum. + * by Charles M. Hannum and Nick Hudson. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -88,13 +88,13 @@ */ /* - * COM driver for the Prime Cell PL010 UART, which is similar to the 16C550, - * but has a completely different programmer's model. + * COM driver for the Prime Cell PL010 and PL011 UARTs. Both are is similar to + * the 16C550, but have a completely different programmer's model. * Derived from the NS16550AF com driver. */ #include -__KERNEL_RCSID(0, "$NetBSD: plcom.c,v 1.39 2012/07/05 10:56:52 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: plcom.c,v 1.40 2012/07/25 07:26:17 skrll Exp $"); #include "opt_plcom.h" #include "opt_ddb.h" @@ -103,9 +103,6 @@ __KERNEL_RCSID(0, "$NetBSD: plcom.c,v 1.39 2012/07/05 10:56:52 skrll Exp $"); #include "opt_multiprocessor.h" #include "rnd.h" -#ifdef RND_COM -#include -#endif /* * Override cnmagic(9) macro before including . @@ -138,6 +135,9 @@ __KERNEL_RCSID(0, "$NetBSD: plcom.c,v 1.39 2012/07/05 10:56:52 skrll Exp $"); #include #include #include +#ifdef RND_COM +#include +#endif #include #include @@ -148,7 +148,8 @@ static void plcom_enable_debugport (struct plcom_softc *); void plcom_config (struct plcom_softc *); void plcom_shutdown (struct plcom_softc *); -int plcomspeed (long, long); +int pl010comspeed (long, long); +int pl011comspeed (long, long); static u_char cflag2lcr (tcflag_t); int plcomparam (struct tty *, struct termios *); void plcomstart (struct tty *); @@ -162,11 +163,10 @@ void tiocm_to_plcom (struct plcom_softc *, u_long, int); int plcom_to_tiocm (struct plcom_softc *); void plcom_iflush (struct plcom_softc *); -int plcom_common_getc (dev_t, bus_space_tag_t, bus_space_handle_t); -void plcom_common_putc (dev_t, bus_space_tag_t, bus_space_handle_t, int); +int plcom_common_getc (dev_t, struct plcom_instance *); +void plcom_common_putc (dev_t, struct plcom_instance *, int); -int plcominit (bus_space_tag_t, bus_addr_t, int, int, tcflag_t, - bus_space_handle_t *); +int plcominit (struct plcom_instance *, int, int, tcflag_t); dev_type_open(plcomopen); dev_type_close(plcomclose); @@ -189,6 +189,8 @@ integrate void plcom_stsoft (struct plcom_softc *, struct tty *); integrate void plcom_schedrx (struct plcom_softc *); void plcomdiag (void *); +bool plcom_intstatus(struct plcom_instance *, u_int *); + extern struct cfdriver plcom_cd; const struct cdevsw plcom_cdevsw = { @@ -207,9 +209,9 @@ u_int plcom_rbuf_hiwat = (PLCOM_RING_SIZE * 1) / 4; u_int plcom_rbuf_lowat = (PLCOM_RING_SIZE * 3) / 4; static int plcomconsunit = -1; -static bus_space_tag_t plcomconstag; -static bus_space_handle_t plcomconsioh; -static int plcomconsattached; +static struct plcom_instance plcomcons_info; + +static int plcomconsattached; static int plcomconsrate; static tcflag_t plcomconscflag; static struct cnm_state plcom_cnm_state; @@ -226,16 +228,14 @@ static int ppscap = #ifdef KGDB #include -static int plcom_kgdb_unit; -static bus_space_tag_t plcom_kgdb_iot; -static bus_space_handle_t plcom_kgdb_ioh; +static struct plcom_instance plcomkgdb_info; static int plcom_kgdb_attached; int plcom_kgdb_getc (void *); void plcom_kgdb_putc (void *, int); #endif /* KGDB */ -#define PLCOMUNIT_MASK 0x7ffff +#define PLCOMUNIT_MASK 0x7ffff #define PLCOMDIALOUT_MASK 0x80000 #define PLCOMUNIT(x) (minor(x) & PLCOMUNIT_MASK) @@ -246,10 +246,58 @@ void plcom_kgdb_putc (void *, int); #define BR BUS_SPACE_BARRIER_READ #define BW BUS_SPACE_BARRIER_WRITE -#define PLCOM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, PLCOM_UART_SIZE, (f)) +#define PLCOM_BARRIER(pi, f) \ + bus_space_barrier((pi)->pi_iot, (pi)->pi_ioh, 0, (pi)->pi_size, (f)) + +static uint8_t +pread1(struct plcom_instance *pi, bus_size_t reg) +{ + if (!ISSET(pi->pi_flags, PLC_FLAG_32BIT_ACCESS)) + return bus_space_read_1(pi->pi_iot, pi->pi_ioh, reg); + + return bus_space_read_4(pi->pi_iot, pi->pi_ioh, reg & -4) >> + (8 * (reg & 3)); +} +int nhcr; +static void +pwrite1(struct plcom_instance *pi, bus_size_t o, uint8_t val) +{ + if (!ISSET(pi->pi_flags, PLC_FLAG_32BIT_ACCESS)) { + bus_space_write_1(pi->pi_iot, pi->pi_ioh, o, val); + } else { + const size_t shift = 8 * (o & 3); + o &= -4; + uint32_t tmp = bus_space_read_4(pi->pi_iot, pi->pi_ioh, o); + tmp = (val << shift) | (tmp & ~(0xff << shift)); + bus_space_write_4(pi->pi_iot, pi->pi_ioh, o, tmp); + } +} + +static void +pwritem1(struct plcom_instance *pi, bus_size_t o, const uint8_t *datap, + bus_size_t count) +{ + if (!ISSET(pi->pi_flags, PLC_FLAG_32BIT_ACCESS)) { + bus_space_write_multi_1(pi->pi_iot, pi->pi_ioh, o, datap, count); + } else { + KASSERT((o & 3) == 0); + while (count--) { + bus_space_write_4(pi->pi_iot, pi->pi_ioh, o, *datap++); + }; + } +} + +#define PREAD1(pi, reg) pread1(pi, reg) +#define PREAD4(pi, reg) \ + (bus_space_read_4((pi)->pi_iot, (pi)->pi_ioh, (reg))) + +#define PWRITE1(pi, reg, val) pwrite1(pi, reg, val) +#define PWRITEM1(pi, reg, d, c) pwritem1(pi, reg, d, c) +#define PWRITE4(pi, reg, val) \ + (bus_space_write_4((pi)->pi_iot, (pi)->pi_ioh, (reg), (val))) int -plcomspeed(long speed, long frequency) +pl010comspeed(long speed, long frequency) { #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ @@ -274,6 +322,20 @@ plcomspeed(long speed, long frequency) #undef divrnd } +int +pl011comspeed(long speed, long frequency) +{ + int denom = 16 * speed; + int div = frequency / denom; + int rem = frequency % denom; + + int ibrd = div << 6; + int fbrd = (((8 * rem) / speed) + 1) / 2; + + /* Tolerance? */ + return ibrd | fbrd; +} + #ifdef PLCOM_DEBUG int plcom_debug = 0; @@ -301,7 +363,7 @@ plcomstatus(struct plcom_softc *sc, const char *str) } #endif -/* XXX this function is not used? */ +#if 0 int plcomprobe1(bus_space_tag_t iot, bus_space_handle_t ioh) { @@ -327,6 +389,7 @@ plcomprobe1(bus_space_tag_t iot, bus_space_handle_t ioh) return 1; } +#endif /* * No locking in this routine; it is only called during attach, @@ -335,55 +398,106 @@ plcomprobe1(bus_space_tag_t iot, bus_space_handle_t ioh) static void plcom_enable_debugport(struct plcom_softc *sc) { + struct plcom_instance *pi = &sc->sc_pi; + + sc->sc_cr = PL01X_CR_UARTEN; + SET(sc->sc_mcr, PL01X_MCR_DTR | PL01X_MCR_RTS); /* Turn on line break interrupt, set carrier. */ - sc->sc_cr = PL010_CR_RIE | PL010_CR_RTIE | PL01X_CR_UARTEN; - bus_space_write_1(sc->sc_iot, sc->sc_ioh, plcom_cr, sc->sc_cr); - SET(sc->sc_mcr, PL01X_MCR_DTR | PL01X_MCR_RTS); - /* XXX device_unit() abuse */ - sc->sc_set_mcr(sc->sc_set_mcr_arg, device_unit(sc->sc_dev), - sc->sc_mcr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + SET(sc->sc_cr, PL010_CR_RIE | PL010_CR_RTIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + if (sc->sc_set_mcr) { + /* XXX device_unit() abuse */ + sc->sc_set_mcr(sc->sc_set_mcr_arg, + device_unit(sc->sc_dev), sc->sc_mcr); + } + break; + case PLCOM_TYPE_PL011: + sc->sc_imsc = PL011_INT_RX | PL011_INT_RT; + SET(sc->sc_cr, PL011_CR_RXE | PL011_CR_TXE); + SET(sc->sc_cr, PL011_MCR(sc->sc_mcr)); + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } + } void plcom_attach_subr(struct plcom_softc *sc) { - int unit = sc->sc_iounit; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; struct tty *tp; + aprint_naive("\n"); + callout_init(&sc->sc_diag_callout, 0); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + case PLCOM_TYPE_PL011: + break; + default: + aprint_error_dev(sc->sc_dev, + "Unknown plcom type: %d\n", pi->pi_type); + return; + } + /* Disable interrupts before configuring the device. */ sc->sc_cr = 0; + sc->sc_imsc = 0; - if (plcomconstag && unit == plcomconsunit) { + if (bus_space_is_equal(pi->pi_iot, plcomcons_info.pi_iot) && + pi->pi_iobase == plcomcons_info.pi_iobase) { plcomconsattached = 1; - plcomconstag = iot; - plcomconsioh = ioh; - /* Make sure the console is always "hardwired". */ delay(1000); /* wait for output to finish */ SET(sc->sc_hwflags, PLCOM_HW_CONSOLE); SET(sc->sc_swflags, TIOCFLAG_SOFTCAR); - /* Must re-enable the console immediately, or we will - hang when trying to print. */ + /* + * Must re-enable the console immediately, or we will + * hang when trying to print. + */ sc->sc_cr = PL01X_CR_UARTEN; + if (pi->pi_type == PLCOM_TYPE_PL011) + SET(sc->sc_cr, PL011_CR_RXE | PL011_CR_TXE); } - bus_space_write_1(iot, ioh, plcom_cr, sc->sc_cr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + + case PLCOM_TYPE_PL011: + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } - /* The PL010 has a 16-byte fifo, but the tx interrupt triggers when - there is space for 8 more bytes. */ - sc->sc_fifolen = 8; - printf("\n"); + if (sc->sc_fifolen == 0) { + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + /* + * The PL010 has a 16-byte fifo, but the tx interrupt + * triggers when there is space for 8 more bytes. + */ + sc->sc_fifolen = 8; + break; + case PLCOM_TYPE_PL011: + /* Some revisions have a 32 byte TX FIFO */ + sc->sc_fifolen = 16; + break; + } + } + aprint_normal("\n"); if (ISSET(sc->sc_hwflags, PLCOM_HW_TXFIFO_DISABLE)) { sc->sc_fifolen = 1; - printf("%s: txfifo disabled\n", device_xname(sc->sc_dev)); + aprint_normal_dev(sc->sc_dev, "txfifo disabled\n"); } if (sc->sc_fifolen > 1) @@ -399,8 +513,8 @@ plcom_attach_subr(struct plcom_softc *sc) sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; sc->sc_rbavail = plcom_rbuf_size; if (sc->sc_rbuf == NULL) { - printf("%s: unable to allocate ring buffer\n", - device_xname(sc->sc_dev)); + aprint_error_dev(sc->sc_dev, + "unable to allocate ring buffer\n"); return; } sc->sc_ebuf = sc->sc_rbuf + (plcom_rbuf_size << 1); @@ -413,9 +527,9 @@ plcom_attach_subr(struct plcom_softc *sc) /* locate the major number */ maj = cdevsw_lookup_major(&plcom_cdevsw); - cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev)); + tp->t_dev = cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev)); - printf("%s: console\n", device_xname(sc->sc_dev)); + aprint_normal_dev(sc->sc_dev, "console\n"); } #ifdef KGDB @@ -423,23 +537,28 @@ plcom_attach_subr(struct plcom_softc *sc) * Allow kgdb to "take over" this port. If this is * the kgdb device, it has exclusive use. */ - if (iot == plcom_kgdb_iot && unit == plcom_kgdb_unit) { - plcom_kgdb_attached = 1; + if (bus_space_is_equal(iot, plcomkgdb_info.pi_iot) && + pi->pi_iobase == plcomkgdb_info.pi_iobase) { + if (!ISSET(sc->sc_hwflags, PLCOM_HW_CONSOLE)) { + plcom_kgdb_attached = 1; - SET(sc->sc_hwflags, PLCOM_HW_KGDB); - printf("%s: kgdb\n", device_xname(sc->sc_dev)); + SET(sc->sc_hwflags, PLCOM_HW_KGDB); + } + aprint_normal_dev(sc->sc_dev, "kgdb\n"); } #endif sc->sc_si = softint_establish(SOFTINT_SERIAL, plcomsoft, sc); #ifdef RND_COM - rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev)), - RND_TYPE_TTY, 0); + rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), + RND_TYPE_TTY, 0); #endif - /* if there are no enable/disable functions, assume the device - is always enabled */ + /* + * if there are no enable/disable functions, assume the device + * is always enabled + */ if (!sc->enable) sc->enabled = 1; @@ -451,12 +570,21 @@ plcom_attach_subr(struct plcom_softc *sc) void plcom_config(struct plcom_softc *sc) { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; /* Disable interrupts before configuring the device. */ sc->sc_cr = 0; - bus_space_write_1(iot, ioh, plcom_cr, sc->sc_cr); + sc->sc_imsc = 0; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + + case PLCOM_TYPE_PL011: + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } if (ISSET(sc->sc_hwflags, PLCOM_HW_CONSOLE|PLCOM_HW_KGDB)) plcom_enable_debugport(sc); @@ -486,6 +614,15 @@ plcom_detach(device_t self, int flags) mn |= PLCOMDIALOUT_MASK; vdevgone(maj, mn, mn, VCHR); + if (sc->sc_rbuf == NULL) { + /* + * Ring buffer allocation failed in the plcom_attach_subr, + * only the tty is allocated, and nothing else. + */ + tty_free(sc->sc_tty); + return 0; + } + /* Free the receive buffer. */ free(sc->sc_rbuf, M_DEVBUF); @@ -500,6 +637,7 @@ plcom_detach(device_t self, int flags) /* Unhook the entropy source. */ rnd_detach_source(&sc->rnd_source); #endif + callout_destroy(&sc->sc_diag_callout); /* Destroy the lock. */ mutex_destroy(&sc->sc_lock); @@ -524,6 +662,7 @@ plcom_activate(device_t self, enum devact act) void plcom_shutdown(struct plcom_softc *sc) { + struct plcom_instance *pi = &sc->sc_pi; struct tty *tp = sc->sc_tty; mutex_spin_enter(&sc->sc_lock); @@ -553,13 +692,36 @@ plcom_shutdown(struct plcom_softc *sc) mutex_spin_enter(&sc->sc_lock); } + sc->sc_cr = 0; + sc->sc_imsc = 0; /* Turn off interrupts. */ - if (ISSET(sc->sc_hwflags, PLCOM_HW_CONSOLE)) + if (ISSET(sc->sc_hwflags, PLCOM_HW_CONSOLE)) { /* interrupt on break */ - sc->sc_cr = PL010_CR_RIE | PL010_CR_RTIE | PL01X_CR_UARTEN; - else - sc->sc_cr = 0; - bus_space_write_1(sc->sc_iot, sc->sc_ioh, plcom_cr, sc->sc_cr); + + sc->sc_cr = PL01X_CR_UARTEN; + sc->sc_imsc = 0; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + SET(sc->sc_cr, PL010_CR_RIE | PL010_CR_RTIE); + break; + case PLCOM_TYPE_PL011: + SET(sc->sc_cr, PL011_CR_RXE); + SET(sc->sc_imsc, PL011_INT_RT | PL011_INT_RX); + break; + } + } + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + SET(sc->sc_cr, PL010_CR_RIE | PL010_CR_RTIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + case PLCOM_TYPE_PL011: + SET(sc->sc_cr, PL011_CR_RXE | PL011_CR_TXE); + SET(sc->sc_imsc, PL011_INT_RT | PL011_INT_RX); + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } mutex_spin_exit(&sc->sc_lock); if (sc->disable) { @@ -576,6 +738,7 @@ int plcomopen(dev_t dev, int flag, int mode, struct lwp *l) { struct plcom_softc *sc; + struct plcom_instance *pi; struct tty *tp; int s; int error; @@ -588,6 +751,8 @@ plcomopen(dev_t dev, int flag, int mode, struct lwp *l) if (!device_is_active(sc->sc_dev)) return ENXIO; + pi = &sc->sc_pi; + #ifdef KGDB /* * If this is the kgdb port, no other use is permitted. @@ -614,8 +779,8 @@ plcomopen(dev_t dev, int flag, int mode, struct lwp *l) if (sc->enable) { if ((*sc->enable)(sc)) { splx(s); - printf("%s: device enable failed\n", - device_xname(sc->sc_dev)); + aprint_error_dev(sc->sc_dev, + "device enable failed\n"); return EIO; } mutex_spin_enter(&sc->sc_lock); @@ -627,11 +792,23 @@ plcomopen(dev_t dev, int flag, int mode, struct lwp *l) /* Turn on interrupts. */ /* IER_ERXRDY | IER_ERLS | IER_EMSC; */ - sc->sc_cr = PL010_CR_RIE | PL010_CR_RTIE | PL010_CR_MSIE | PL01X_CR_UARTEN; - bus_space_write_1(sc->sc_iot, sc->sc_ioh, plcom_cr, sc->sc_cr); - /* Fetch the current modem control status, needed later. */ - sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, plcom_fr); + sc->sc_cr = PL01X_CR_UARTEN; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + SET(sc->sc_cr, + PL010_CR_RIE | PL010_CR_RTIE | PL010_CR_MSIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + sc->sc_msr = PREAD1(pi, PL01XCOM_FR); + break; + case PLCOM_TYPE_PL011: + SET(sc->sc_cr, PL011_CR_RXE | PL011_CR_TXE); + SET(sc->sc_imsc, PL011_INT_RT | PL011_INT_RX | + PL011_INT_MSMASK); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + sc->sc_msr = PREAD4(pi, PL01XCOM_FR); + break; + } /* Clear PPS capture state on first open. */ @@ -646,7 +823,6 @@ plcomopen(dev_t dev, int flag, int mode, struct lwp *l) * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ - t.c_ispeed = 0; if (ISSET(sc->sc_hwflags, PLCOM_HW_CONSOLE)) { t.c_ospeed = plcomconsrate; t.c_cflag = plcomconscflag; @@ -654,6 +830,8 @@ plcomopen(dev_t dev, int flag, int mode, struct lwp *l) t.c_ospeed = TTYDEF_SPEED; t.c_cflag = TTYDEF_CFLAG; } + t.c_ispeed = t.c_ospeed; + if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) @@ -802,12 +980,16 @@ plcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct plcom_softc *sc = device_lookup_private(&plcom_cd, PLCOMUNIT(dev)); - struct tty *tp = sc->sc_tty; + struct tty *tp; int error; + if (sc == NULL) + return ENXIO; if (PLCOM_ISALIVE(sc) == 0) return EIO; + tp = sc->sc_tty; + error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); if (error != EPASSTHROUGH) return error; @@ -817,6 +999,18 @@ plcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) return error; error = 0; + switch (cmd) { + case TIOCSFLAGS: + error = kauth_authorize_device_tty(l->l_cred, + KAUTH_DEVICE_TTY_PRIVSET, tp); + break; + default: + /* nothing */ + break; + } + if (error) { + return error; + } mutex_spin_enter(&sc->sc_lock); switch (cmd) { @@ -841,10 +1035,6 @@ plcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) break; case TIOCSFLAGS: - error = kauth_authorize_device_tty(l->l_cred, - KAUTH_DEVICE_TTY_PRIVSET, tp); - if (error) - break; sc->sc_swflags = *(int *)data; break; @@ -1085,6 +1275,8 @@ plcom_to_tiocm(struct plcom_softc *sc) SET(ttybits, TIOCM_CTS); if (ISSET(plcombits, PL01X_MSR_DSR)) SET(ttybits, TIOCM_DSR); + if (ISSET(plcombits, PL011_MSR_RI)) + SET(ttybits, TIOCM_RI); if (sc->sc_cr != 0) SET(ttybits, TIOCM_LE); @@ -1127,13 +1319,21 @@ plcomparam(struct tty *tp, struct termios *t) { struct plcom_softc *sc = device_lookup_private(&plcom_cd, PLCOMUNIT(tp->t_dev)); - int ospeed; + struct plcom_instance *pi = &sc->sc_pi; + int ospeed = -1; u_char lcr; if (PLCOM_ISALIVE(sc) == 0) return EIO; - ospeed = plcomspeed(t->c_ospeed, sc->sc_frequency); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + ospeed = pl010comspeed(t->c_ospeed, sc->sc_frequency); + break; + case PLCOM_TYPE_PL011: + ospeed = pl011comspeed(t->c_ospeed, sc->sc_frequency); + break; + } /* Check requested parameters. */ if (ospeed < 0) @@ -1224,11 +1424,19 @@ plcomparam(struct tty *tp, struct termios *t) SET(sc->sc_mcr, sc->sc_mcr_dtr); #endif - sc->sc_dlbl = ospeed; - sc->sc_dlbh = ospeed >> 8; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + sc->sc_ratel = ospeed & 0xff; + sc->sc_rateh = (ospeed >> 8) & 0xff; + break; + case PLCOM_TYPE_PL011: + sc->sc_ratel = ospeed & ((1 << 6) - 1); + sc->sc_rateh = ospeed >> 6; + break; + } /* And copy to tty. */ - tp->t_ispeed = 0; + tp->t_ispeed = t->c_ospeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = t->c_cflag; @@ -1285,8 +1493,7 @@ plcomparam(struct tty *tp, struct termios *t) void plcom_iflush(struct plcom_softc *sc) { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; #ifdef DIAGNOSTIC int reg; #endif @@ -1297,40 +1504,56 @@ plcom_iflush(struct plcom_softc *sc) #endif timo = 50000; /* flush any pending I/O */ - while (! ISSET(bus_space_read_1(iot, ioh, plcom_fr), PL01X_FR_RXFE) + while (! ISSET(PREAD1(pi, PL01XCOM_FR), PL01X_FR_RXFE) && --timo) #ifdef DIAGNOSTIC reg = #else (void) #endif - bus_space_read_1(iot, ioh, plcom_dr); + PREAD1(pi, PL01XCOM_DR); #ifdef DIAGNOSTIC if (!timo) - printf("%s: plcom_iflush timeout %02x\n", device_xname(sc->sc_dev), - reg); + aprint_error_dev(sc->sc_dev, ": %s timeout %02x\n", __func__, + reg); #endif } void plcom_loadchannelregs(struct plcom_softc *sc) { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; /* XXXXX necessary? */ plcom_iflush(sc); - bus_space_write_1(iot, ioh, plcom_cr, 0); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + PWRITE1(pi, PL010COM_CR, 0); + PWRITE1(pi, PL010COM_DLBL, sc->sc_ratel); + PWRITE1(pi, PL010COM_DLBH, sc->sc_rateh); + PWRITE1(pi, PL010COM_LCR, sc->sc_lcr); - bus_space_write_1(iot, ioh, plcom_dlbl, sc->sc_dlbl); - bus_space_write_1(iot, ioh, plcom_dlbh, sc->sc_dlbh); - bus_space_write_1(iot, ioh, plcom_lcr, sc->sc_lcr); - /* XXX device_unit() abuse */ - sc->sc_set_mcr(sc->sc_set_mcr_arg, device_unit(sc->sc_dev), - sc->sc_mcr_active = sc->sc_mcr); + /* XXX device_unit() abuse */ + if (sc->sc_set_mcr) + sc->sc_set_mcr(sc->sc_set_mcr_arg, + device_unit(sc->sc_dev), + sc->sc_mcr_active = sc->sc_mcr); - bus_space_write_1(iot, ioh, plcom_cr, sc->sc_cr); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + + case PLCOM_TYPE_PL011: + PWRITE4(pi, PL011COM_CR, 0); + PWRITE1(pi, PL011COM_FBRD, sc->sc_ratel); + PWRITE4(pi, PL011COM_IBRD, sc->sc_rateh); + PWRITE1(pi, PL011COM_LCRH, sc->sc_lcr); + sc->sc_mcr_active = sc->sc_mcr; + CLR(sc->sc_cr, PL011_MCR(PL01X_MCR_RTS | PL01X_MCR_DTR)); + SET(sc->sc_cr, PL011_MCR(sc->sc_mcr_active)); + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + break; + } } int @@ -1373,6 +1596,8 @@ plcomhwiflow(struct tty *tp, int block) void plcom_hwiflow(struct plcom_softc *sc) { + struct plcom_instance *pi = &sc->sc_pi; + if (sc->sc_mcr_rts == 0) return; @@ -1383,9 +1608,19 @@ plcom_hwiflow(struct plcom_softc *sc) SET(sc->sc_mcr, sc->sc_mcr_rts); SET(sc->sc_mcr_active, sc->sc_mcr_rts); } - /* XXX device_unit() abuse */ - sc->sc_set_mcr(sc->sc_set_mcr_arg, device_unit(sc->sc_dev), - sc->sc_mcr_active); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + if (sc->sc_set_mcr) + /* XXX device_unit() abuse */ + sc->sc_set_mcr(sc->sc_set_mcr_arg, + device_unit(sc->sc_dev), sc->sc_mcr_active); + break; + case PLCOM_TYPE_PL011: + CLR(sc->sc_cr, PL011_MCR(PL01X_MCR_RTS | PL01X_MCR_DTR)); + SET(sc->sc_cr, PL011_MCR(sc->sc_mcr_active)); + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + break; + } } @@ -1394,8 +1629,7 @@ plcomstart(struct tty *tp) { struct plcom_softc *sc = device_lookup_private(&plcom_cd, PLCOMUNIT(tp->t_dev)); - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; int s; if (PLCOM_ISALIVE(sc) == 0) @@ -1428,9 +1662,19 @@ plcomstart(struct tty *tp) sc->sc_tx_busy = 1; /* Enable transmit completion interrupts if necessary. */ - if (!ISSET(sc->sc_cr, PL010_CR_TIE)) { - SET(sc->sc_cr, PL010_CR_TIE); - bus_space_write_1(iot, ioh, plcom_cr, sc->sc_cr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + if (!ISSET(sc->sc_cr, PL010_CR_TIE)) { + SET(sc->sc_cr, PL010_CR_TIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + } + break; + case PLCOM_TYPE_PL011: + if (!ISSET(sc->sc_imsc, PL011_INT_TX)) { + SET(sc->sc_imsc, PL011_INT_TX); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + } + break; } /* Output the first chunk of the contiguous buffer. */ @@ -1440,7 +1684,7 @@ plcomstart(struct tty *tp) n = sc->sc_tbc; if (n > sc->sc_fifolen) n = sc->sc_fifolen; - bus_space_write_multi_1(iot, ioh, plcom_dr, sc->sc_tba, n); + PWRITEM1(pi, PL01XCOM_DR, sc->sc_tba, n); sc->sc_tbc -= n; sc->sc_tba += n; } @@ -1494,6 +1738,7 @@ integrate void plcom_rxsoft(struct plcom_softc *sc, struct tty *tp) { int (*rint) (int, struct tty *) = tp->t_linesw->l_rint; + struct plcom_instance *pi = &sc->sc_pi; u_char *get, *end; u_int cc, scc; u_char rsr; @@ -1568,8 +1813,18 @@ plcom_rxsoft(struct plcom_softc *sc, struct tty *tp) if (cc >= sc->sc_r_lowat) { if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); - SET(sc->sc_cr, PL010_CR_RIE | PL010_CR_RTIE); - bus_space_write_1(sc->sc_iot, sc->sc_ioh, plcom_cr, sc->sc_cr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + SET(sc->sc_cr, + PL010_CR_RIE | PL010_CR_RTIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + case PLCOM_TYPE_PL011: + SET(sc->sc_imsc, + PL011_INT_RX | PL011_INT_RT); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } } if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); @@ -1653,22 +1908,46 @@ plcomsoft(void *arg) } } +bool +plcom_intstatus(struct plcom_instance *pi, u_int *istatus) +{ + bool ret = false; + u_int stat = 0; + + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + stat = PREAD1(pi, PL010COM_IIR); + ret = ISSET(stat, PL010_IIR_IMASK); + break; + case PLCOM_TYPE_PL011: + stat = PREAD4(pi, PL011COM_MIS); + ret = ISSET(stat, PL011_INT_ALLMASK); + break; + } + *istatus = stat; + + return ret; +} + int plcomintr(void *arg) { struct plcom_softc *sc = arg; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; + struct plcom_instance *pi = &sc->sc_pi; u_char *put, *end; u_int cc; - u_char rsr, iir; + u_int istatus = 0; + u_char rsr; + bool intr = false; + + PLCOM_BARRIER(pi, BR | BW); if (PLCOM_ISALIVE(sc) == 0) return 0; mutex_spin_enter(&sc->sc_lock); - iir = bus_space_read_1(iot, ioh, plcom_iir); - if (! ISSET(iir, PL010_IIR_IMASK)) { + intr = plcom_intstatus(pi, &istatus); + if (!intr) { mutex_spin_exit(&sc->sc_lock); return 0; } @@ -1678,21 +1957,21 @@ plcomintr(void *arg) cc = sc->sc_rbavail; do { - u_char msr, delta, fr; + u_int msr = 0, delta, fr; + bool rxintr = false, txintr = false, msintr; - fr = bus_space_read_1(iot, ioh, plcom_fr); + /* don't need RI here*/ + fr = PREAD1(pi, PL01XCOM_FR); if (!ISSET(fr, PL01X_FR_RXFE) && !ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { while (cc > 0) { int cn_trapped = 0; - put[0] = bus_space_read_1(iot, ioh, - plcom_dr); - rsr = bus_space_read_1(iot, ioh, plcom_rsr); + put[0] = PREAD1(pi, PL01XCOM_DR); + rsr = PREAD1(pi, PL01XCOM_RSR); /* Clear any error status. */ if (ISSET(rsr, PL01X_RSR_ERROR)) - bus_space_write_1(iot, ioh, plcom_ecr, - 0); + PWRITE1(pi, PL01XCOM_ECR, 0); if (ISSET(rsr, PL01X_RSR_BE)) { cn_trapped = 0; cn_check_magic(sc->sc_tty->t_dev, @@ -1710,11 +1989,10 @@ plcomintr(void *arg) put[1] = rsr; cn_trapped = 0; - cn_check_magic(sc->sc_tty->t_dev, - put[0], plcom_cnm_state); + cn_check_magic(sc->sc_tty->t_dev, put[0], + plcom_cnm_state); if (cn_trapped) { - fr = bus_space_read_1(iot, ioh, - plcom_fr); + fr = PREAD1(pi, PL01XCOM_FR); if (ISSET(fr, PL01X_FR_RXFE)) break; @@ -1725,7 +2003,8 @@ plcomintr(void *arg) put = sc->sc_rbuf; cc--; - fr = bus_space_read_1(iot, ioh, plcom_fr); + /* don't need RI here*/ + fr = PREAD1(pi, PL01XCOM_FR); if (ISSET(fr, PL01X_FR_RXFE)) break; } @@ -1757,26 +2036,68 @@ plcomintr(void *arg) */ if (!cc) { SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); - CLR(sc->sc_cr, PL010_CR_RIE | PL010_CR_RTIE); - bus_space_write_1(iot, ioh, plcom_cr, - sc->sc_cr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + CLR(sc->sc_cr, + PL010_CR_RIE | PL010_CR_RTIE); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + break; + case PLCOM_TYPE_PL011: + CLR(sc->sc_imsc, + PL011_INT_RT | PL011_INT_RX); + PWRITE4(pi, PL011COM_IMSC, sc->sc_imsc); + break; + } } } else { - if (ISSET(iir, PL010_IIR_RIS)) { - bus_space_write_1(iot, ioh, plcom_cr, 0); - delay(10); - bus_space_write_1(iot, ioh, plcom_cr, - sc->sc_cr); - continue; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + rxintr = ISSET(istatus, PL010_IIR_RIS); + if (rxintr) { + PWRITE1(pi, PL010COM_CR, 0); + delay(10); + PWRITE1(pi, PL010COM_CR, sc->sc_cr); + continue; + } + break; + case PLCOM_TYPE_PL011: + rxintr = ISSET(istatus, PL011_INT_RX); + if (rxintr) { + PWRITE4(pi, PL011COM_CR, 0); + delay(10); + PWRITE4(pi, PL011COM_CR, sc->sc_cr); + continue; + } + break; } } - msr = bus_space_read_1(iot, ioh, plcom_fr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + msr = PREAD1(pi, PL01XCOM_FR); + break; + case PLCOM_TYPE_PL011: + msr = PREAD4(pi, PL01XCOM_FR); + break; + } delta = msr ^ sc->sc_msr; sc->sc_msr = msr; + /* Clear any pending modem status interrupt. */ - if (iir & PL010_IIR_MIS) - bus_space_write_1(iot, ioh, plcom_icr, 0); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + msintr = ISSET(istatus, PL010_IIR_MIS); + if (msintr) { + PWRITE1(pi, PL010COM_ICR, 0); + } + break; + case PLCOM_TYPE_PL011: + msintr = ISSET(istatus, PL011_INT_MSMASK); + if (msintr) { + PWRITE4(pi, PL011COM_ICR, PL011_INT_MSMASK); + } + break; + } /* * Pulse-per-second (PSS) signals on edge of DCD? * Process these even if line discipline is ignoring DCD. @@ -1847,14 +2168,24 @@ plcomintr(void *arg) /* * Done handling any receive interrupts. See if data - * can be * transmitted as well. Schedule tx done - * event if no data left * and tty was marked busy. + * can be transmitted as well. Schedule tx done + * event if no data left and tty was marked busy. */ - if (ISSET(iir, PL010_IIR_TIS)) { + + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + txintr = ISSET(istatus, PL010_IIR_TIS); + break; + case PLCOM_TYPE_PL011: + txintr = ISSET(istatus, PL011_INT_TX); + break; + } + if (txintr) { /* * If we've delayed a parameter change, do it * now, and restart * output. */ +// PWRITE4(pi, PL011COM_ICR, PL011_INT_TX); if (sc->sc_heldchange) { plcom_loadchannelregs(sc); sc->sc_heldchange = 0; @@ -1872,19 +2203,29 @@ plcomintr(void *arg) n = sc->sc_tbc; if (n > sc->sc_fifolen) n = sc->sc_fifolen; - bus_space_write_multi_1(iot, ioh, plcom_dr, - sc->sc_tba, n); + PWRITEM1(pi, PL01XCOM_DR, sc->sc_tba, n); sc->sc_tbc -= n; sc->sc_tba += n; } else { /* - * Disable transmit plcompletion + * Disable transmit completion * interrupts if necessary. */ - if (ISSET(sc->sc_cr, PL010_CR_TIE)) { - CLR(sc->sc_cr, PL010_CR_TIE); - bus_space_write_1(iot, ioh, plcom_cr, - sc->sc_cr); + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + if (ISSET(sc->sc_cr, PL010_CR_TIE)) { + CLR(sc->sc_cr, PL010_CR_TIE); + PWRITE1(pi, PL010COM_CR, + sc->sc_cr); + } + break; + case PLCOM_TYPE_PL011: + if (ISSET(sc->sc_imsc, PL011_INT_TX)) { + CLR(sc->sc_imsc, PL011_INT_TX); + PWRITE4(pi, PL011COM_IMSC, + sc->sc_imsc); + } + break; } if (sc->sc_tx_busy) { sc->sc_tx_busy = 0; @@ -1892,8 +2233,8 @@ plcomintr(void *arg) } } } - } while (ISSET((iir = bus_space_read_1(iot, ioh, plcom_iir)), - PL010_IIR_IMASK)); + + } while (plcom_intstatus(pi, &istatus)); mutex_spin_exit(&sc->sc_lock); @@ -1901,9 +2242,11 @@ plcomintr(void *arg) softint_schedule(sc->sc_si); #ifdef RND_COM - rnd_add_uint32(&sc->rnd_source, iir | rsr); + rnd_add_uint32(&sc->rnd_source, istatus | rsr); #endif + PLCOM_BARRIER(pi, BR | BW); + return 1; } @@ -1921,7 +2264,7 @@ static int plcom_readahead[MAX_READAHEAD]; static int plcom_readaheadcount = 0; int -plcom_common_getc(dev_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) +plcom_common_getc(dev_t dev, struct plcom_instance *pi) { int s = splserial(); u_char stat, c; @@ -1940,11 +2283,10 @@ plcom_common_getc(dev_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) } /* block until a character becomes available */ - while (ISSET(stat = bus_space_read_1(iot, ioh, plcom_fr), PL01X_FR_RXFE)) + while (ISSET(stat = PREAD1(pi, PL01XCOM_FR), PL01X_FR_RXFE)) ; - c = bus_space_read_1(iot, ioh, plcom_dr); - stat = bus_space_read_1(iot, ioh, plcom_iir); + c = PREAD1(pi, PL01XCOM_DR); { int cn_trapped = 0; /* unused */ #ifdef DDB @@ -1958,33 +2300,31 @@ plcom_common_getc(dev_t dev, bus_space_tag_t iot, bus_space_handle_t ioh) } void -plcom_common_putc(dev_t dev, bus_space_tag_t iot, bus_space_handle_t ioh, - int c) +plcom_common_putc(dev_t dev, struct plcom_instance *pi, int c) { int s = splserial(); int timo; int cin, stat; if (plcom_readaheadcount < MAX_READAHEAD - && !ISSET(stat = bus_space_read_1(iot, ioh, plcom_fr), PL01X_FR_RXFE)) { + && !ISSET(stat = PREAD1(pi, PL01XCOM_FR), PL01X_FR_RXFE)) { int cn_trapped = 0; - cin = bus_space_read_1(iot, ioh, plcom_dr); - stat = bus_space_read_1(iot, ioh, plcom_iir); + cin = PREAD1(pi, PL01XCOM_DR); cn_check_magic(dev, cin, plcom_cnm_state); plcom_readahead[plcom_readaheadcount++] = cin; } /* wait for any pending transmission to finish */ timo = 150000; - while (!ISSET(bus_space_read_1(iot, ioh, plcom_fr), PL01X_FR_TXFE) && --timo) + while (!ISSET(PREAD1(pi, PL01XCOM_FR), PL01X_FR_TXFE) && --timo) continue; - bus_space_write_1(iot, ioh, plcom_dr, c); - PLCOM_BARRIER(iot, ioh, BR | BW); + PWRITE1(pi, PL01XCOM_DR, c); + PLCOM_BARRIER(pi, BR | BW); /* wait for this transmission to complete */ timo = 1500000; - while (!ISSET(bus_space_read_1(iot, ioh, plcom_fr), PL01X_FR_TXFE) && --timo) + while (!ISSET(PREAD1(pi, PL01XCOM_FR), PL01X_FR_TXFE) && --timo) continue; splx(s); @@ -1994,20 +2334,49 @@ plcom_common_putc(dev_t dev, bus_space_tag_t iot, bus_space_handle_t ioh, * Initialize UART for use as console or KGDB line. */ int -plcominit(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, - tcflag_t cflag, bus_space_handle_t *iohp) +plcominit(struct plcom_instance *pi, int rate, int frequency, tcflag_t cflag) { - bus_space_handle_t ioh; + u_char lcr; - if (bus_space_map(iot, iobase, PLCOM_UART_SIZE, 0, &ioh)) + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + if (pi->pi_size == 0) + pi->pi_size = PL010COM_UART_SIZE; + break; + case PLCOM_TYPE_PL011: + if (pi->pi_size == 0) + pi->pi_size = PL011COM_UART_SIZE; + break; + default: + panic("Unknown plcom type"); + } + + if (bus_space_map(pi->pi_iot, pi->pi_iobase, pi->pi_size, 0, + &pi->pi_ioh)) return ENOMEM; /* ??? */ - rate = plcomspeed(rate, frequency); - bus_space_write_1(iot, ioh, plcom_cr, 0); - bus_space_write_1(iot, ioh, plcom_dlbl, rate); - bus_space_write_1(iot, ioh, plcom_dlbh, rate >> 8); - bus_space_write_1(iot, ioh, plcom_lcr, cflag2lcr(cflag) | PL01X_LCR_FEN); - bus_space_write_1(iot, ioh, plcom_cr, PL01X_CR_UARTEN); + lcr = cflag2lcr(cflag) | PL01X_LCR_FEN; + switch (pi->pi_type) { + case PLCOM_TYPE_PL010: + PWRITE1(pi, PL010COM_CR, 0); + + rate = pl010comspeed(rate, frequency); + PWRITE1(pi, PL010COM_DLBL, (rate & 0xff)); + PWRITE1(pi, PL010COM_DLBH, ((rate >> 8) & 0xff)); + PWRITE1(pi, PL010COM_LCR, lcr); + PWRITE1(pi, PL010COM_CR, PL01X_CR_UARTEN); + break; + case PLCOM_TYPE_PL011: + PWRITE4(pi, PL011COM_CR, 0); + + rate = pl011comspeed(rate, frequency); + PWRITE1(pi, PL011COM_FBRD, rate & ((1 << 6) - 1)); + PWRITE4(pi, PL011COM_IBRD, rate >> 6); + PWRITE1(pi, PL011COM_LCRH, lcr); + PWRITE4(pi, PL011COM_CR, + PL01X_CR_UARTEN | PL011_CR_RXE | PL011_CR_TXE); + break; + } #if 0 /* Ought to do something like this, but we have no sc to @@ -2017,7 +2386,6 @@ plcominit(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, PL01X_MCR_DTR | PL01X_MCR_RTS); #endif - *iohp = ioh; return 0; } @@ -2029,14 +2397,15 @@ struct consdev plcomcons = { NULL, NULL, NODEV, CN_NORMAL }; - int -plcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, +plcomcnattach(struct plcom_instance *pi, int rate, int frequency, tcflag_t cflag, int unit) { int res; - res = plcominit(iot, iobase, rate, frequency, cflag, &plcomconsioh); + plcomcons_info = *pi; + + res = plcominit(&plcomcons_info, rate, frequency, cflag); if (res) return res; @@ -2044,7 +2413,6 @@ plcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, cn_init_magic(&plcom_cnm_state); cn_set_magic("\047\001"); /* default magic is BREAK */ - plcomconstag = iot; plcomconsunit = unit; plcomconsrate = rate; plcomconscflag = cflag; @@ -2055,8 +2423,10 @@ plcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, int frequency, void plcomcndetach(void) { - bus_space_unmap(plcomconstag, plcomconsioh, PLCOM_UART_SIZE); - plcomconstag = NULL; + + bus_space_unmap(plcomcons_info.pi_iot, plcomcons_info.pi_ioh, + plcomcons_info.pi_size); + plcomcons_info.pi_iot = NULL; cn_tab = NULL; } @@ -2064,7 +2434,7 @@ plcomcndetach(void) int plcomcngetc(dev_t dev) { - return plcom_common_getc(dev, plcomconstag, plcomconsioh); + return plcom_common_getc(dev, &plcomcons_info); } /* @@ -2073,7 +2443,7 @@ plcomcngetc(dev_t dev) void plcomcnputc(dev_t dev, int c) { - plcom_common_putc(dev, plcomconstag, plcomconsioh, c); + plcom_common_putc(dev, &plcomcons_info, c); } void @@ -2084,23 +2454,25 @@ plcomcnpollc(dev_t dev, int on) #ifdef KGDB int -plcom_kgdb_attach(bus_space_tag_t iot, bus_addr_t iobase, int rate, - int frequency, tcflag_t cflag, int unit) +plcom_kgdb_attach(struct plcom_instance *pi, int rate, int frequency, + tcflag_t cflag, int unit) { int res; - if (iot == plcomconstag && iobase == plcomconsunit) + if (pi->pi_iot == plcomcons_info.pi_iot && + pi->pi_iobase == plcomcons_info.pi_iobase) return EBUSY; /* cannot share with console */ - res = plcominit(iot, iobase, rate, frequency, cflag, &plcom_kgdb_ioh); + res = plcominit(pi, rate, frequency, cflag); if (res) return res; kgdb_attach(plcom_kgdb_getc, plcom_kgdb_putc, NULL); kgdb_dev = 123; /* unneeded, only to satisfy some tests */ - plcom_kgdb_iot = iot; - plcom_kgdb_unit = unit; + plcomkgdb_info.pi_iot = pi->pi_iot; + plcomkgdb_info.pi_ioh = pi->pi_ioh; + plcomkgdb_info.pi_iobase = pi->pi_iobase; return 0; } @@ -2109,6 +2481,7 @@ plcom_kgdb_attach(bus_space_tag_t iot, bus_addr_t iobase, int rate, int plcom_kgdb_getc(void *arg) { + return plcom_common_getc(NODEV, plcom_kgdb_iot, plcom_kgdb_ioh); } @@ -2123,17 +2496,19 @@ plcom_kgdb_putc(void *arg, int c) /* helper function to identify the plcom ports used by console or KGDB (and not yet autoconf attached) */ int -plcom_is_console(bus_space_tag_t iot, int unit, +plcom_is_console(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t *ioh) { bus_space_handle_t help; if (!plcomconsattached && - iot == plcomconstag && unit == plcomconsunit) - help = plcomconsioh; + bus_space_is_equal(iot, plcomcons_info.pi_iot) && + iobase == plcomcons_info.pi_iobase) + help = plcomcons_info.pi_ioh; #ifdef KGDB else if (!plcom_kgdb_attached && - iot == plcom_kgdb_iot && unit == plcom_kgdb_unit) + bus_space_is_equal(iot, plcomkgdb_info.pi_iot) && + iobase == plcomkgdb_info.pi_iobase) help = plcom_kgdb_ioh; #endif else diff --git a/sys/arch/evbarm/dev/plcomreg.h b/sys/arch/evbarm/dev/plcomreg.h index 577c3d32d414..9777693912ec 100644 --- a/sys/arch/evbarm/dev/plcomreg.h +++ b/sys/arch/evbarm/dev/plcomreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: plcomreg.h,v 1.3 2012/05/14 19:40:06 skrll Exp $ */ +/* $NetBSD: plcomreg.h,v 1.4 2012/07/25 07:26:17 skrll Exp $ */ /*- * Copyright (c) 2001 ARM Ltd @@ -52,11 +52,12 @@ #define PL01X_CR_UARTEN 0x0001 /* Uart enable */ /* interrupt identification register */ -#define PL010_IIR_IMASK 0x0f #define PL010_IIR_RTIS 0x08 #define PL010_IIR_TIS 0x04 #define PL010_IIR_RIS 0x02 #define PL010_IIR_MIS 0x01 +#define PL010_IIR_IMASK \ + (PL010_IIR_RTIS | PL010_IIR_TIS | PL010_IIR_RIS | PL010_IIR_MIS) /* line control register */ #define PL011_LCR_SPS 0x80 /* Stick parity select */ @@ -77,16 +78,18 @@ /* modem control register */ #define PL01X_MCR_RTS 0x02 /* Request To Send */ #define PL01X_MCR_DTR 0x01 /* Data Terminal Ready */ +#define PL011_MCR(mcr) ((mcr) << 10) /* MCR to CR bit values for PL011 */ /* receive status register */ #define PL01X_RSR_OE 0x08 /* Overrun Error */ #define PL01X_RSR_BE 0x04 /* Break */ #define PL01X_RSR_PE 0x02 /* Parity Error */ #define PL01X_RSR_FE 0x01 /* Framing Error */ -#define PL01X_RSR_ERROR (PL01X_RSR_OE | PL01X_RSR_BE | PL01X_RSR_PE | PL01X_RSR_FE) +#define PL01X_RSR_ERROR \ + (PL01X_RSR_OE | PL01X_RSR_BE | PL01X_RSR_PE | PL01X_RSR_FE) /* flag register */ -#define PL01X_FR_RI 0x100 /* Ring Indicator */ +#define PL011_FR_RI 0x100 /* Ring Indicator */ #define PL01X_FR_TXFE 0x080 /* Transmit fifo empty */ #define PL01X_FR_RXFF 0x040 /* Recive fifo full */ #define PL01X_FR_TXFF 0x020 /* Transmit fifo full */ @@ -101,6 +104,7 @@ #define PL01X_MSR_DCD PL01X_FR_DCD #define PL01X_MSR_DSR PL01X_FR_DSR #define PL01X_MSR_CTS PL01X_FR_CTS +#define PL011_MSR_RI PL011_FR_RI /* All interrupt status/clear registers */ #define PL011_INT_OE 0x400 @@ -114,6 +118,12 @@ #define PL011_INT_DCD 0x004 #define PL011_INT_CTS 0x002 #define PL011_INT_RIR 0x001 +#define PL011_INT_MSMASK \ + (PL011_INT_DSR | PL011_INT_DCD | PL011_INT_CTS | PL011_INT_RIR) + +#define PL011_INT_ALLMASK \ + (PL011_INT_RT | PL011_INT_TX | PL011_INT_RX | PL011_INT_MSMASK) + /* DMA control registers */ #define PL011_DMA_ONERR 0x4 @@ -121,17 +131,27 @@ #define PL011_DMA_RXE 0x1 /* Register offsets */ -#define plcom_dr 0x00 -#define plcom_rsr 0x04 -#define plcom_ecr 0x04 -#define plcom_lcr 0x08 -#define plcom_dlbh 0x0c -#define plcom_dlbl 0x10 -#define plcom_cr 0x14 -#define plcom_fr 0x18 -#define plcom_iir 0x1c -#define plcom_icr 0x1c -#define plcom_ilpr 0x20 +#define PL01XCOM_DR 0x00 /* Data Register */ +#define PL01XCOM_RSR 0x04 /* Receive status register */ +#define PL01XCOM_ECR 0x04 /* Error clear register - same as RSR */ +#define PL010COM_LCR 0x08 /* Line Control Register */ +#define PL010COM_DLBH 0x0c +#define PL010COM_DLBL 0x10 +#define PL010COM_CR 0x14 +#define PL01XCOM_FR 0x18 /* Flag Register */ +#define PL010COM_IIR 0x1c +#define PL010COM_ICR 0x1c +#define PL01XCOM_ILPR 0x20 /* IrDA low-power control register */ +#define PL011COM_IBRD 0x24 /* Integer baud rate divisor register */ +#define PL011COM_FBRD 0x28 /* Fractional baud rate divisor register */ +#define PL011COM_LCRH 0x2c /* Line control register */ +#define PL011COM_CR 0x30 /* Control register */ +#define PL011COM_IFLS 0x34 /* Interrupt FIFO level select register */ +#define PL011COM_IMSC 0x38 /* Interrupt mask set/clear register */ +#define PL011COM_RIS 0x3c /* Raw interrupt status register */ +#define PL011COM_MIS 0x40 /* Masked interrupt status register */ +#define PL011COM_ICR 0x44 /* Interrupt clear register register */ +#define PL011COM_DMACR 0x48 /* DMA control register register */ -/* IFPGA specific */ -#define PLCOM_UART_SIZE 0x24 +#define PL010COM_UART_SIZE 0x100 +#define PL011COM_UART_SIZE 0x1000 diff --git a/sys/arch/evbarm/dev/plcomvar.h b/sys/arch/evbarm/dev/plcomvar.h index c8916c991c6d..b5ea328a07f1 100644 --- a/sys/arch/evbarm/dev/plcomvar.h +++ b/sys/arch/evbarm/dev/plcomvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: plcomvar.h,v 1.10 2012/05/20 10:28:44 skrll Exp $ */ +/* $NetBSD: plcomvar.h,v 1.11 2012/07/25 07:26:18 skrll Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -44,14 +44,16 @@ #include #include -int plcomcnattach (bus_space_tag_t, bus_addr_t, int, int, tcflag_t, int); +struct plcom_instance; + +int plcomcnattach (struct plcom_instance *, int, int, tcflag_t, int); void plcomcndetach (void); #ifdef KGDB -int plcom_kgdb_attach (bus_space_tag_t, bus_addr_t, int, int, tcflag_t); +int plcom_kgdb_attach (struct plcom_instance *, int, int, tcflag_t); #endif -int plcom_is_console (bus_space_tag_t, int, bus_space_handle_t *); +int plcom_is_console (bus_space_tag_t, bus_addr_t, bus_space_handle_t *); /* Hardware flag masks */ #define PLCOM_HW_NOIEN 0x01 @@ -66,18 +68,43 @@ int plcom_is_console (bus_space_tag_t, int, bus_space_handle_t *); /* Buffer size for character buffer */ #define PLCOM_RING_SIZE 2048 +struct plcom_instance { + u_int pi_type; +#define PLCOM_TYPE_PL010 0 +#define PLCOM_TYPE_PL011 1 + + uint32_t pi_flags; /* flags for this PLCOM */ +#define PLC_FLAG_USE_DMA 0x0001 +#define PLC_FLAG_32BIT_ACCESS 0x0002 + + void *pi_cookie; + + bus_space_tag_t pi_iot; + bus_space_handle_t pi_ioh; + bus_addr_t pi_iobase; + bus_addr_t pi_size; + struct plcom_registers *pi_regs; +}; + +struct plcomcons_info { + int rate; + int frequency; + int type; + + tcflag_t cflag; +}; + struct plcom_softc { device_t sc_dev; - void *sc_si; + struct tty *sc_tty; + void *sc_si; struct callout sc_diag_callout; - bus_addr_t sc_iounit; - int sc_frequency; + int sc_frequency; - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; + struct plcom_instance sc_pi; u_int sc_overflows, sc_floods, @@ -112,12 +139,13 @@ struct plcom_softc { sc_rx_ready; volatile u_char sc_heldchange; - volatile u_char sc_msr, sc_msr_delta, sc_msr_mask, sc_mcr, - sc_mcr_active, sc_lcr, sc_cr, sc_dlbl, sc_dlbh; + volatile u_int sc_cr, sc_ratel, sc_rateh, sc_imsc; + volatile u_int sc_msr, sc_msr_delta, sc_msr_mask; + volatile u_char sc_mcr, sc_mcr_active, sc_lcr; u_char sc_mcr_dtr, sc_mcr_rts, sc_msr_cts, sc_msr_dcd; u_int sc_fifo; - /* Support routine to program mcr lines, if present. */ + /* Support routine to program mcr lines for PL010, if present. */ void (*sc_set_mcr)(void *, int, u_int); void *sc_set_mcr_arg; @@ -139,7 +167,9 @@ struct plcom_softc { kmutex_t sc_lock; }; +#if 0 int plcomprobe1 (bus_space_tag_t, bus_space_handle_t); +#endif int plcomintr (void *); void plcom_attach_subr (struct plcom_softc *); int plcom_detach (device_t, int); diff --git a/sys/arch/evbarm/ifpga/ifpgareg.h b/sys/arch/evbarm/ifpga/ifpgareg.h index e1518743fc79..56dbdfeb3253 100644 --- a/sys/arch/evbarm/ifpga/ifpgareg.h +++ b/sys/arch/evbarm/ifpga/ifpgareg.h @@ -1,4 +1,4 @@ -/* $NetBSD: ifpgareg.h,v 1.3 2005/12/11 12:17:09 christos Exp $ */ +/* $NetBSD: ifpgareg.h,v 1.4 2012/07/25 07:26:18 skrll Exp $ */ /* * Copyright (c) 2001 ARM Ltd @@ -32,6 +32,7 @@ /* System clock defaults. */ #define IFPGA_UART_CLK 14745600 /* Uart REFCLK freq */ +#define IFPGA_UART_SIZE 0x24 /* * IFPGA registers diff --git a/sys/arch/evbarm/ifpga/plcom_ifpga.c b/sys/arch/evbarm/ifpga/plcom_ifpga.c index a31752b19f30..b6fc21da22c7 100644 --- a/sys/arch/evbarm/ifpga/plcom_ifpga.c +++ b/sys/arch/evbarm/ifpga/plcom_ifpga.c @@ -1,4 +1,4 @@ -/* $NetBSD: plcom_ifpga.c,v 1.13 2012/05/20 10:28:44 skrll Exp $ */ +/* $NetBSD: plcom_ifpga.c,v 1.14 2012/07/25 07:26:18 skrll Exp $ */ /* * Copyright (c) 2001 ARM Ltd @@ -32,7 +32,7 @@ /* Interface to plcom (PL010) serial driver. */ #include -__KERNEL_RCSID(0, "$NetBSD: plcom_ifpga.c,v 1.13 2012/05/20 10:28:44 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: plcom_ifpga.c,v 1.14 2012/07/25 07:26:18 skrll Exp $"); #include #include @@ -75,24 +75,27 @@ plcom_ifpga_attach(device_t parent, device_t self, void *aux) isc->sc_iot = ifa->ifa_iot; isc->sc_ioh = ifa->ifa_sc_ioh; + sc->sc_dev = self; - sc->sc_iounit = device_unit(sc->sc_dev); + sc->sc_pi.pi_type = PLCOM_TYPE_PL010; + sc->sc_pi.pi_iot = ifa->ifa_iot; + sc->sc_pi.pi_iobase = ifa->ifa_addr; + sc->sc_pi.pi_size = IFPGA_UART_SIZE; sc->sc_frequency = IFPGA_UART_CLK; - sc->sc_iot = ifa->ifa_iot; sc->sc_hwflags = 0; sc->sc_swflags = 0; sc->sc_set_mcr = plcom_ifpga_set_mcr; sc->sc_set_mcr_arg = (void *)isc; - if (bus_space_map(ifa->ifa_iot, ifa->ifa_addr, PLCOM_UART_SIZE, 0, - &sc->sc_ioh)) { + if (bus_space_map(ifa->ifa_iot, ifa->ifa_addr, IFPGA_UART_SIZE, 0, + &sc->sc_pi.pi_ioh)) { printf("%s: unable to map device\n", device_xname(sc->sc_dev)); return; } plcom_attach_subr(sc); - isc->sc_ih = ifpga_intr_establish(ifa->ifa_irq, IPL_SERIAL, plcomintr, - sc); + isc->sc_ih = ifpga_intr_establish(ifa->ifa_irq, IPL_SERIAL, + plcomintr, sc); if (isc->sc_ih == NULL) panic("%s: cannot install interrupt handler", device_xname(sc->sc_dev)); diff --git a/sys/arch/evbarm/integrator/integrator_machdep.c b/sys/arch/evbarm/integrator/integrator_machdep.c index 76ed6ff95ea7..86156ceab92b 100644 --- a/sys/arch/evbarm/integrator/integrator_machdep.c +++ b/sys/arch/evbarm/integrator/integrator_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: integrator_machdep.c,v 1.68 2011/07/01 20:39:34 dyoung Exp $ */ +/* $NetBSD: integrator_machdep.c,v 1.69 2012/07/25 07:26:18 skrll Exp $ */ /* * Copyright (c) 2001,2002 ARM Ltd @@ -68,7 +68,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: integrator_machdep.c,v 1.68 2011/07/01 20:39:34 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: integrator_machdep.c,v 1.69 2012/07/25 07:26:18 skrll Exp $"); #include "opt_ddb.h" #include "opt_pmap_debug.h" @@ -383,9 +383,6 @@ initarm(void *arg) psize_t memsize; vm_offset_t physical_freestart; vm_offset_t physical_freeend; -#if NPLCOM > 0 && defined(PLCONSOLE) - static struct bus_space plcom_bus_space; -#endif /* * Heads up ... Setup the CPU / MMU / TLB functions @@ -402,13 +399,29 @@ initarm(void *arg) */ if (PLCOMCNUNIT == 0) { + static struct bus_space plcom_bus_space; + static struct plcom_instance ifpga_pi0 = { + .pi_type = PLCOM_TYPE_PL010, + .pi_iot = &plcom_bus_space, + .pi_size = IFPGA_UART_SIZE, + .pi_iobase = 0x0 + }; + ifpga_create_io_bs_tag(&plcom_bus_space, (void*)0xfd600000); - plcomcnattach(&plcom_bus_space, 0, plcomcnspeed, - IFPGA_UART_CLK, plcomcnmode, PLCOMCNUNIT); + plcomcnattach(&ifpga_pi0, plcomcnspeed, IFPGA_UART_CLK, + plcomcnmode, PLCOMCNUNIT); } else if (PLCOMCNUNIT == 1) { + static struct bus_space plcom_bus_space; + static struct plcom_instance ifpga_pi1 = { + .pi_type = PLCOM_TYPE_PL010, + .pi_iot = &plcom_bus_space, + .pi_size = IFPGA_UART_SIZE, + .pi_iobase = 0x0 + }; + ifpga_create_io_bs_tag(&plcom_bus_space, (void*)0xfd700000); - plcomcnattach(&plcom_bus_space, 0, plcomcnspeed, - IFPGA_UART_CLK, plcomcnmode, PLCOMCNUNIT); + plcomcnattach(&ifpga_pi1, plcomcnspeed, IFPGA_UART_CLK, + plcomcnmode, PLCOMCNUNIT); } #endif @@ -788,9 +801,6 @@ void consinit(void) { static int consinit_called = 0; -#if NPLCOM > 0 && defined(PLCONSOLE) - static struct bus_space plcom_bus_space; -#endif #if 0 char *console = CONSDEVNAME; #endif @@ -802,17 +812,35 @@ consinit(void) #if NPLCOM > 0 && defined(PLCONSOLE) if (PLCOMCNUNIT == 0) { + static struct bus_space plcom_bus_space; + static struct plcom_instance ifpga_pi1 = { + .pi_type = PLCOM_TYPE_PL010, + .pi_iot = &plcom_bus_space, + .pi_size = IFPGA_UART_SIZE, + .pi_iobase = 0x0 + }; + ifpga_create_io_bs_tag(&plcom_bus_space, (void*)UART0_BOOT_BASE); - if (plcomcnattach(&plcom_bus_space, 0, plcomcnspeed, - IFPGA_UART_CLK, plcomcnmode, PLCOMCNUNIT)) + + if (plcomcnattach(&ifpga_pi1, plcomcnspeed, IFPGA_UART_CLK, + plcomcnmode, PLCOMCNUNIT)) panic("can't init serial console"); return; } else if (PLCOMCNUNIT == 1) { + static struct bus_space plcom_bus_space; + static struct plcom_instance ifpga_pi1 = { + .pi_type = PLCOM_TYPE_PL010, + .pi_iot = &plcom_bus_space, + .pi_size = IFPGA_UART_SIZE, + .pi_iobase = 0x0 + }; + ifpga_create_io_bs_tag(&plcom_bus_space, (void*)UART0_BOOT_BASE); - if (plcomcnattach(&plcom_bus_space, 0, plcomcnspeed, - IFPGA_UART_CLK, plcomcnmode, PLCOMCNUNIT)) + + if (plcomcnattach(&ifpga_pi1, plcomcnspeed, IFPGA_UART_CLK, + plcomcnmode, PLCOMCNUNIT)) panic("can't init serial console"); return; }