diff options
author | sobomax <sobomax@FreeBSD.org> | 2003-03-15 16:25:40 +0000 |
---|---|---|
committer | sobomax <sobomax@FreeBSD.org> | 2003-03-15 16:25:40 +0000 |
commit | b8597af91cb6ffe5daabe96d27818547ef65ff33 (patch) | |
tree | 55efefc19da767f399830aeb6d78166bc554ea4f | |
parent | 9cb5290df7bf3276f0ddc34c782809f8d1573ee4 (diff) | |
download | FreeBSD-src-b8597af91cb6ffe5daabe96d27818547ef65ff33.zip FreeBSD-src-b8597af91cb6ffe5daabe96d27818547ef65ff33.tar.gz |
- Add minimal support for TI16754 4xUART chip into sio(4) driver and remove
now unnecessary hack from the previous commit;
- Add support for Interrupt Latch Register (ILR) into puc(4). So far only
ILRs compatible with specifications from Digi International are supported.
Support for other types of ILRs could be easily added later;
- Correct clock frequency for IC Book Labs Dreadnought x16 Lite board;
- Enable ILR detection/usage for IC Book Labs Dreadnought x16 boards.
Sponsored by: IC Book Labs
MFC after: 2 weeks
-rw-r--r-- | sys/dev/puc/puc.c | 74 | ||||
-rw-r--r-- | sys/dev/puc/pucdata.c | 70 | ||||
-rw-r--r-- | sys/dev/puc/pucvar.h | 9 | ||||
-rw-r--r-- | sys/dev/sio/sio.c | 34 |
4 files changed, 146 insertions, 41 deletions
diff --git a/sys/dev/puc/puc.c b/sys/dev/puc/puc.c index 18d2fba..fedf9bb 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 e556215..7e65aa7 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 fcbb0eb..9bb3928 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 f5e7363..dcfd46a 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) \ @@ -605,6 +606,33 @@ sioprobe(dev, xrid, rclk, noprobe) /* 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. * The speed is undefined after a master reset and must be set @@ -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 |