diff -Naur linux-2.4.x.orig/drivers/char/68328serial.c linux-2.4.x/drivers/char/68328serial.c --- linux-2.4.x.orig/drivers/char/68328serial.c Thu Oct 4 11:16:04 2001 +++ linux-2.4.x/drivers/char/68328serial.c Thu Oct 4 09:33:00 2001 @@ -6,6 +6,7 @@ * Copyright (C) 1999 Vladimir Gurevich * * VZ Support/Fixes Evan Stawnyczy + * Multiple UART support Daniel Potts */ #include @@ -59,7 +60,13 @@ #define USE_INTS #endif -static struct m68k_serial m68k_soft; +static struct m68k_serial m68k_soft[NR_PORTS]; +struct m86k_serial *IRQ_ports[NR_IRQS]; + +static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; + +/* multiple ports are contiguous in memory */ +m68328_uart *uart_addr = USTCNT_ADDR; struct tty_struct m68k_ttys; struct m68k_serial *m68k_consinfo = 0; @@ -95,9 +102,9 @@ static void change_speed(struct m68k_serial *info); -static struct tty_struct *serial_table[2]; -static struct termios *serial_termios[2]; -static struct termios *serial_termios_locked[2]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -188,7 +195,7 @@ static inline int get_baud(struct m68k_serial *ss) { unsigned long result = 115200; - unsigned short int baud = UBAUD; + unsigned short int baud = uart_addr[ss->line].ubaud; if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400; result >>= GET_FIELD(baud, UBAUD_DIVIDE); @@ -206,13 +213,14 @@ static void rs_stop(struct tty_struct *tty) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_stop")) return; save_flags(flags); cli(); - USTCNT &= ~USTCNT_TXEN; + uart->ustcnt &= ~USTCNT_TXEN; restore_flags(flags); } @@ -235,17 +243,18 @@ static void rs_start(struct tty_struct *tty) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_start")) return; save_flags(flags); cli(); - if (info->xmit_cnt && info->xmit_buf && !(USTCNT & USTCNT_TXEN)) { + if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { #ifdef USE_INTS - USTCNT |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; + uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; #else - USTCNT |= USTCNT_TXEN; + uart->ustcnt |= USTCNT_TXEN; #endif } restore_flags(flags); @@ -301,6 +310,7 @@ static _INLINE_ void receive_chars(struct m68k_serial *info, struct pt_regs *regs, unsigned short rx) { struct tty_struct *tty = info->tty; + m68328_uart *uart = &uart_addr[info->line]; unsigned char ch; /* @@ -360,7 +368,7 @@ tty->flip.count++; #ifndef CONFIG_XCOPILOT_BUGS - } while((rx = URX) & URX_DATA_READY); + } while((rx = uart->urx.w) & URX_DATA_READY); #endif queue_task(&tty->flip.tqueue, &tq_timer); @@ -371,21 +379,23 @@ static _INLINE_ void transmit_chars(struct m68k_serial *info) { + m68328_uart *uart = &uart_addr[info->line]; + if (info->x_char) { /* Send next char */ - UTX_TXDATA = info->x_char; + uart->utx.b.txdata = info->x_char; info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... TX ints off */ - USTCNT &= ~USTCNT_TX_INTR_MASK; + uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; } /* Send char */ - UTX_TXDATA = info->xmit_buf[info->xmit_tail++]; + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; @@ -394,7 +404,7 @@ if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ - USTCNT &= ~USTCNT_TX_INTR_MASK; + uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; } @@ -408,10 +418,20 @@ */ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct m68k_serial * info = &m68k_soft; - unsigned short rx = URX; + struct m68k_serial * info; + m68328_uart *uart; + unsigned short rx; + unsigned short tx; + + info = IRQ_ports[irq]; + if(!info) + return; + + uart = &uart_addr[info->line]; + rx = uart->urx.w; + #ifdef USE_INTS - unsigned short tx = UTX; + tx = uart->utx.w; if (rx & URX_DATA_READY) receive_chars(info, regs, rx); if (tx & UTX_TX_AVAIL) transmit_chars(info); @@ -477,6 +497,7 @@ static int startup(struct m68k_serial * info) { + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (info->flags & S_INITIALIZED) @@ -495,19 +516,19 @@ * (they will be reenabled in change_speed()) */ - USTCNT = USTCNT_UEN; + uart->ustcnt = USTCNT_UEN; info->xmit_fifo_size = 1; - USTCNT = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; - (void)URX; + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; + (void)uart->urx.w; /* * Finally, enable sequencing and interrupts */ #ifdef USE_INTS - USTCNT = USTCNT_UEN | USTCNT_RXEN | + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK; #else - USTCNT = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif if (info->tty) @@ -531,9 +552,10 @@ */ static void shutdown(struct m68k_serial * info) { + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - USTCNT = 0; /* All off! */ + uart->ustcnt = 0; /* All off! */ if (!(info->flags & S_INITIALIZED)) return; @@ -605,6 +627,7 @@ */ static void change_speed(struct m68k_serial *info) { + m68328_uart *uart = &uart_addr[info->line]; unsigned short port; unsigned short ustcnt; unsigned cflag; @@ -616,8 +639,8 @@ if (!(port = info->port)) return; - ustcnt = USTCNT; - USTCNT = ustcnt & ~USTCNT_TXEN; + ustcnt = uart->ustcnt; + uart->ustcnt = ustcnt & ~USTCNT_TXEN; i = cflag & CBAUD; if (i & CBAUDEX) { @@ -625,7 +648,7 @@ } info->baud = baud_table[i]; - UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | + uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); @@ -643,15 +666,15 @@ #ifdef CONFIG_68328_SERIAL_RTS_CTS if (cflag & CRTSCTS) { - UTX &= ~ UTX_NOCTS; + uart->utx.w &= ~ UTX_NOCTS; } else { - UTX |= UTX_NOCTS; + uart->utx.w |= UTX_NOCTS; } #endif ustcnt |= USTCNT_TXEN; - USTCNT = ustcnt; + uart->ustcnt = ustcnt; return; } @@ -662,7 +685,7 @@ { int left; /* Output no more than that */ unsigned long flags; - struct m68k_serial *info = &m68k_soft; + struct m68k_serial *info = &m68k_soft[0]; char c; if (info == 0) return; @@ -723,6 +746,7 @@ static void rs_flush_chars(struct tty_struct *tty) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) @@ -738,24 +762,24 @@ save_flags(flags); cli(); #ifdef USE_INTS - USTCNT |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; + uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; #else - USTCNT |= USTCNT_TXEN; + uart->ustcnt |= USTCNT_TXEN; #endif #ifdef USE_INTS - if (UTX & UTX_TX_AVAIL) { + if (uart->utx.w & UTX_TX_AVAIL) { #else if (1) { #endif /* Send char */ - UTX_TXDATA = info->xmit_buf[info->xmit_tail++]; + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; } #ifndef USE_INTS - while (!(UTX & UTX_TX_AVAIL)) udelay(5); + while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); } #endif restore_flags(flags); @@ -768,6 +792,7 @@ { int c, total = 0; struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (serial_paranoia_check(info, tty->device, "rs_write")) @@ -808,14 +833,14 @@ while(info->xmit_cnt) { #endif - USTCNT |= USTCNT_TXEN; + uart->ustcnt |= USTCNT_TXEN; #ifdef USE_INTS - USTCNT |= USTCNT_TX_INTR_MASK; + uart->ustcnt |= USTCNT_TX_INTR_MASK; #else - while (!(UTX & UTX_TX_AVAIL)) udelay(5); + while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); #endif - if (UTX & UTX_TX_AVAIL) { - UTX_TXDATA = info->xmit_buf[info->xmit_tail++]; + if (uart->utx.w & UTX_TX_AVAIL) { + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; } @@ -988,11 +1013,14 @@ */ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) { +#ifdef CONFIG_68328_SERIAL_RTS_CTS + m68328_uart *uart = &uart_addr[info->line]; +#endif unsigned char status; cli(); #ifdef CONFIG_68328_SERIAL_RTS_CTS - status = (UTX & UTX_CTS_STAT) ? 1 : 0; + status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; #else status = 0; #endif @@ -1006,6 +1034,7 @@ */ static void send_break( struct m68k_serial * info, int duration) { + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (!info->port) return; @@ -1013,9 +1042,9 @@ save_flags(flags); cli(); #ifdef USE_INTS - UTX |= UTX_SEND_BREAK; + uart->utx.w |= UTX_SEND_BREAK; schedule_timeout(duration); - UTX &= ~UTX_SEND_BREAK; + uart->utx.w &= ~UTX_SEND_BREAK; #endif restore_flags(flags); } @@ -1129,6 +1158,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) { struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (!info || serial_paranoia_check(info, tty->device, "rs_close")) @@ -1185,8 +1215,8 @@ * line status register. */ - USTCNT &= ~USTCNT_RXEN; - USTCNT &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); + uart->ustcnt &= ~USTCNT_RXEN; + uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); shutdown(info); if (tty->driver.flush_buffer) @@ -1367,10 +1397,10 @@ line = MINOR(tty->device) - tty->driver.minor_start; - if (line != 0) /* we have exactly one */ + if (line >= NR_PORTS || line < 0) /* we have exactly one */ return -ENODEV; - info = &m68k_soft; + info = &m68k_soft[line]; if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; @@ -1418,7 +1448,7 @@ static int __init rs68328_init(void) { - int flags; + int flags, i; struct m68k_serial *info; /* Setup base handler, and timer table. */ @@ -1433,7 +1463,7 @@ serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; - serial_driver.num = 1; + serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; @@ -1477,38 +1507,43 @@ save_flags(flags); cli(); - info = &m68k_soft; - info->magic = SERIAL_MAGIC; - info->port = 0xfffff900; - info->tty = 0; - info->irq = 0x40; - info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - info->tqueue_hangup.routine = do_serial_hangup; - info->tqueue_hangup.data = info; - info->callout_termios =callout_driver.init_termios; - info->normal_termios = serial_driver.init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->line = 0; - info->is_cons = 1; /* Means shortcuts work */ - - printk("%s%d at 0x%08x (irq = %d)", serial_driver.name, info->line, - info->port, info->irq); - printk(" is a builtin MC68328 UART\n"); - - if (request_irq(UART_IRQ_NUM, - rs_interrupt, - IRQ_FLG_STD, - "M68328_UART", NULL)) + for(i=0;imagic = SERIAL_MAGIC; + info->port = &uart_addr[i]; + info->tty = 0; + info->irq = uart_irqs[i]; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; + info->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->line = i; + info->is_cons = 1; /* Means shortcuts work */ + + printk("%s%d at 0x%08x (irq = %d)", serial_driver.name, info->line, + info->port, info->irq); + printk(" is a builtin MC68328 UART\n"); + + IRQ_ports[info->irq] = info; /* waste of space */ + + if (request_irq(uart_irqs[i], + rs_interrupt, + IRQ_FLG_STD, + "M68328_UART", NULL)) panic("Unable to attach 68328 serial interrupt\n"); + } restore_flags(flags); return 0; } diff -Naur linux-2.4.x.orig/drivers/char/68328serial.h linux-2.4.x/drivers/char/68328serial.h --- linux-2.4.x.orig/drivers/char/68328serial.h Thu Oct 4 11:16:04 2001 +++ linux-2.4.x/drivers/char/68328serial.h Thu Oct 4 11:08:03 2001 @@ -183,5 +183,16 @@ */ #define RS_EVENT_WRITE_WAKEUP 0 +/* + * Define the number of ports supported and their irqs. + */ +#ifndef CONFIG_68328_SERIAL_UART2 +#define NR_PORTS 1 +#define UART_IRQ_DEFNS {UART_IRQ_NUM} +#else +#define NR_PORTS 2 +#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM} +#endif + #endif /* __KERNEL__ */ #endif /* !(_MC683XX_SERIAL_H) */ diff -Naur linux-2.4.x.orig/drivers/char/Config.in linux-2.4.x/drivers/char/Config.in --- linux-2.4.x.orig/drivers/char/Config.in Thu Oct 4 11:16:04 2001 +++ linux-2.4.x/drivers/char/Config.in Thu Oct 4 05:49:40 2001 @@ -32,6 +32,9 @@ #(es) if [ "$CONFIG_M68VZ328" = "y" ]; then bool '68328 serial support' CONFIG_68328_SERIAL + if [ "$CONFIG_68328_SERIAL" = "y" ]; then + bool 'Enable second 68328 serial support' CONFIG_68328_SERIAL_UART2 + fi fi #(/es) --- linux-2.4.x.orig/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S Tue Sep 25 07:26:00 2001 +++ linux-2.4.x/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S Thu Oct 4 09:20:38 2001 @@ -80,6 +80,11 @@ movel %d0, _ramend movel #__ramvec, %d0 movel %d0, _ramvec + +#ifdef CONFIG_68328_SERIAL_UART2 + /* Enable RXD TXD port bits to enable UART2 */ + moveb #0xcf, 0xfffff43b +#endif /* * load the current task pointer and stack diff -Naur linux-2.4.x.orig/include/asm-m68knommu/MC68328.h linux-2.4.x/include/asm-m68knommu/MC68328.h --- linux-2.4.x.orig/include/asm-m68knommu/MC68328.h Thu Oct 4 11:16:46 2001 +++ linux-2.4.x/include/asm-m68knommu/MC68328.h Thu Oct 4 10:28:36 2001 @@ -970,6 +970,33 @@ #define UMISC_FORCE_PERR 0x2000 /* Force Parity Error */ #define UMISC_CLKSRC 0x4000 /* Clock Source */ + +/* generalization of uart control registers to support multiple ports: */ +typedef struct { + volatile unsigned short int ustcnt __attribute__((packed)); + volatile unsigned short int ubaud __attribute__((packed)); + union { + volatile unsigned short int w __attribute__((packed)); + struct { + volatile unsigned char status __attribute__((packed)); + volatile unsigned char rxdata __attribute__((packed)); + } b; + } urx; + union { + volatile unsigned short int w __attribute__((packed)); + struct { + volatile unsigned char status __attribute__((packed)); + volatile unsigned char txdata __attribute__((packed)); + } b; + } utx; + volatile unsigned short int umisc __attribute__((packed)); + volatile unsigned short int pad1 __attribute__((packed)); + volatile unsigned short int pad2 __attribute__((packed)); + volatile unsigned short int pad3 __attribute__((packed)); +} m68328_uart; + + + /********** * * 0xFFFFFAxx -- LCD Controller diff -Naur linux-2.4.x.orig/include/asm-m68knommu/MC68EZ328.h linux-2.4.x/include/asm-m68knommu/MC68EZ328.h --- linux-2.4.x.orig/include/asm-m68knommu/MC68EZ328.h Thu Oct 4 11:16:46 2001 +++ linux-2.4.x/include/asm-m68knommu/MC68EZ328.h Thu Oct 4 10:43:25 2001 @@ -791,6 +791,32 @@ #define NIPR_SELECT_SHIFT 8 #define NIPR_PRE_SEL 0x8000 /* Non-integer prescaler select */ + +/* generalization of uart control registers to support multiple ports: */ +typedef struct { + volatile unsigned short int ustcnt __attribute__((packed)); + volatile unsigned short int ubaud __attribute__((packed)); + union { + volatile unsigned short int w __attribute__((packed)); + struct { + volatile unsigned char status __attribute__((packed)); + volatile unsigned char rxdata __attribute__((packed)); + } b; + } urx; + union { + volatile unsigned short int w __attribute__((packed)); + struct { + volatile unsigned char status __attribute__((packed)); + volatile unsigned char txdata __attribute__((packed)); + } b; + } utx; + volatile unsigned short int umisc __attribute__((packed)); + volatile unsigned short int nipr __attribute__((packed)); + volatile unsigned short int pad1 __attribute__((packed)); + volatile unsigned short int pad2 __attribute__((packed)); +} m68328_uart; + + /********** * * 0xFFFFFAxx -- LCD Controller diff -Naur linux-2.4.x.orig/include/asm-m68knommu/MC68VZ328.h linux-2.4.x/include/asm-m68knommu/MC68VZ328.h --- linux-2.4.x.orig/include/asm-m68knommu/MC68VZ328.h Thu Oct 4 11:16:46 2001 +++ linux-2.4.x/include/asm-m68knommu/MC68VZ328.h Thu Oct 4 10:26:03 2001 @@ -822,6 +822,8 @@ } utx; volatile unsigned short int umisc __attribute__((packed)); volatile unsigned short int nipr __attribute__((packed)); + volatile unsigned short int hmark __attribute__((packed)); + volatile unsigned short int unused __attribute__((packed)); } m68328_uart;