diff options
author | Jeff Garzik <jgarzik@pretzel.yyz.us> | 2005-06-22 13:07:28 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-22 13:07:28 -0400 |
commit | ff40c6d3d1437ecdf295b8e39adcb06c3d6021ef (patch) | |
tree | 3666d029b4bd4df2909dbefd9c7a09e6042b7d32 /drivers/serial | |
parent | 8bf62ecee58360749c5f0e68bc97d5e02a6816b1 (diff) | |
parent | 2a5a68b840cbab31baab2d9b2e1e6de3b289ae1e (diff) |
Merge upstream kernel changes into 'C/H/S support' branch of libata.
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/21285.c | 14 | ||||
-rw-r--r-- | drivers/serial/8250.c | 32 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 11 | ||||
-rw-r--r-- | drivers/serial/Makefile | 2 | ||||
-rw-r--r-- | drivers/serial/amba-pl010.c | 14 | ||||
-rw-r--r-- | drivers/serial/amba-pl011.c | 14 | ||||
-rw-r--r-- | drivers/serial/clps711x.c | 5 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.c | 9 | ||||
-rw-r--r-- | drivers/serial/ioc4_serial.c | 336 | ||||
-rw-r--r-- | drivers/serial/pxa.c | 16 | ||||
-rw-r--r-- | drivers/serial/s3c2410.c | 15 | ||||
-rw-r--r-- | drivers/serial/sa1100.c | 7 | ||||
-rw-r--r-- | drivers/serial/serial_cs.c | 4 | ||||
-rw-r--r-- | drivers/serial/serial_lh7a40x.c | 13 | ||||
-rw-r--r-- | drivers/serial/serial_txx9.c | 15 | ||||
-rw-r--r-- | drivers/serial/sunsab.c | 109 | ||||
-rw-r--r-- | drivers/serial/sunsab.h | 1 | ||||
-rw-r--r-- | drivers/serial/vr41xx_siu.c | 72 |
18 files changed, 282 insertions, 407 deletions
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 33fbda79f35..0b10169961e 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r flag = TTY_FRAME; } - if ((rxs & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rxs & RXSTAT_OVERRUN) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); + status = *CSR_UARTFLG; } tty_flip_buffer_push(tty); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 0d9358608fd..30e8beb7143 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -682,8 +682,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) * from EXCR1. Switch back to bank 0, change it in MCR. Then * switch back to bank 2, read it from EXCR1 again and check * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - * On PowerPC we don't want to change baud_base, as we have - * a number of different divisors. -- Tom Rini */ serial_outp(up, UART_LCR, 0); status1 = serial_in(up, UART_MCR); @@ -699,16 +697,25 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_outp(up, UART_MCR, status1); if ((status2 ^ status1) & UART_MCR_LOOP) { -#ifndef CONFIG_PPC + unsigned short quot; + serial_outp(up, UART_LCR, 0xE0); + + quot = serial_inp(up, UART_DLM) << 8; + quot += serial_inp(up, UART_DLL); + quot <<= 3; + status1 = serial_in(up, 0x04); /* EXCR1 */ status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ serial_outp(up, 0x04, status1); + + serial_outp(up, UART_DLL, quot & 0xff); + serial_outp(up, UART_DLM, quot >> 8); + serial_outp(up, UART_LCR, 0); - up->port.uartclk = 921600*16; -#endif + up->port.uartclk = 921600*16; up->port.type = PORT_NS16550A; up->capabilities |= UART_NATSEMI; return; @@ -1122,18 +1129,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((lsr & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((lsr & UART_LSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + ignore_char: lsr = serial_inp(up, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6e44b46c9e9..25fcef2c42d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -753,7 +753,7 @@ config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_ICOM tristate "IBM Multiport Serial Adapter" - depends on PPC_ISERIES || PPC_PSERIES + depends on PCI && (PPC_ISERIES || PPC_PSERIES) select SERIAL_CORE help This driver is for a family of multiport serial adapters @@ -843,4 +843,13 @@ config SERIAL_JSM To compile this driver as a module, choose M here: the module will be called jsm. +config SERIAL_SGI_IOC4 + tristate "SGI IOC4 controller serial support" + depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4 + select SERIAL_CORE + help + If you have an SGI Altix with an IOC4 based Base IO card + and wish to use the serial ports on this card, say Y. + Otherwise, say N. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 81b77d769b8..8f1cdde7dbe 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -51,4 +51,4 @@ obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o -obj-$(CONFIG_BLK_DEV_SGIIOC4) += ioc4_serial.o +obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index f2a5e2933c4..2884b310e54 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port) if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((rsr & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rsr & UART01x_RSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); + ignore_char: status = UART_GET_FR(port); } diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index d5cbef3fe8b..7db88ee18f7 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap) if (uart_handle_sysrq_char(&uap->port, ch, regs)) goto ignore_char; - if ((rsr & uap->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rsr & UART01x_RSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); + ignore_char: status = readw(uap->port.membase + UART01x_FR); } diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 6242f3090a9..e92522b33c4 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ - if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0) - tty_insert_flip_char(tty, ch, flg); - if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); ignore_char: status = clps_readl(SYSFLG(port)); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index b422c3abfba..c4c8f4b44f5 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -134,12 +134,21 @@ void scc1_lineif(struct uart_cpm_port *pinfo) void scc2_lineif(struct uart_cpm_port *pinfo) { + /* + * STx GP3 uses the SCC2 secondary option pin assignment + * which this driver doesn't account for in the static + * pin assignments. This kind of board specific info + * really has to get out of the driver so boards can + * be supported in a sane fashion. + */ +#ifndef CONFIG_STX_GP3 volatile iop_cpm2_t *io = &cpm2_immr->im_ioport; io->iop_pparb |= 0x008b0000; io->iop_pdirb |= 0x00880000; io->iop_psorb |= 0x00880000; io->iop_pdirb &= ~0x00030000; io->iop_psorb &= ~0x00030000; +#endif cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff; cpm2_immr->im_cpmux.cmx_scr |= 0x00090000; pinfo->brg = 2; diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index ba4e13a22a5..793c3a7cbe4 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -20,7 +20,7 @@ #include <linux/serial_reg.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/ioc4_common.h> +#include <linux/ioc4.h> #include <linux/serial_core.h> /* @@ -130,12 +130,19 @@ IOC4_SIO_IR_S3_TX_EXPLICIT) /* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ -#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ -#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ -#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ -#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ -#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ -#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */ +#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */ +#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */ + +#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ + IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR) /* Bitmasks for IOC4_SIO_CR */ #define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ @@ -274,70 +281,24 @@ struct ioc4_uartregs { #define i4u_dlm u2.dlm #define i4u_fcr u3.fcr -/* PCI memory space register map addressed using pci_bar0 */ -struct ioc4_memregs { - struct ioc4_mem { - /* Miscellaneous IOC4 registers */ - uint32_t pci_err_addr_l; - uint32_t pci_err_addr_h; - uint32_t sio_ir; - uint32_t other_ir; - - /* These registers are read-only for general kernel code. */ - uint32_t sio_ies_ro; - uint32_t other_ies_ro; - uint32_t sio_iec_ro; - uint32_t other_iec_ro; - uint32_t sio_cr; - uint32_t misc_fill1; - uint32_t int_out; - uint32_t misc_fill2; - uint32_t gpcr_s; - uint32_t gpcr_c; - uint32_t gpdr; - uint32_t misc_fill3; - uint32_t gppr_0; - uint32_t gppr_1; - uint32_t gppr_2; - uint32_t gppr_3; - uint32_t gppr_4; - uint32_t gppr_5; - uint32_t gppr_6; - uint32_t gppr_7; - } ioc4_mem; - - char misc_fill4[0x100 - 0x5C - 4]; - - /* ATA/ATAP registers */ - uint32_t ata_notused[9]; - char ata_fill1[0x140 - 0x120 - 4]; - uint32_t ata_notused1[8]; - char ata_fill2[0x200 - 0x15C - 4]; - - /* Keyboard and mouse registers */ - uint32_t km_notused[5];; - char km_fill1[0x300 - 0x210 - 4]; - - /* Serial port registers used for DMA serial I/O */ - struct ioc4_serial { - uint32_t sbbr01_l; - uint32_t sbbr01_h; - uint32_t sbbr23_l; - uint32_t sbbr23_h; - - struct ioc4_serialregs port_0; - struct ioc4_serialregs port_1; - struct ioc4_serialregs port_2; - struct ioc4_serialregs port_3; - struct ioc4_uartregs uart_0; - struct ioc4_uartregs uart_1; - struct ioc4_uartregs uart_2; - struct ioc4_uartregs uart_3; - } ioc4_serial; -}; +/* Serial port registers used for DMA serial I/O */ +struct ioc4_serial { + uint32_t sbbr01_l; + uint32_t sbbr01_h; + uint32_t sbbr23_l; + uint32_t sbbr23_h; + + struct ioc4_serialregs port_0; + struct ioc4_serialregs port_1; + struct ioc4_serialregs port_2; + struct ioc4_serialregs port_3; + struct ioc4_uartregs uart_0; + struct ioc4_uartregs uart_1; + struct ioc4_uartregs uart_2; + struct ioc4_uartregs uart_3; +} ioc4_serial; /* UART clock speed */ -#define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66 #define IOC4_SER_XIN_CLK_66 66666667 #define IOC4_SER_XIN_CLK_33 33333333 @@ -412,8 +373,8 @@ enum sio_proto { | UART_LCR_WLEN7 | UART_LCR_WLEN8) #define LCR_MASK_STOP_BITS (UART_LCR_STOP) -#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir) & _p->ip_ienb) -#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir) +#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb) +#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw) /* Default to 4k buffers */ #ifdef IOC4_1K_BUFFERS @@ -447,7 +408,7 @@ struct ioc4_control { */ #define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) struct ioc4_soft { - struct ioc4_mem __iomem *is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; struct ioc4_serial __iomem *is_ioc4_serial_addr; /* Each interrupt type has an entry in the array */ @@ -486,7 +447,7 @@ struct ioc4_port { struct ioc4_soft *ip_ioc4_soft; /* pci mem addresses */ - struct ioc4_mem __iomem *ip_mem; + struct ioc4_misc_regs __iomem *ip_mem; struct ioc4_serial __iomem *ip_serial; struct ioc4_serialregs __iomem *ip_serial_regs; struct ioc4_uartregs __iomem *ip_uart_regs; @@ -553,7 +514,7 @@ struct hooks { uint32_t intr_dma_error; uint32_t intr_clear; uint32_t intr_all; - char rs422_select_pin; + int rs422_select_pin; }; static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { @@ -669,7 +630,7 @@ static void handle_intr(void *arg, uint32_t sio_ir); static inline void write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) { - struct ioc4_mem __iomem *mem = ioc4_soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr; unsigned long flags; spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); @@ -678,11 +639,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) case IOC4_SIO_INTR_TYPE: switch (which) { case IOC4_W_IES: - writel(val, &mem->sio_ies_ro); + writel(val, &mem->sio_ies.raw); break; case IOC4_W_IEC: - writel(val, &mem->sio_iec_ro); + writel(val, &mem->sio_iec.raw); break; } break; @@ -690,11 +651,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) case IOC4_OTHER_INTR_TYPE: switch (which) { case IOC4_W_IES: - writel(val, &mem->other_ies_ro); + writel(val, &mem->other_ies.raw); break; case IOC4_W_IEC: - writel(val, &mem->other_iec_ro); + writel(val, &mem->other_iec.raw); break; } break; @@ -747,7 +708,8 @@ static int set_baud(struct ioc4_port *port, int baud) */ static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) { - struct ioc4_control *control = dev_get_drvdata(the_port->dev); + struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); + struct ioc4_control *control = idd->idd_serial_data; int ii; if (control) { @@ -782,7 +744,7 @@ static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) static inline uint32_t pending_intrs(struct ioc4_soft *soft, int type) { - struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; unsigned long flag; uint32_t intrs = 0; @@ -793,11 +755,11 @@ pending_intrs(struct ioc4_soft *soft, int type) switch (type) { case IOC4_SIO_INTR_TYPE: - intrs = readl(&mem->sio_ir) & readl(&mem->sio_ies_ro); + intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw); break; case IOC4_OTHER_INTR_TYPE: - intrs = readl(&mem->other_ir) & readl(&mem->other_ies_ro); + intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw); /* Don't process any ATA interrupte */ intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); @@ -826,7 +788,7 @@ static int inline port_init(struct ioc4_port *port) /* Wait until any pending bus activity for this port has ceased */ do - sio_cr = readl(&port->ip_mem->sio_cr); + sio_cr = readl(&port->ip_mem->sio_cr.raw); while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); /* Finish reset sequence */ @@ -899,7 +861,7 @@ static int inline port_init(struct ioc4_port *port) write_ireg(port->ip_ioc4_soft, hooks->intr_clear, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); port->ip_ienb &= ~hooks->intr_clear; - writel(hooks->intr_clear, &port->ip_mem->sio_ir); + writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw); return 0; } @@ -918,23 +880,23 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir) spin_lock_irqsave(&port->ip_lock, flags); /* ACK the interrupt */ - writel(hooks->intr_dma_error, &port->ip_mem->other_ir); + writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw); - if (readl(&port->ip_mem->pci_err_addr_l) & IOC4_PCI_ERR_ADDR_VLD) { + if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) { printk(KERN_ERR "PCI error address is 0x%lx, " "master is serial port %c %s\n", (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) << 32) - | readl(&port->ip_mem->pci_err_addr_l)) + | readl(&port->ip_mem->pci_err_addr_l.raw)) & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + - ((char)(readl(&port->ip_mem-> pci_err_addr_l) & + ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), - (readl(&port->ip_mem->pci_err_addr_l) + (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) ? "RX" : "TX"); - if (readl(&port->ip_mem->pci_err_addr_l) + if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_MUL_ERR) { printk(KERN_ERR "Multiple errors occurred\n"); @@ -1018,26 +980,26 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) "other_ies = 0x%x\n", (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" : "other", this_ir, - readl(&soft->is_ioc4_mem_addr->sio_ir), - readl(&soft->is_ioc4_mem_addr->sio_ies_ro), - readl(&soft->is_ioc4_mem_addr->other_ir), - readl(&soft->is_ioc4_mem_addr->other_ies_ro)); + readl(&soft->is_ioc4_misc_addr->sio_ir.raw), + readl(&soft->is_ioc4_misc_addr->sio_ies.raw), + readl(&soft->is_ioc4_misc_addr->other_ir.raw), + readl(&soft->is_ioc4_misc_addr->other_ies.raw)); } } #ifdef DEBUG_INTERRUPTS { - struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; spinlock_t *lp = &soft->is_ir_lock; unsigned long flag; spin_lock_irqsave(&soft->is_ir_lock, flag); - printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies_ro 0x%x " - "other_ir 0x%x other_ies_ro 0x%x mask 0x%x\n", + printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " + "other_ir 0x%x other_ies 0x%x mask 0x%x\n", __FUNCTION__, __LINE__, - (void *)mem, readl(&mem->sio_ir), - readl(&mem->sio_ies_ro), - readl(&mem->other_ir), - readl(&mem->other_ies_ro), + (void *)mem, readl(&mem->sio_ir.raw), + readl(&mem->sio_ies.raw), + readl(&mem->other_ir.raw), + readl(&mem->other_ies.raw), IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); spin_unlock_irqrestore(&soft->is_ir_lock, flag); } @@ -1049,21 +1011,20 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) * ioc4_attach_local - Device initialization. * Called at *_attach() time for each * IOC4 with serial ports in the system. - * @control: ioc4_control ptr - * @pdev: PCI handle for this device - * @soft: soft struct for this device - * @ioc4: ioc4 mem space + * @idd: Master module data for this IOC4 */ -static int inline ioc4_attach_local(struct pci_dev *pdev, - struct ioc4_control *control, - struct ioc4_soft *soft, void __iomem *ioc4_mem, - void __iomem *ioc4_serial) +static int inline ioc4_attach_local(struct ioc4_driver_data *idd) { struct ioc4_port *port; struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS]; int port_number; uint16_t ioc4_revid_min = 62; uint16_t ioc4_revid; + struct pci_dev *pdev = idd->idd_pdev; + struct ioc4_control* control = idd->idd_serial_data; + struct ioc4_soft *soft = control->ic_soft; + void __iomem *ioc4_misc = idd->idd_misc_regs; + void __iomem *ioc4_serial = soft->is_ioc4_serial_addr; /* IOC4 firmware must be at least rev 62 */ pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid); @@ -1076,7 +1037,7 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, ioc4_revid, ioc4_revid_min); return -EPERM; } - BUG_ON(ioc4_mem == NULL); + BUG_ON(ioc4_misc == NULL); BUG_ON(ioc4_serial == NULL); /* Create port structures for each port */ @@ -1100,10 +1061,18 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, port->ip_ioc4_soft = soft; port->ip_pdev = pdev; port->ip_ienb = 0; - port->ip_pci_bus_speed = IOC4_SER_XIN_CLK; + /* Use baud rate calculations based on detected PCI + * bus speed. Simply test whether the PCI clock is + * running closer to 66MHz or 33MHz. + */ + if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66; + } else { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33; + } port->ip_baud = 9600; port->ip_control = control; - port->ip_mem = ioc4_mem; + port->ip_mem = ioc4_misc; port->ip_serial = ioc4_serial; /* point to the right hook */ @@ -1604,14 +1573,12 @@ static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto) switch (proto) { case PROTO_RS232: /* Clear the appropriate GIO pin */ - writel(0, (&port->ip_mem->gppr_0 + - hooks->rs422_select_pin)); + writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); break; case PROTO_RS422: /* Set the appropriate GIO pin */ - writel(1, (&port->ip_mem->gppr_0 + - hooks->rs422_select_pin)); + writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); break; default: @@ -1885,7 +1852,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_delta_dcd) { /* ACK the interrupt */ writel(hooks->intr_delta_dcd, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); shadow = readl(&port->ip_serial_regs->shadow); @@ -1907,7 +1874,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_delta_cts) { /* ACK the interrupt */ writel(hooks->intr_delta_cts, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); shadow = readl(&port->ip_serial_regs->shadow); @@ -1928,7 +1895,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) if (sio_ir & hooks->intr_rx_timer) { /* ACK the interrupt */ writel(hooks->intr_rx_timer, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); if ((port->ip_notify & N_DATA_READY) && (port->ip_port)) { @@ -1974,7 +1941,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) /* ACK the interrupt */ writel(hooks->intr_tx_explicit, - &port->ip_mem->sio_ir); + &port->ip_mem->sio_ir.raw); if (port->ip_notify & N_OUTPUT_LOWAT) ioc4_cb_output_lowat(port); @@ -2634,7 +2601,8 @@ ioc4_serial_core_attach(struct pci_dev *pdev) { struct ioc4_port *port; struct uart_port *the_port; - struct ioc4_control *control = pci_get_drvdata(pdev); + struct ioc4_driver_data *idd = pci_get_drvdata(pdev); + struct ioc4_control *control = idd->idd_serial_data; int ii; DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", @@ -2680,55 +2648,29 @@ ioc4_serial_core_attach(struct pci_dev *pdev) /** * ioc4_serial_attach_one - register attach function - * called per card found from ioc4_serial_detect as part - * of module_init(). - * @pdev: handle for this card - * @pci_id: pci id for this card + * called per card found from IOC4 master module. + * @idd: Master module data for this IOC4 */ int -ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) +ioc4_serial_attach_one(struct ioc4_driver_data *idd) { - struct ioc4_mem __iomem *mem; - unsigned long tmp_addr, tmp_addr1; + unsigned long tmp_addr1; struct ioc4_serial __iomem *serial; struct ioc4_soft *soft; struct ioc4_control *control; - int tmp, ret = 0; + int ret = 0; - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, pdev, pci_id)); - - /* Map in the ioc4 memory */ - tmp_addr = pci_resource_start(pdev, 0); - if (!tmp_addr) { - printk(KERN_WARNING - "ioc4 (%p) : unable to get PIO mapping for " - "MEM space\n", (void *)pdev); - return -ENODEV; - } - if (!request_region(tmp_addr, sizeof(struct ioc4_mem), "sioc4_mem")) { - printk(KERN_ALERT - "ioc4 (%p): unable to get request region for " - "MEM space\n", (void *)pdev); - return -ENODEV; - } - mem = ioremap(tmp_addr, sizeof(struct ioc4_mem)); - if (!mem) { - printk(KERN_WARNING - "ioc4 (%p) : unable to remap ioc4 memory\n", - (void *)pdev); - ret = -ENODEV; - goto out1; - } + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id)); /* request serial registers */ - tmp_addr1 = pci_resource_start(pdev, 0) + IOC4_SERIAL_OFFSET; + tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; if (!request_region(tmp_addr1, sizeof(struct ioc4_serial), "sioc4_uart")) { printk(KERN_WARNING "ioc4 (%p): unable to get request region for " - "uart space\n", (void *)pdev); + "uart space\n", (void *)idd->idd_pdev); ret = -ENODEV; goto out1; } @@ -2736,12 +2678,12 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!serial) { printk(KERN_WARNING "ioc4 (%p) : unable to remap ioc4 serial register\n", - (void *)pdev); + (void *)idd->idd_pdev); ret = -ENODEV; goto out2; } DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", - __FUNCTION__, (void *)mem, (void *)serial)); + __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial)); /* Get memory for the new card */ control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS, @@ -2754,59 +2696,56 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) goto out2; } memset(control, 0, sizeof(struct ioc4_control)); - pci_set_drvdata(pdev, control); + idd->idd_serial_data = control; /* Allocate the soft structure */ soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL); if (!soft) { printk(KERN_WARNING "ioc4 (%p): unable to get memory for the soft struct\n", - (void *)pdev); + (void *)idd->idd_pdev); ret = -ENOMEM; goto out3; } memset(soft, 0, sizeof(struct ioc4_soft)); spin_lock_init(&soft->is_ir_lock); - soft->is_ioc4_mem_addr = mem; + soft->is_ioc4_misc_addr = idd->idd_misc_regs; soft->is_ioc4_serial_addr = serial; /* Init the IOC4 */ - pci_read_config_dword(pdev, PCI_COMMAND, &tmp); - pci_write_config_dword(pdev, PCI_COMMAND, - tmp | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - - writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, &mem->sio_cr); + writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, + &idd->idd_misc_regs->sio_cr.raw); /* Enable serial port mode select generic PIO pins as outputs */ writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, - &mem->gpcr_s); + &idd->idd_misc_regs->gpcr_s.raw); - /* Clear and disable all interrupts */ + /* Clear and disable all serial interrupts */ write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); - writel(~0, &mem->sio_ir); - write_ireg(soft, ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR), - IOC4_W_IEC, IOC4_OTHER_INTR_TYPE); - writel(~(IOC4_OTHER_IR_ATA_MEMERR | IOC4_OTHER_IR_ATA_MEMERR), - &mem->other_ir); + writel(~0, &idd->idd_misc_regs->sio_ir.raw); + write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC, + IOC4_OTHER_INTR_TYPE); + writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw); control->ic_soft = soft; - if (!request_irq(pdev->irq, ioc4_intr, SA_SHIRQ, + + /* Hook up interrupt handler */ + if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ, "sgi-ioc4serial", (void *)soft)) { - control->ic_irq = pdev->irq; + control->ic_irq = idd->idd_pdev->irq; } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, pdev->irq); + __FUNCTION__, idd->idd_pdev->irq); } - if ((ret = ioc4_attach_local(pdev, control, soft, - soft->is_ioc4_mem_addr, - soft->is_ioc4_serial_addr))) + ret = ioc4_attach_local(idd); + if (ret) goto out4; /* register port with the serial core */ - if ((ret = ioc4_serial_core_attach(pdev))) + if ((ret = ioc4_serial_core_attach(idd->idd_pdev))) goto out4; return ret; @@ -2819,7 +2758,6 @@ out3: out2: release_region(tmp_addr1, sizeof(struct ioc4_serial)); out1: - release_region(tmp_addr, sizeof(struct ioc4_mem)); return ret; } @@ -2828,11 +2766,10 @@ out1: /** * ioc4_serial_remove_one - detach function * - * @pdev: handle for this card + * @idd: IOC4 master module data for this IOC4 */ -#if 0 -void ioc4_serial_remove_one(struct pci_dev *pdev) +int ioc4_serial_remove_one(struct ioc4_driver_data *idd) { int ii; struct ioc4_control *control; @@ -2840,7 +2777,7 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) struct ioc4_port *port; struct ioc4_soft *soft; - control = pci_get_drvdata(pdev); + control = idd->idd_serial_data; for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { the_port = &control->ic_port[ii].icp_uart_port; @@ -2867,10 +2804,17 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) kfree(soft); } kfree(control); - pci_set_drvdata(pdev, NULL); - uart_unregister_driver(&ioc4_uart); + idd->idd_serial_data = NULL; + + return 0; } -#endif + +static struct ioc4_submodule ioc4_serial_submodule = { + .is_name = "IOC4_serial", + .is_owner = THIS_MODULE, + .is_probe = ioc4_serial_attach_one, + .is_remove = ioc4_serial_remove_one, +}; /** * ioc4_serial_init - module init @@ -2886,12 +2830,20 @@ int ioc4_serial_init(void) __FUNCTION__); return ret; } - return 0; + + /* register with IOC4 main module */ + return ioc4_register_submodule(&ioc4_serial_submodule); +} + +static void __devexit ioc4_serial_exit(void) +{ + ioc4_unregister_submodule(&ioc4_serial_submodule); + uart_unregister_driver(&ioc4_uart); } +module_init(ioc4_serial_init); +module_exit(ioc4_serial_exit); + MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>"); MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(ioc4_serial_init); -EXPORT_SYMBOL(ioc4_serial_attach_one); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 51d8a49f447..9dc151d8fa6 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) else if (*status & UART_LSR_FE) flag = TTY_FRAME; } + if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((*status & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((*status & UART_LSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); + ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 435750d40a4..2a9f7ade2c9 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((uerstat & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - - if ((uerstat & S3C2410_UERSTAT_OVERRUN) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); ignore_char: continue; diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 157218bc6c6..98641c3f5ab 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -197,7 +197,7 @@ static void sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) { struct tty_struct *tty = sport->port.info->tty; - unsigned int status, ch, flg, ignored = 0; + unsigned int status, ch, flg; status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | UTSR0_TO_SM(UART_GET_UTSR0(sport)); @@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) if (uart_handle_sysrq_char(&sport->port, ch, regs)) goto ignore_char; - if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0) - tty_insert_flip_char(tty, ch, flg); - if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR)) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); ignore_char: status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 6eeb48f6a48..0d7b65f93e8 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -661,10 +661,10 @@ void serial_config(dev_link_t * link) /* Is this a multiport card? */ tuple->DesiredTuple = CISTPL_MANFID; if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { - info->manfid = le16_to_cpu(buf[0]); + info->manfid = parse->manfid.manf; for (i = 0; i < MULTI_COUNT; i++) if ((info->manfid == multi_id[i].manfid) && - (le16_to_cpu(buf[1]) == multi_id[i].prodid)) + (parse->manfid.card == multi_id[i].prodid)) break; if (i < MULTI_COUNT) info->multi = multi_id[i].multi; diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 85cfa08d3ba..56f269b6bfb 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) continue; - if ((data & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, data, flag); - } - if ((data & RxOverrunError) - && tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, data, RxOverrunError, data, flag); } tty_flip_buffer_push (tty); return; diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 37b2ef297cb..3f1051a4a13 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((disr & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((disr & TXX9_SIDISR_UOER) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); + ignore_char: disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 39b788d95e3..10e2990a40d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -61,6 +61,16 @@ struct uart_sunsab_port { unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ int type; /* SAB82532 version */ + + /* Setting configuration bits while the transmitter is active + * can cause garbage characters to get emitted by the chip. + * Therefore, we cache such writes here and do the real register + * write the next time the transmitter becomes idle. + */ + unsigned int cached_ebrg; + unsigned char cached_mode; + unsigned char cached_pvr; + unsigned char cached_dafo; }; /* @@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *up, } static void sunsab_stop_tx(struct uart_port *, unsigned int); +static void sunsab_tx_idle(struct uart_sunsab_port *); static void transmit_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) @@ -258,6 +269,7 @@ static void transmit_chars(struct uart_sunsab_port *up, return; set_bit(SAB82532_XPR, &up->irqflags); + sunsab_tx_idle(up); if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; @@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; if (mctrl & TIOCM_RTS) { - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_mode &= ~SAB82532_MODE_FRTS; + up->cached_mode |= SAB82532_MODE_RTS; } else { - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_mode |= (SAB82532_MODE_FRTS | + SAB82532_MODE_RTS); } if (mctrl & TIOCM_DTR) { - writeb(readb(&up->regs->rw.pvr) & ~(up->pvr_dtr_bit), &up->regs->rw.pvr); + up->cached_pvr &= ~(up->pvr_dtr_bit); } else { - writeb(readb(&up->regs->rw.pvr) | up->pvr_dtr_bit, &up->regs->rw.pvr); + up->cached_pvr |= up->pvr_dtr_bit; } + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); } /* port->lock is not held. */ @@ -450,6 +462,25 @@ static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop) } /* port->lock held by caller. */ +static void sunsab_tx_idle(struct uart_sunsab_port *up) +{ + if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) { + u8 tmp; + + clear_bit(SAB82532_REGS_PENDING, &up->irqflags); + writeb(up->cached_mode, &up->regs->rw.mode); + writeb(up->cached_pvr, &up->regs->rw.pvr); + writeb(up->cached_dafo, &up->regs->w.dafo); + + writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr); + tmp = readb(&up->regs->rw.ccr2); + tmp &= ~0xc0; + tmp |= (up->cached_ebrg >> 2) & 0xc0; + writeb(tmp, &up->regs->rw.ccr2); + } +} + +/* port->lock held by caller. */ static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; @@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) spin_lock_irqsave(&up->port.lock, flags); - val = readb(&up->regs->rw.dafo); + val = up->cached_dafo; if (break_state) val |= SAB82532_DAFO_XBRK; else val &= ~SAB82532_DAFO_XBRK; - writeb(val, &up->regs->rw.dafo); + up->cached_dafo = val; + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_port *port) SAB82532_CCR2_TOE, &up->regs->w.ccr2); writeb(0, &up->regs->w.ccr3); writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); - writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | - SAB82532_MODE_RAC, &up->regs->w.mode); + up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS | + SAB82532_MODE_RAC); + writeb(up->cached_mode, &up->regs->w.mode); writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); tmp = readb(&up->regs->rw.ccr0); @@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_port *port) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; unsigned long flags; - unsigned char tmp; spin_lock_irqsave(&up->port.lock, flags); @@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_port *port) writeb(up->interrupt_mask1, &up->regs->w.imr1); /* Disable break condition */ - tmp = readb(&up->regs->rw.dafo); - tmp &= ~SAB82532_DAFO_XBRK; - writeb(tmp, &up->regs->rw.dafo); + up->cached_dafo = readb(&up->regs->rw.dafo); + up->cached_dafo &= ~SAB82532_DAFO_XBRK; + writeb(up->cached_dafo, &up->regs->rw.dafo); /* Disable Receiver */ - tmp = readb(&up->regs->rw.mode); - tmp &= ~SAB82532_MODE_RAC; - writeb(tmp, &up->regs->rw.mode); + up->cached_mode &= ~SAB82532_MODE_RAC; + writeb(up->cached_mode, &up->regs->rw.mode); /* * XXX FIXME @@ -685,7 +719,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla unsigned int iflag, unsigned int baud, unsigned int quot) { - unsigned int ebrg; unsigned char dafo; int bits, n, m; @@ -714,10 +747,11 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla } else { dafo |= SAB82532_DAFO_PAR_EVEN; } + up->cached_dafo = dafo; calc_ebrg(baud, &n, &m); - ebrg = n | (m << 6); + up->cached_ebrg = n | (m << 6); up->tec_timeout = (10 * 1000000) / baud; up->cec_timeout = up->tec_timeout >> 2; @@ -770,16 +804,13 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla uart_update_timeout(&up->port, cflag, (up->port.uartclk / (16 * quot))); - /* Now bang the new settings into the chip. */ - sunsab_cec_wait(up); - sunsab_tec_wait(up); - writeb(dafo, &up->regs->w.dafo); - writeb(ebrg & 0xff, &up->regs->w.bgr); - writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), - &up->regs->rw.ccr2); - - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode); - + /* Now schedule a register update when the chip's + * transmitter is idle. + */ + up->cached_mode |= SAB82532_MODE_RAC; + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); } /* port->lock is not held. */ @@ -1084,11 +1115,13 @@ static void __init sunsab_init_hw(void) up->pvr_dsr_bit = (1 << 3); up->pvr_dtr_bit = (1 << 2); } - writeb((1 << 1) | (1 << 2) | (1 << 4), &up->regs->w.pvr); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); + writeb(up->cached_pvr, &up->regs->w.pvr); + up->cached_mode = readb(&up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_FRTS; + writeb(up->cached_mode, &up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_RTS; + writeb(up->cached_mode, &up->regs->rw.mode); up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h index 686086fcbbf..b78e1f7b805 100644 --- a/drivers/serial/sunsab.h +++ b/drivers/serial/sunsab.h @@ -126,6 +126,7 @@ union sab82532_irq_status { /* irqflags bits */ #define SAB82532_ALLS 0x00000001 #define SAB82532_XPR 0x00000002 +#define SAB82532_REGS_PENDING 0x00000004 /* RFIFO Status Byte */ #define SAB82532_RSTAT_PE 0x80 diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 307886199f2..1f985327b0d 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -234,7 +234,7 @@ static inline const char *siu_type_name(struct uart_port *port) return "DSIU"; } - return "unknown"; + return NULL; } static unsigned int siu_tx_empty(struct uart_port *port) @@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status, if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((lsr & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); - if ((lsr & UART_LSR_OE) && (tty->flip.count < TTY_FLIPBUF_SIZE)) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); ignore_char: lsr = siu_read(port, UART_LSR); @@ -484,9 +482,6 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct uart_port *port; uint8_t iir, lsr; - if (dev_id == NULL) - return IRQ_NONE; - port = (struct uart_port *)dev_id; iir = siu_read(port, UART_IIR); @@ -509,6 +504,9 @@ static int siu_startup(struct uart_port *port) { int retval; + if (port->membase == NULL) + return -ENODEV; + siu_clear_fifo(port); (void)siu_read(port, UART_LSR); @@ -547,9 +545,6 @@ static void siu_shutdown(struct uart_port *port) unsigned long flags; uint8_t lcr; - if (port->membase == NULL) - return; - siu_write(port, UART_IER, 0); spin_lock_irqsave(&port->lock, flags); @@ -804,53 +799,6 @@ static int siu_init_ports(void) #ifdef CONFIG_SERIAL_VR41XX_CONSOLE -static void early_set_termios(struct uart_port *port, struct termios *new, - struct termios *old) -{ - tcflag_t c_cflag; - uint8_t lcr; - unsigned int baud, quot; - - c_cflag = new->c_cflag; - switch (c_cflag & CSIZE) { - case CS5: - lcr = UART_LCR_WLEN5; - break; - case CS6: - lcr = UART_LCR_WLEN6; - break; - case CS7: - lcr = UART_LCR_WLEN7; - break; - default: - lcr = UART_LCR_WLEN8; - break; - } - - if (c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - if (c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - if ((c_cflag & PARODD) != PARODD) - lcr |= UART_LCR_EPAR; - if (c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; - - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); - - siu_write(port, UART_DLL, (uint8_t)quot); - siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); - - siu_write(port, UART_LCR, lcr); -} - -static struct uart_ops early_uart_ops = { - .set_termios = early_set_termios, -}; - #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) static void wait_for_xmitr(struct uart_port *port) @@ -917,7 +865,7 @@ static int siu_console_setup(struct console *con, char *options) if (port->membase == NULL) { if (port->mapbase == 0) return -ENODEV; - port->membase = (unsigned char __iomem *)KSEG1ADDR(port->mapbase); + port->membase = ioremap(port->mapbase, siu_port_size(port)); } vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); @@ -951,7 +899,7 @@ static int __devinit siu_console_init(void) for (i = 0; i < num; i++) { port = &siu_uart_ports[i]; - port->ops = &early_uart_ops; + port->ops = &siu_uart_ops; } register_console(&siu_console); @@ -996,8 +944,10 @@ static int siu_probe(struct device *dev) port->dev = dev; retval = uart_add_one_port(&siu_uart_driver, port); - if (retval) + if (retval < 0) { + port->dev = NULL; break; + } } if (i == 0 && retval < 0) { |