diff --git a/sys/dev/puc/puc.c b/sys/dev/puc/puc.c index 18d2fbabc0f5..fedf9bb073cf 100644 --- a/sys/dev/puc/puc.c +++ b/sys/dev/puc/puc.c @@ -130,6 +130,35 @@ puc_port_bar_index(struct puc_softc *sc, int bar) return (i); } +static int +puc_probe_ilr(struct puc_softc *sc, struct resource *res) +{ + u_char t1, t2; + int i; + + switch (sc->sc_desc->ilr_type) { + case PUC_ILR_TYPE_DIGI: + sc->ilr_st = rman_get_bustag(res); + sc->ilr_sh = rman_get_bushandle(res); + for (i = 0; i < 2; i++) { + t1 = bus_space_read_1(sc->ilr_st, sc->ilr_sh, + sc->sc_desc->ilr_offset[i]); + t1 = ~t1; + bus_space_write_1(sc->ilr_st, sc->ilr_sh, + sc->sc_desc->ilr_offset[i], t1); + t2 = bus_space_read_1(sc->ilr_st, sc->ilr_sh, + sc->sc_desc->ilr_offset[i]); + if (t2 == t1) + return (0); + } + return (1); + + default: + break; + } + return (0); +} + int puc_attach(device_t dev, const struct puc_device_description *desc) { @@ -195,6 +224,14 @@ puc_attach(device_t dev, const struct puc_device_description *desc) } sc->sc_bar_mappings[bidx].type = type; sc->sc_bar_mappings[bidx].res = res; + + if (sc->sc_desc->ilr_type != PUC_ILR_TYPE_NONE) { + sc->ilr_enabled = puc_probe_ilr(sc, res); + if (sc->ilr_enabled) + device_printf(dev, "ILR enabled\n"); + else + device_printf(dev, "ILR disabled\n"); + } #ifdef PUC_DEBUG printf("%s rid %d bst %x, start %x, end %x\n", (type == SYS_RES_MEMORY) ? "memory" : "port", rid, @@ -307,22 +344,47 @@ puc_attach(device_t dev, const struct puc_device_description *desc) return (0); } +static u_int32_t +puc_ilr_read(struct puc_softc *sc) +{ + u_int32_t mask; + int i; + + mask = 0; + switch (sc->sc_desc->ilr_type) { + case PUC_ILR_TYPE_DIGI: + for (i = 1; i >= 0; i--) { + mask = (mask << 8) | (bus_space_read_1(sc->ilr_st, + sc->ilr_sh, sc->sc_desc->ilr_offset[i]) & 0xff); + } + break; + + default: + mask = 0xffffffff; + break; + } + return (mask); +} + /* - * This is just a brute force interrupt handler. It just calls all the - * registered handlers sequencially. - * - * Later on we should maybe have a different handler for boards that can - * tell us which device generated the interrupt. + * This is an interrupt handler. For boards that can't tell us which + * device generated the interrupt it just calls all the registered + * handlers sequencially, but for boards that can tell us which + * device(s) generated the interrupt it calls only handlers for devices + * that actually generated the interrupt. */ static void puc_intr(void *arg) { int i; + u_int32_t ilr_mask; struct puc_softc *sc; sc = (struct puc_softc *)arg; + ilr_mask = sc->ilr_enabled ? puc_ilr_read(sc) : 0xffffffff; for (i = 0; i < PUC_MAX_PORTS; i++) - if (sc->sc_ports[i].ihand != NULL) + if (sc->sc_ports[i].ihand != NULL && + ((ilr_mask >> i) & 0x00000001)) (sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg); } diff --git a/sys/dev/puc/pucdata.c b/sys/dev/puc/pucdata.c index e55621502b6e..7e65aa775a15 100644 --- a/sys/dev/puc/pucdata.c +++ b/sys/dev/puc/pucdata.c @@ -1000,23 +1000,24 @@ const struct puc_device_description puc_devices[] = { { 0xb00c, 0x091c, 0, 0 }, { 0xffff, 0xffff, 0, 0 }, { - { PUC_PORT_TYPE_COM, 0x10, 0x00, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x08, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x10, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x18, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x20, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x28, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x30, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x38, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x40, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x48, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x50, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x58, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x60, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x68, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x70, COM_FREQ * 4 }, - { PUC_PORT_TYPE_COM, 0x10, 0x78, COM_FREQ * 4 }, + { PUC_PORT_TYPE_COM, 0x10, 0x00, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x08, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x10, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x18, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x20, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x28, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x30, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x38, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x40, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x48, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x50, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x58, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x60, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x68, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x70, COM_FREQ }, + { PUC_PORT_TYPE_COM, 0x10, 0x78, COM_FREQ }, }, + PUC_ILR_TYPE_DIGI, { 0x07, 0x47 }, }, { "IC Book Labs Dreadnought x16 Pro", @@ -1024,23 +1025,24 @@ const struct puc_device_description puc_devices[] = { { 0xb00c, 0x081c, 0, 0 }, { 0xffff, 0xffff, 0, 0 }, { - { PUC_PORT_TYPE_COM, 0x10, 0x00, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x08, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x10, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x18, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x20, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x28, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x30, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x38, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x40, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x48, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x50, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x58, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x60, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x68, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x70, COM_FREQ * 8 }, - { PUC_PORT_TYPE_COM, 0x10, 0x78, COM_FREQ * 8 }, + { PUC_PORT_TYPE_COM, 0x10, 0x00, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x08, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x10, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x18, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x20, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x28, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x30, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x38, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x40, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x48, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x50, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x58, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x60, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x68, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x70, COM_FREQ * 8, 0x200000 }, + { PUC_PORT_TYPE_COM, 0x10, 0x78, COM_FREQ * 8, 0x200000 }, }, + PUC_ILR_TYPE_DIGI, { 0x07, 0x47 }, }, { 0 } diff --git a/sys/dev/puc/pucvar.h b/sys/dev/puc/pucvar.h index fcbb0eb86b66..9bb3928340de 100644 --- a/sys/dev/puc/pucvar.h +++ b/sys/dev/puc/pucvar.h @@ -80,6 +80,8 @@ struct puc_device_description { u_int serialfreq; u_int flags; } ports[PUC_MAX_PORTS]; + uint32_t ilr_type; + uint32_t ilr_offset[2]; }; #define PUC_REG_VEND 0 @@ -91,6 +93,10 @@ struct puc_device_description { #define PUC_PORT_TYPE_COM 1 #define PUC_PORT_TYPE_LPT 2 +/* Interrupt Latch Register (ILR) types */ +#define PUC_ILR_TYPE_NONE 0 +#define PUC_ILR_TYPE_DIGI 1 + #define PUC_FLAGS_MEMORY 0x0001 /* Use memory mapped I/O. */ #define PUC_PORT_VALID(desc, port) \ @@ -126,6 +132,9 @@ struct puc_softc { int irqrid; struct resource *irqres; void *intr_cookie; + int ilr_enabled; + bus_space_tag_t ilr_st; + bus_space_handle_t ilr_sh; struct { int used; diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c index f5e7363601eb..dcfd46a781f7 100644 --- a/sys/dev/sio/sio.c +++ b/sys/dev/sio/sio.c @@ -120,6 +120,7 @@ #define COM_C_IIR_TXRDYBUG (0x80000) #define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG) #define COM_NOSCR(flags) ((flags) & 0x100000) +#define COM_TI16754(flags) ((flags) & 0x200000) #define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24) #define sio_getreg(com, off) \ @@ -604,6 +605,33 @@ sioprobe(dev, xrid, rclk, noprobe) mtx_lock_spin(&sio_lock); /* EXTRA DELAY? */ + /* + * For the TI16754 chips set prescaler to 1 (4 is often the + * default after-reset value), otherwise it's impossible to + * get highest baudrates. + */ + if (COM_TI16754(flags)) { + u_char t1, t2; + + /* Save LCR */ + t1 = sio_getreg(com, com_lctl); + /* Enable EFR */ + sio_setreg(com, com_lctl, 0xbf); + /* Save EFR */ + t2 = sio_getreg(com, com_iir); + /* Unlock MCR[7] */ + sio_setreg(com, com_iir, t2 | 0x10); + /* Disable EFR */ + sio_setreg(com, com_lctl, 0); + /* Set prescaler to 1 */ + sio_setreg(com, com_mcr, sio_getreg(com, com_mcr) & 0x7f); + /* Enable EFR */ + sio_setreg(com, com_lctl, 0xbf); + /* Restore EFR */ + sio_setreg(com, com_iir, t2); + /* Restore LCR */ + sio_setreg(com, com_lctl, t1); + } /* * Initialize the speed and the word size and wait long enough to * drain the maximum of 16 bytes of junk in device output queues. @@ -731,6 +759,7 @@ sioprobe(dev, xrid, rclk, noprobe) failures[0] = sio_getreg(com, com_cfcr) - CFCR_8BITS; failures[1] = sio_getreg(com, com_ier) - IER_ETXRDY; failures[2] = (sio_getreg(com, com_mcr) & 0x7f) - mcr_image; + failures[2] = sio_getreg(com, com_mcr) - mcr_image; DELAY(10000); /* Some internal modems need this time */ irqmap[1] = isa_irq_pending(); failures[4] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_TXRDY; @@ -1007,6 +1036,9 @@ sioattach(dev, xrid, rclk) com->st16650a = 1; com->tx_fifo_size = 32; printf(" ST16650A"); + } else if (COM_TI16754(flags)) { + com->tx_fifo_size = 64; + printf(" TI16754"); } else { com->tx_fifo_size = COM_FIFOSIZE(flags); printf(" 16550A"); @@ -1019,7 +1051,7 @@ sioattach(dev, xrid, rclk) break; } #endif - if (!com->st16650a) { + if (!com->st16650a && !COM_TI16754(flags)) { if (!com->tx_fifo_size) com->tx_fifo_size = 16; else