Messages in this thread | | | From | Robert Kaiser <> | Subject | Re: Kernel booting on serial console ... crawling | Date | Fri, 9 Nov 2001 17:18:16 +0100 |
| |
Hi Robert,
Am Freitag, 9. November 2001 13:27 schrieben Sie: > On Fri, 9 Nov 2001, Robert Kaiser wrote: > > Is this an AMD Elan's built-in serial port, perchance ? > > I got a patch for the Elan's serial port from Jason Sodergren some days > ago, but it's not clear to me what exactly the problem is with this port. > I'm using the serial console on a DIL/Net-PC without any problems so far. > Perhaps it might be a good idea to join forces and try to get a patch for > the Elan series into the main kernel? > > However, my current affords can be found on > > http://www.schwebel.de/software/dnp/index_en.html > > This currently implements a new CPU configuration parameter and a fix for > the clock on the Elan CPUs.
This is interesting, I was not aware of the different clock frequency issue.
Anyway, the patch I am using to fix the crawling console output symptom on the Elan is entirely different (see attachment). It was originally posted by Anders Larsen <a.larsen@identecsolutions.de> and we have been using it with good success in our embedded Linux product for quite a while now. The comments in the source describe the problem. Interestingly, even the latest AMD Elan product (SC520) seems to have this problem too.
Rob
---------------------------------------------------------------- Robert Kaiser email: rkaiser@sysgo.de SYSGO RTS GmbH Am Pfaffenstein 14 phone: (49) 6136 9948-762 D-55270 Klein-Winternheim / Germany fax: (49) 6136 9948-10 Index: sysgo/elinos/linux/drivers/char/serial.c diff -c sysgo/elinos/linux/drivers/char/serial.c:1.2 sysgo/elinos/linux/drivers/char/serial.c:1.3 *** sysgo/elinos/linux/drivers/char/serial.c:1.2 Wed May 17 14:07:00 2000 --- sysgo/elinos/linux/drivers/char/serial.c Wed Jun 7 15:19:53 2000 *************** *** 607,612 **** --- 607,613 ---- int status; struct async_struct * info; int pass_counter = 0; + int iir; struct async_struct *end_mark = 0; #ifdef CONFIG_SERIAL_MULTIPORT int first_multi = 0; *************** *** 627,635 **** first_multi = inb(multi->port_monitor); #endif do { if (!info->tty || ! (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; --- 628,637 ---- first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { if (!info->tty || ! ((iir = serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; *************** *** 645,650 **** --- 647,663 ---- if (status & UART_LSR_DR) receive_chars(info, &status); check_modem_status(info); + #ifdef CONFIG_AMD_ELAN + /* + ** There is a bug (misfeature?) in the UART on the AMD Elan + ** SC4x0 and SC520 embedded processor series; the THRE bit of + ** the line status register seems to be delayed one bit + ** clock after the interrupt is generated, so kludge this + ** if the IIR indicates a Transmit Holding Register Interrupt + */ + if ((iir & UART_IIR_ID) == UART_IIR_THRI) + status |= UART_LSR_THRE; + #endif if (status & UART_LSR_THRE) transmit_chars(info, 0); *************** *** 679,685 **** */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { ! int status; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT --- 692,698 ---- */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { ! int status, iir; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT *************** *** 701,706 **** --- 714,720 ---- first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR *************** *** 709,714 **** --- 723,739 ---- if (status & UART_LSR_DR) receive_chars(info, &status); check_modem_status(info); + #ifdef CONFIG_AMD_ELAN + /* + ** There is a bug (misfeature?) in the UART on the AMD Elan + ** SC4x0 and SC520 embedded processor series; the THRE bit of + ** the line status register seems to be delayed one bit + ** clock after the interrupt is generated, so kludge this + ** if the IIR indicates a Transmit Holding Register Interrupt + */ + if ((iir & UART_IIR_ID) == UART_IIR_THRI) + status |= UART_LSR_THRE; + #endif if (status & UART_LSR_THRE) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { *************** *** 717,723 **** #endif break; } ! } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor) --- 742,748 ---- #endif break; } ! } while (!((iir = serial_in(info, UART_IIR)) & UART_IIR_NO_INT)); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor)
| |