New version of AMD Elan patch

From: Robert Schwebel (robert@schwebel.de)
Date: Mon Jan 21 2002 - 02:28:00 EST


Hi Marcelo and Alan,

Here's a new version of the AMD Elan patch, against 2.4.18-pre4. Please
apply.

Description:

The following patch for linux-2.4.18-pre3 fixes problems with the AMD Elan
CPUs which are popular x86 devices for embedded applications.

Content of the patch:
---------------------

        1. add a new processor type "Elan" in "Processor type
           and features", with CONFIG_MELAN, is introduced

        2. fix the A20 code which was broken since the cleanup
           in 2.4.15

        3. correct the ioport resource registration for Elans
           (standard kernel reserves ports which are special
           function registers on Elans)

        4. fix UART transmit bug

        5. fix timer 0 frequency to correct the clock

Details:
--------

1. As discussed on LKML the Elan processors have some
   "features" which need to be fixed but should not live
   in a standard kernel. Therefore, we propose a new
   configuration option CONFIG_MELAN. Ideas for better
   places for this option in the configuration tree are
   welcome.

2. In 2.4.15 H. Peter Anvin ported the A20 gate code from
   syslinux to the kernel, which is much more sophisticated
   than the code we had before. This leads to the Elan
   processors not booting any more (they did before without
   any problem, but that was more luck than intention). If
   you try to boot kernels newer than 2.4.14 the system
   reboots right in the middle of the initialisation
   sequence. As the Elans don't have a keyboard controller
   a special A20 gate sequence is added according to the
   config option introduced in 1.

3. Due to the fact that the ports of the PIC of the original
   PC are mirrored to several adresses Linux normally reserves
   the areas 0x20..0x3f and 0xa0..0xbf for pic1 and pic2,
   although the PICs use only the first two adresses of each
   block. This part of the patch uses only the "real" adresses,
   (0x20,0x21 / 0xa0,0xa1) as the Elan processors have special
   function registers in these blocks for the integrated
   peripherals.

4. The on-chip serial interface has a bug: the UART_LSR_THRE
   bit is delayed one bit clock after the interrupt line is
   asserted, i.e. if the serial port is running at 1200 bps, and
   the tranmitter becomes empty and causes an interupt, the
   interrupt is signalled about a millisecond (1/1200second)
   _before_ the THRE bit is set. This means that when the
   interrupt handler is entered after the interrupt, the THRE
   bit is still clear, the handler believes that there is
   nothing to be done and returns.

5. A normal PC has a basic frequency for the system timer 0
   of 1.19318 MHz, whereas the Elans have 1.1892 MHz due to the
   fact that all clocks are derived from a single oscillator.
   Without the patch the clock is wrong.

Credits:
--------

- Anders Larsen <anders@alarsen.net>
  First attempt of a patch for the Elan series
  http://www.uwsg.iu.edu/hypermail/linux/kernel/0004.2/0667.html

- Jason Sodergren <jason@mugwump.taiga.com>
  Clock patch

- Christer Weinigel <wingel@hog.ctrl-c.liu.se>
  Serial interface patch, A20 patch

- H. Peter Anvin <hpa@zytor.com>
  Discussions and ideas about the A20 stuff

- Juergen Beisert <jbeisert@eurodsn.de>
  Tests on SC520, suggestions for boot sequence changes, RS232

Patch:
------

The latest version of this patch can always be found on

  http://www.pengutronix.de/software/elan_en.html

The following code is version 2.4.18-pre4.1 of the patch. Suggestions for
further improvement are welcome.

----------8<----------8<----------8<----------8<----------8<----------
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/CREDITS linux-2.4.18-pre4-elan/CREDITS
--- linux-2.4.18-pre4/CREDITS Sun Jan 20 20:39:06 2002
+++ linux-2.4.18-pre4-elan/CREDITS Sun Jan 20 21:35:37 2002
@@ -2659,6 +2659,16 @@
 S: Oldenburg
 S: Germany

+N: Robert Schwebel
+E: robert@schwebel.de
+W: http://www.schwebel.de
+D: Embedded hacker and book author,
+D: AMD Elan support for Linux
+S: Pengutronix
+S: Braunschweiger Strasse 79
+S: 31134 Hildesheim
+S: Germany
+
 N: Darren Senn
 E: sinster@darkwater.com
 D: Whatever I notice needs doing (so far: itimers, /proc)
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/Documentation/Configure.help linux-2.4.18-pre4-elan/Documentation/Configure.help
--- linux-2.4.18-pre4/Documentation/Configure.help Sun Jan 20 20:39:06 2002
+++ linux-2.4.18-pre4-elan/Documentation/Configure.help Sun Jan 20 21:35:38 2002
@@ -3813,6 +3813,7 @@
    - "Pentium-4" for the Intel Pentium 4.
    - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
    - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
+ - "Elan" for the AMD Elan family (Elan SC400/SC410).
    - "Crusoe" for the Transmeta Crusoe series.
    - "Winchip-C6" for original IDT Winchip.
    - "Winchip-2" for IDT Winchip 2.
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/arch/i386/boot/setup.S linux-2.4.18-pre4-elan/arch/i386/boot/setup.S
--- linux-2.4.18-pre4/arch/i386/boot/setup.S Sun Jan 20 20:39:07 2002
+++ linux-2.4.18-pre4-elan/arch/i386/boot/setup.S Mon Jan 21 07:44:20 2002
@@ -42,6 +42,9 @@
  * if CX/DX have been changed in the e801 call and if so use AX/BX .
  * Michael Miller, April 2001 <michaelm@mjmm.org>
  *
+ * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
+ * by Robert Schwebel, December 2001 <robert@schwebel.de>
+ *
  */

 #include <linux/config.h>
@@ -651,7 +654,18 @@
 #
 # Enable A20. This is at the very best an annoying procedure.
 # A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
+# AMD Elan bug fix by Robert Schwebel.
 #
+
+#if defined(CONFIG_MELAN)
+ movb $0x02, %al # alternate A20 gate
+ outb %al, $0x92 # this works on SC410/SC520
+a20_elan_wait:
+ call a20_test
+ jz a20_elan_wait
+ jmp a20_done
+#endif
+

 A20_TEST_LOOPS = 32 # Iterations per wait
 A20_ENABLE_LOOPS = 255 # Total loops to try
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/arch/i386/config.in linux-2.4.18-pre4-elan/arch/i386/config.in
--- linux-2.4.18-pre4/arch/i386/config.in Fri Dec 21 18:41:53 2001
+++ linux-2.4.18-pre4-elan/arch/i386/config.in Sun Jan 20 21:35:38 2002
@@ -37,6 +37,7 @@
          Pentium-4 CONFIG_MPENTIUM4 \
          K6/K6-II/K6-III CONFIG_MK6 \
          Athlon/Duron/K7 CONFIG_MK7 \
+ Elan CONFIG_MELAN \
          Crusoe CONFIG_MCRUSOE \
          Winchip-C6 CONFIG_MWINCHIPC6 \
          Winchip-2 CONFIG_MWINCHIP2 \
@@ -125,6 +126,11 @@
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+fi
+if [ "$CONFIG_MELAN" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 4
+ define_bool CONFIG_X86_USE_STRING_486 y
+ define_bool CONFIG_X86_ALIGNMENT_16 y
 fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int CONFIG_X86_L1_CACHE_SHIFT 5
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/arch/i386/kernel/setup.c linux-2.4.18-pre4-elan/arch/i386/kernel/setup.c
--- linux-2.4.18-pre4/arch/i386/kernel/setup.c Sun Jan 20 20:39:07 2002
+++ linux-2.4.18-pre4-elan/arch/i386/kernel/setup.c Sun Jan 20 21:35:38 2002
@@ -329,6 +329,10 @@
         { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
         { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
 };
+#ifdef CONFIG_ELAN
+standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
+standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
+#endif

 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))

diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/drivers/char/serial.c linux-2.4.18-pre4-elan/drivers/char/serial.c
--- linux-2.4.18-pre4/drivers/char/serial.c Sun Jan 20 20:39:13 2002
+++ linux-2.4.18-pre4-elan/drivers/char/serial.c Sun Jan 20 21:35:38 2002
@@ -57,6 +57,9 @@
  * 10/00: add in optional software flow control for serial console.
  * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
  *
+ * 12/01: Fix for AMD Elan bug in transmit irq routine, by
+ * Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
+ * Robert Schwebel <robert@schwebel.de>
  */

 static char *serial_version = "5.05c";
@@ -853,7 +856,7 @@
                 if (!info) {
                         info = IRQ_ports[irq];
                         if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
+#ifdef SERIAL_DEBUG_INTR
                                 printk("rs loop break\n");
 #endif
                                 break; /* Prevent infinite loops */
@@ -886,6 +889,9 @@
         int first_multi = 0;
         struct rs_multiport_struct *multi;
 #endif
+#ifdef CONFIG_MELAN
+ int iir;
+#endif

 #ifdef SERIAL_DEBUG_INTR
         printk("rs_interrupt_single(%d)...", irq);
@@ -900,7 +906,9 @@
         if (multi->port_monitor)
                 first_multi = inb(multi->port_monitor);
 #endif
-
+#ifdef CONFIG_MELAN
+ iir = serial_in(info, UART_IIR);
+#endif
         do {
                 status = serial_inp(info, UART_LSR);
 #ifdef SERIAL_DEBUG_INTR
@@ -909,10 +917,24 @@
                 if (status & UART_LSR_DR)
                         receive_chars(info, &status, regs);
                 check_modem_status(info);
+
+#ifdef CONFIG_M_ELAN
+ /*
+ * There is a bug in the UART on the AMD Elan SC4x0
+ * 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 (status & UART_LSR_THRE || (iir & UART_IIR_ID) == UART_IIR_THRI)
+ transmit_chars(info, 0);
+#else
                 if (status & UART_LSR_THRE)
                         transmit_chars(info, 0);
+#endif
                 if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
+#ifdef SERIAL_DEBUG_INTR
                         printk("rs_single loop break.\n");
 #endif
                         break;
diff -urN -X kernel-patches/dontdiff linux-2.4.18-pre4/include/asm-i386/timex.h linux-2.4.18-pre4-elan/include/asm-i386/timex.h
--- linux-2.4.18-pre4/include/asm-i386/timex.h Thu Nov 22 20:46:18 2001
+++ linux-2.4.18-pre4-elan/include/asm-i386/timex.h Sun Jan 20 21:41:35 2002
@@ -9,7 +9,12 @@
 #include <linux/config.h>
 #include <asm/msr.h>

-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#ifdef CONFIG_MELAN
+# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
+#else
+# define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#endif
+
 #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
         (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
----------8<----------8<----------8<----------8<----------8<----------

Robert

--
 +--------------------------------------------------------+
 | Dipl.-Ing. Robert Schwebel | http://www.pengutronix.de |
 | Pengutronix - Linux Solutions for Science and Industry |
 |   Braunschweiger Str. 79,  31134 Hildesheim, Germany   |
 |    Phone: +49-5121-28619-0 |  Fax: +49-5121-28619-4    |
 +--------------------------------------------------------+

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Jan 23 2002 - 21:00:43 EST