[patch] HWUART instead of BTUART on the h5550 (workaround for Bluetooth UART overruns)

From: Catalin Drula <Catalin.Drula_at_imag.fr>
Date: Wed, 9 Mar 2005 16:12:32 +0100 (CET)

Hi,

Following Will Spruce's observation that Windows CE on the h5550 uses the
HWUART (and not the BTUART) for communicating to the Bluetooth module,
I wrote a patch to do the same on Linux. After initial testing it appears
that the automatic flow control feature of the HWUART makes the overruns
problem go away.

Note that this patch involves an irq renumbering (all the irq numbers get
shifted up by two units) so that the modules that handle irqs need to be
recompiled/reinstalled. The HWUART will be at irq 1.

There is a variable CONFIG_PXA_HWUART, accessible through "make
menuconfig" in

System Type --->
Intel PXA250/210 Implementations --->
[X] PXA255 HWUART support (for Bluetooth on HP iPAQ H5550)

If the variable is disabled then the BTUART is used (and the old irq
numbering is kept); if it is enabled (and assuming the processor
is a PXA 255) HWUART is used.

In addition to the changes strictly related to the HWUART, I have also
backported some of the changes made in 2.14.19-rmk7-pxa2 to the irq code
and the entry code in arch/arm/kernel/entry-*.S. These were necessary to
remove some bugs (for example, some irq numbers were hardcoded instead of
being relative to PXA_IRQ_SKIP as they should have been).

Note this one change that might not be desirable: registering the
timer interrupt handler as a fast interrupt handler (called with irqs
disabled). This was backported from the 2.4.19-rmk7-pxa2 code. If you
think it's harmful you can remove it from the attached patch.

I did some testing with Bluetooth while using the HWUART and there are no
more overruns. If you remember my last post, I was noticing there that
there seemed to be some kind of interaction between the wlan irqs and the
BT irqs, such that overruns occured in particular when the wlan was up
(they occured usually after a few seconds of testing).

I ran a test where I was transfering data in both ways over Bluetooth
(L2CAP) while at the same time doing disk I/O and wlan traffic and there
were no overruns. During the wlan transfer the Bluetooth transfers slowed
down (by quite a bit), but all the data arrived uncorrupted.

For the sake of completeness, I also tested the HWUART with the hardware
autoflow control disabled, and overruns occur, same as on the BTUART. So
it is this automatic flow control feature that solves the problem.

My patch keeps the HWUART on /dev/tts/1 (same as BTUART was) so that
scripts and programs that rely on this do not break (I am thinking about
gpe-bluetooth, for example). It might be advisable to run hciattach with
the noflow paramater though, (not sure if it makes a difference, but it's
safer to use it) as:

hciattach /dev/tts/1 any 921600 noflow

If there is anyone who wants to grab a tar archive of the ipk packages
containing the (compiled) kernel and modules with this patch, they can
download it from:

http://www-lsr.imag.fr/Les.Personnes/Catalin.Drula/bluetooth.html

Catalin

diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/config.in linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/config.in
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/config.in 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/config.in 2005-03-09 13:38:54.152635889 +0100
@@ -186,6 +186,8 @@
 dep_tristate ' Support for PXA USB network link function' CONFIG_PXA_USB_NETLINK $CONFIG_PXA_USB
 dep_tristate ' Support for PXA USB character device emulation' CONFIG_PXA_USB_CHAR $CONFIG_PXA_USB

+dep_bool ' PXA255 HWUART support (for Bluetooth on HP iPAQ H5550)' CONFIG_PXA_HWUART $CONFIG_ARCH_PXA
+
 endmenu

 mainmenu_option next_comment
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-armv.S linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-armv.S
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-armv.S 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-armv.S 2005-03-09 13:38:54.072644414 +0100
@@ -629,7 +629,7 @@
                 rsb \irqnr, \irqstat, #0
                 and \irqstat, \irqstat, \irqnr
                 clz \irqnr, \irqstat
- rsb \irqnr, \irqnr, #23
+ rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
 1001:
                 .endm

@@ -894,8 +894,9 @@
  * This is the return code to user mode for abort handlers
  */
 ENTRY(ret_from_exception)
- get_current_task tsk
+ disable_irq r1
                 mov why, #0
+ get_current_task tsk
                 b ret_to_user

                 .data
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-common.S linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-common.S
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-common.S 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-common.S 2005-03-09 13:38:54.077643881 +0100
@@ -34,6 +34,7 @@
  * stack.
  */
 ret_fast_syscall:
+ disable_irq r1 @ ensure IRQs are disabled
         ldr r1, [tsk, #TSK_NEED_RESCHED]
         ldr r2, [tsk, #TSK_SIGPENDING]
         teq r1, #0 @ need_resched || sigpending
@@ -45,28 +46,35 @@
  * Ok, we need to do extra processing, enter the slow path.
  */
 slow: str r0, [sp, #S_R0+S_OFF]! @ returned r0
- b 1f
+ teq r1, #0
+ beq 1f

 /*
  * "slow" syscall return path. "why" tells us if this was a real syscall.
  */
 reschedule:
         bl SYMBOL_NAME(schedule)
+ret_disable_irq:
+ disable_irq r1 @ ensure IRQs are disabled
 ENTRY(ret_to_user)
 ret_slow_syscall:
         ldr r1, [tsk, #TSK_NEED_RESCHED]
         ldr r2, [tsk, #TSK_SIGPENDING]
-1: teq r1, #0 @ need_resched => schedule()
+ teq r1, #0 @ need_resched => schedule()
         bne reschedule
- teq r2, #0 @ sigpending => do_signal()
- blne __do_signal
+1: teq r2, #0 @ sigpending => do_signal()
+ bne __do_signal
+restore:
         restore_user_regs

 __do_signal:
+ enable_irq r1
         mov r0, #0 @ NULL 'oldset'
         mov r1, sp @ 'regs'
         mov r2, why @ 'syscall'
- b SYMBOL_NAME(do_signal) @ note the bl above sets lr
+ bl SYMBOL_NAME(do_signal) @ note the bl above sets lr
+ disable_irq r1 @ ensure IRQs are disabled
+ b restore

 /*
  * This is how we return from a fork. __switch_to will be calling us
@@ -79,11 +87,11 @@
         ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing
         mov why, #1
         tst ip, #PT_TRACESYS @ are we tracing syscalls?
- beq ret_slow_syscall
+ beq ret_disable_irq
         mov r1, sp
         mov r0, #1 @ trace exit [IP = 1]
         bl SYMBOL_NAME(syscall_trace)
- b ret_slow_syscall
+ b ret_disable_irq

 #include "calls.S"
@@ -130,7 +138,7 @@
         ldr ip, [ip]
         mcr p15, 0, ip, c1, c0 @ update control register
 #endif
- enable_irqs ip
+ enable_irq ip

         str r4, [sp, #-S_OFF]! @ push fifth arg

@@ -174,7 +182,7 @@
         mov r1, sp
         mov r0, #1 @ trace exit [IP = 1]
         bl SYMBOL_NAME(syscall_trace)
- b ret_slow_syscall
+ b ret_disable_irq

         .align 5
 #ifdef CONFIG_ALIGNMENT_TRAP
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-header.S linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-header.S
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/entry-header.S 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/entry-header.S 2005-03-09 13:38:54.078643774 +0100
@@ -41,14 +41,14 @@
 @
 @ Stack format (ensured by USER_* and SVC_*)
 @
-#define S_FRAME_SIZE 72
 #ifdef CONFIG_CPU_32
+#define S_FRAME_SIZE 72
 #define S_OLD_R0 68
 #define S_PSR 64
 #else
+#define S_FRAME_SIZE 68
 #define S_OLD_R0 64
 #define S_PSR 60
-#define S_PC 60
 #endif

 #define S_PC 60
@@ -70,6 +70,24 @@
 #define S_OFF 8

 #ifdef CONFIG_CPU_32
+ .macro set_cpsr_c, reg, mode
+#if 1
+ /* broken binutils */
+ mov \reg, \mode
+ msr cpsr_c, \reg
+#else
+ msr cpsr_c, \mode
+#endif
+ .endm
+
+ .macro disable_irq, temp
+ set_cpsr_c \temp, #I_BIT | MODE_SVC
+ .endm
+
+ .macro enable_irq, temp
+ set_cpsr_c \temp, #MODE_SVC
+ .endm
+
                 .macro save_user_regs
                 sub sp, sp, #S_FRAME_SIZE
                 stmia sp, {r0 - r12} @ Calling r0 - r12
@@ -81,21 +99,23 @@
                 str r0, [sp, #S_OLD_R0] @ Save OLD_R0
                 .endm

+/*
+ * Must be called with IRQs already disabled.
+ */
                 .macro restore_user_regs
- ldr r0, [sp, #S_PSR] @ Get calling cpsr
- mov ip, #I_BIT | MODE_SVC
- msr cpsr_c, ip @ disable IRQs
- msr spsr, r0 @ save in spsr_svc
- ldr lr, [sp, #S_PC] @ Get PC
- ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
+ ldr r1, [sp, #S_PSR] @ Get calling cpsr
+ ldr lr, [sp, #S_PC]! @ Get PC
+ msr spsr, r1 @ save in spsr_svc
+ ldmdb sp, {r0 - lr}^ @ Get calling r0 - lr
                 mov r0, r0
- add sp, sp, #S_FRAME_SIZE
+ add sp, sp, #S_FRAME_SIZE - S_PC
                 movs pc, lr @ return & move spsr_svc into cpsr
                 .endm

+/*
+ * Must be called with IRQs already disabled.
+ */
                 .macro fast_restore_user_regs
- mov ip, #I_BIT | MODE_SVC
- msr cpsr_c, ip @ disable IRQs
                 ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr
                 ldr lr, [sp, #S_OFF + S_PC]! @ get pc
                  msr spsr, r1 @ save in spsr_svc
@@ -108,11 +128,6 @@
                 .macro mask_pc, rd, rm
                 .endm

- .macro enable_irqs, temp
- mov \temp, #MODE_SVC
- msr cpsr_c, \temp
- .endm
-
                 .macro get_current_task, rd
                 mov \rd, sp, lsr #13
                 mov \rd, \rd, lsl #13
@@ -136,9 +151,9 @@

 #else
                 .macro save_user_regs
- str r0, [sp, #-4]!
- str lr, [sp, #-4]!
- sub sp, sp, #15*4
+ sub sp, sp, #S_FRAME_SIZE
+ str r0, [sp, #S_OLD_R0]
+ str lr, [sp, #S_PC]
                 stmia sp, {r0 - lr}^
                 mov r0, r0
                 .endm
@@ -146,17 +161,16 @@
                 .macro restore_user_regs
                 ldmia sp, {r0 - lr}^
                 mov r0, r0
- ldr lr, [sp, #15*4]
- add sp, sp, #15*4+8
+ ldr lr, [sp, #S_PC]
+ add sp, sp, #S_FRAME_SIZE
                 movs pc, lr
                 .endm

                 .macro fast_restore_user_regs
- add sp, sp, #S_OFF
- ldmib sp, {r1 - lr}^
+ add sp, sp, #S_OFF + S_PC
+ ldmdb sp, {r1 - lr}^
                 mov r0, r0
- ldr lr, [sp, #15*4]
- add sp, sp, #15*4+8
+ ldr lr, [sp], #S_FRAME_SIZE - S_PC
                 movs pc, lr
                 .endm

@@ -164,7 +178,11 @@
                 bic \rd, \rm, #PCMASK
                 .endm

- .macro enable_irqs, temp
+ .macro disable_irq, temp
+ teqp pc, #0x08000003
+ .endm
+
+ .macro enable_irq, temp
                 teqp pc, #0x00000003
                 .endm

diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/irq-arch.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/irq-arch.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/irq-arch.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/irq-arch.c 2005-03-09 13:38:54.073644307 +0100
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
+#include <linux/list.h>
+#include <linux/timer.h>
 #include <linux/init.h>

 #include <asm/hardware.h>
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/irq.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/irq.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/irq.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/irq.c 2005-03-09 13:38:54.075644094 +0100
@@ -28,6 +28,7 @@
 #include <linux/random.h>
 #include <linux/smp.h>
 #include <linux/list.h>
+#include <linux/timer.h>
 #include <linux/init.h>

 #include <asm/irq.h>
@@ -74,9 +75,9 @@

         spin_lock_irqsave(&irq_controller_lock, flags);
         if (!desc->disable_depth++) {
-//#ifndef CONFIG_CPU_SA1100
+ //#ifndef CONFIG_CPU_SA1100
                 desc->mask(irq);
-//#endif
+ //#endif
         }
         spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
@@ -219,7 +220,7 @@
          * we shouldn't process the IRQ. Instead, turn on the
          * hardware masks.
          */
- if ((desc->running && !desc->reentrant) || desc->disable_depth)
+ if (desc->running || desc->disable_depth)
                 goto running;

         /*
@@ -249,10 +250,8 @@
         /*
          * If we are disabled or freed, shut down the handler.
          */
- if (desc->action && desc->disable_depth == 0 && !desc->no_unmask && !check_irq_lock(desc, irq, regs) ) {
+ if (desc->action && !check_irq_lock(desc, irq, regs))
                 desc->unmask(irq);
- }
-
         return;

  running:
@@ -260,7 +259,6 @@
          * We got another IRQ while this one was masked or
          * currently running. Delay it.
          */
- desc->mask(irq);
         desc->pending = 1;
 }

@@ -364,7 +362,7 @@
         int cpu;

 #ifdef CONFIG_ARCH_S3C2410
-eint_again:
+ eint_again:

         if( irq == IRQ_EINT4_7 || EINT4_7flag) {
                 EINT4_7flag = 1;
@@ -373,7 +371,7 @@
                         EINT4_7flag = 0;
                 }
         }
-
+
         if( irq == IRQ_EINT8_23 || EINT8_23flag) {
                 EINT8_23flag = 1;
                 irq = Split_EINT8_23(irq);
@@ -383,6 +381,7 @@
         }
 #endif

+
         desc = irq_desc + irq;

         cpu = smp_processor_id();
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/time.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/time.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/kernel/time.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/kernel/time.c 2005-03-09 13:38:54.072644414 +0100
@@ -203,6 +203,7 @@

 static struct irqaction timer_irq = {
         .name = "timer",
+ .flags = SA_INTERRUPT,
 };

 /*
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/h5400.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/h5400.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/h5400.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/h5400.c 2005-03-09 13:38:54.085643028 +0100
@@ -481,11 +481,17 @@
         GPIO39_FFTXD_MD,
         GPIO40_FFDTR_MD,
         GPIO41_FFRTS_MD,
+#ifdef CONFIG_PXA_HWUART
+ GPIO42_HWRXD_MD,
+ GPIO43_HWTXD_MD,
+ GPIO44_HWCTS_MD,
+ GPIO45_HWRTS_MD,
+#else
         GPIO42_BTRXD_MD,
         GPIO43_BTTXD_MD,
         GPIO44_BTCTS_MD,
         GPIO45_BTRTS_MD,
-
+#endif
         GPIO_NR_H5400_IRDA_SD | GPIO_OUT, /* GPIO58 */
         59 | GPIO_OUT, /* GPIO59 XXX docs say "usb charge on" input */
         GPIO_NR_H5400_POWER_SD_N | GPIO_OUT, /* GPIO60 XXX not really active low? */
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/ipaq.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/ipaq.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/ipaq.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/ipaq.c 2005-03-09 13:38:54.081643455 +0100
@@ -67,7 +67,7 @@
 {
         static int power_state[NR_SERIAL];

- if (line >= NR_SERIAL)
+ if (line > NR_SERIAL)
                 return;

         if (state) {
@@ -78,6 +78,7 @@
                                 set_h3600_egpio(IPAQ_EGPIO_RS232_ON);
                                 break;
                         case 1:
+ case 3:
                                 ipaq_led_blink(BLUE_LED,1,7);
                                 set_h3600_egpio(IPAQ_EGPIO_BLUETOOTH_ON);
                                 break;
@@ -90,6 +91,7 @@
                                 clr_h3600_egpio(IPAQ_EGPIO_RS232_ON);
                                 break;
                         case 1:
+ case 3:
                                 ipaq_led_off(BLUE_LED);
                                 clr_h3600_egpio(IPAQ_EGPIO_BLUETOOTH_ON);
                                 break;
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/irq.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/irq.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/arch/arm/mach-pxa/irq.c 2005-03-08 11:02:26.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/arch/arm/mach-pxa/irq.c 2005-03-09 13:38:54.084643135 +0100
@@ -250,6 +250,14 @@
         /* only unmasked interrupts kick us out of idle */
         ICCR = 1;

+ for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
+ irq_desc[irq].valid = 1;
+ irq_desc[irq].probe_ok = 0;
+ irq_desc[irq].mask_ack = pxa_mask_irq;
+ irq_desc[irq].mask = pxa_mask_irq;
+ irq_desc[irq].unmask = pxa_unmask_irq;
+ }
+
         /*
          * Note: GPIO IRQs are initially invalid until set_GPIO_IRQ_edge()
          * is called at least once.
@@ -263,17 +271,6 @@
                 irq_desc[irq].unmask = pxa_unmask_GPIO_0_1_irq;
         }

- for (irq = IRQ_GPIO_2_80; irq <= IRQ_RTCAlrm; irq++) {
- irq_desc[irq].valid = 1;
- irq_desc[irq].probe_ok = 0;
- irq_desc[irq].mask_ack = pxa_mask_irq;
- irq_desc[irq].mask = pxa_mask_irq;
- irq_desc[irq].unmask = pxa_unmask_irq;
- }
- /* Those are reserved */
- irq_desc[PXA_IRQ(15)].valid = 0;
- irq_desc[PXA_IRQ(16)].valid = 0;
-
         for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) {
                 irq_desc[irq].valid = 0;
                 irq_desc[irq].probe_ok = 1;
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/drivers/char/serial.c linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/drivers/char/serial.c
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/drivers/char/serial.c 2005-03-08 11:02:27.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/drivers/char/serial.c 2005-03-09 13:38:55.000000000 +0100
@@ -1047,7 +1047,7 @@
                     ((iir & UART_IIR_ID) == UART_IIR_THRI))
                         transmit_chars(info, 0);
                 if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if SERIAL_DEBUG_INTR
+#ifdef SERIAL_DEBUG_INTR
                         printk("rs_single loop break.\n");
 #endif
                         break;
@@ -1442,8 +1442,13 @@
         if (state->type == PORT_PXA) {
                 switch ((long)state->iomem_base) {
                         case (long)&FFUART: CKEN |= CKEN6_FFUART; break;
+#ifndef CONFIG_PXA_HWUART
                         case (long)&BTUART: CKEN |= CKEN7_BTUART; break;
+#endif
                         case (long)&STUART: CKEN |= CKEN5_STUART; break;
+#ifdef CONFIG_PXA_HWUART
+ case (long)&HWUART: CKEN |= CKEN4_HWUART; break;
+#endif
                 }
         }
 #endif
@@ -1492,7 +1497,7 @@
         printk(" state->irq = %d\n", state->irq);
         printk(" IRQ_ports[state->irq] = %p\n", IRQ_ports[state->irq]);
 #endif
-
+
         if (state->irq && (!IRQ_ports[state->irq] ||
                           !IRQ_ports[state->irq]->next_port)) {
                 if (IRQ_ports[state->irq]) {
@@ -1555,7 +1560,15 @@
                         info->MCR ^= UART_MCR_OUT2;
         }
         info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
- serial_outp(info, UART_MCR, info->MCR);
+#ifdef CONFIG_PXA_HWUART
+ /* Enable autoflow control for HWUART */
+ if (state->type == PORT_PXA &&
+ (long)state->iomem_base == (long)&HWUART) {
+ info->MCR |= UART_MCR_AFE;
+ info->MCR |= UART_MCR_RTS;
+ }
+#endif
+ serial_outp(info, UART_MCR, info->MCR);

         /* Switch to receive mode for half-duplex ports */
         HALFDUPLEX_RX;
@@ -1728,8 +1741,13 @@
         if (state->type == PORT_PXA) {
                 switch ((long)state->iomem_base) {
                         case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break;
+#ifndef CONFIG_PXA_HWUART
                         case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break;
+#endif
                         case (long)&STUART: CKEN &= ~CKEN5_STUART; break;
+#ifdef CONFIG_PXA_HWUART
+ case (long)&HWUART: CKEN &= ~CKEN4_HWUART; break;
+#endif CONFIG_PXA_HWUART
                 }
         }
 #endif
@@ -6214,8 +6232,13 @@
                         wasdisabled = 1;
                         switch ((long)info->state->iomem_base) {
                         case (long)&FFUART: CKEN |= CKEN6_FFUART; break;
+#ifndef CONFIG_PXA_HWUART
                         case (long)&BTUART: CKEN |= CKEN7_BTUART; break;
+#endif
                         case (long)&STUART: CKEN |= CKEN5_STUART; break;
+#ifdef CONFIG_PXA_HWUART
+ case (long)&HWUART: CKEN |= CKEN4_HWUART; break;
+#endif
                         }
                 }
                 serial_out(info, UART_IER, UART_IER_UUE);
@@ -6250,8 +6273,13 @@
         if (0 && wasdisabled) {
                 switch ((long)info->state->iomem_base) {
                 case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break;
+#ifndef CONFIG_PXA_HWUART
                 case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break;
+#endif
                 case (long)&STUART: CKEN &= ~CKEN5_STUART; break;
+#ifdef CONFIG_PXA_HWUART
+ case (long)&HWUART: CKEN &= ~CKEN4_HWUART; break;
+#endif
                 }
         }
 #endif
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/irqs.h linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/irqs.h
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/irqs.h 2005-03-08 11:02:28.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/irqs.h 2005-03-09 13:38:56.000000000 +0100
@@ -12,9 +12,18 @@
     28/05/03 Martin Demin Added MQ1132
  */

+#ifdef CONFIG_PXA_HWUART
+#define PXA_IRQ_SKIP 6 /* Only the first 7 IRQs are reserved, but stupid drivers don't like irq 0 so */
+ /* I am offseting by yet another unit, so that IRQ_HWUART is not 0 */
+#else
 #define PXA_IRQ_SKIP 8 /* The first 8 IRQs are reserved */
+#endif
+
 #define PXA_IRQ(x) ((x) - PXA_IRQ_SKIP)

+#ifdef CONFIG_PXA_HWUART
+#define IRQ_HWUART PXA_IRQ(7)
+#endif
 #define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */
 #define IRQ_GPIO1 PXA_IRQ(9) /* GPIO1 Edge Detect */
 #define IRQ_GPIO_2_80 PXA_IRQ(10) /* GPIO[2-80] Edge Detect */
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/pxa-regs.h linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/pxa-regs.h
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/pxa-regs.h 2005-03-08 11:02:28.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/pxa-regs.h 2005-03-09 13:54:41.000000000 +0100
@@ -323,6 +323,27 @@
 #define STDLL __REG(0x40700000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
 #define STDLH __REG(0x40700004) /* Divisor Latch High Register (DLAB = 1) (read/write) */

+#ifdef CONFIG_PXA_HWUART
+/* Hardware UART (HWUART) */
+#define HWUART HWRBR
+#define HWRBR __REG(0x41600000) /* Receive Buffer Register (read only) */
+#define HWTHR __REG(0x41600000) /* Transmit Holding Register (write only) */
+#define HWIER __REG(0x41600004) /* Interrupt Enable Register (read/write) */
+#define HWIIR __REG(0x41600008) /* Interrupt ID Register (read only) */
+#define HWFCR __REG(0x41600008) /* FIFO Control Register (write only) */
+#define HWLCR __REG(0x4160000C) /* Line Control Register (read/write) */
+#define HWMCR __REG(0x41600010) /* Modem Control Register (read/write) */
+#define HWLSR __REG(0x41600014) /* Line Status Register (read only) */
+#define HWMSR __REG(0x41600018) /* Modem Status Register (read only) */
+#define HWSPR __REG(0x4160001C) /* Scratch Pad Register (read/write) */
+#define HWISR __REG(0x41600020) /* Infrared Selection Register (read/write) */
+#define HWDLL __REG(0x41600000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+#define HWDLH __REG(0x41600004) /* Divisor Latch High Register (DLAB = 1) (read/write) */
+#define HWFOR __REG(0x41600024) /* Receive FIFO Occupancy Register (FOR) (read only) */
+#define HWABR __REG(0x41600028) /* Auto-Baud Control Register (ABR) (read/write) */
+#define HWACR __REG(0x4160002C) /* Auto-Baud Count Register (ACR) (read/write) */
+#endif
+
 #define IER_DMAE (1 << 7) /* DMA Requests Enable */
 #define IER_UUE (1 << 6) /* UART Unit Enable */
 #define IER_NRZE (1 << 5) /* NRZ coding Enable */
@@ -1007,6 +1028,12 @@
 #define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT)
 #define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN)
 #define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT)
+#ifdef CONFIG_PXA_HWUART
+#define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN)
+#define GPIO43_HWTXD_MD (43 | GPIO_ALT_FN_3_OUT)
+#define GPIO44_HWCTS_MD (44 | GPIO_ALT_FN_3_IN)
+#define GPIO45_HWRTS_MD (45 | GPIO_ALT_FN_3_OUT)
+#endif
 #define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN)
 #define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN)
 #define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT)
@@ -1200,6 +1227,9 @@
 #define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */
 #define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */
 #define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */
+#ifdef CONFIG_PXA_HWUART
+#define CKEN4_HWUART (1 << 4) /* HWUART Unit Clock Enable */
+#endif
 #define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */
 #define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */
 #define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */
diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/serial.h linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/serial.h
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/serial.h 2005-03-08 11:02:28.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/serial.h 2005-03-09 14:09:11.000000000 +0100
@@ -12,11 +12,50 @@

 #define BAUD_BASE 921600

+#ifdef CONFIG_PXA_HWUART
+#define UART_MCR_AFE 0x20
+#endif
+
 /* Standard COM flags */
 #define STD_COM_FLAGS (ASYNC_SKIP_TEST)

 extern void pxa_serial_power_hook(int line, int state);

+#ifdef CONFIG_PXA_HWUART
+#define STD_SERIAL_PORT_DEFNS \
+ { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 32, \
+ baud_base: BAUD_BASE, \
+ iomem_base: (void *)&FFUART,\
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM32,\
+ irq: IRQ_FFUART, \
+ flags: STD_COM_FLAGS, \
+ power_func: pxa_serial_power_hook, \
+ }, { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 32, \
+ baud_base: BAUD_BASE, \
+ iomem_base: (void *)&HWUART,\
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM32,\
+ irq: IRQ_HWUART, \
+ flags: STD_COM_FLAGS, \
+ power_func: pxa_serial_power_hook, \
+ }, { \
+ type: PORT_PXA, \
+ xmit_fifo_size: 32, \
+ baud_base: BAUD_BASE, \
+ iomem_base: (void *)&STUART,\
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM32,\
+ irq: IRQ_STUART, \
+ flags: STD_COM_FLAGS, \
+ power_func: pxa_serial_power_hook, \
+ }
+
+#else
 #define STD_SERIAL_PORT_DEFNS \
         { \
                 type: PORT_PXA, \
@@ -48,7 +87,8 @@
                 irq: IRQ_STUART, \
                 flags: STD_COM_FLAGS, \
                 power_func: pxa_serial_power_hook, \
- }
+ }
+#endif

 #define RS_TABLE_SIZE 8

diff -urN -x '*[cC][vV][sS]*' linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/uncompress.h linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/uncompress.h
--- linux-2.4.19-rmk6-pxa1-hh37.5-r4/include/asm-arm/arch-pxa/uncompress.h 2005-03-08 11:02:28.000000000 +0100
+++ linux-2.4.19-rmk6-pxa1-hh37.5-r4-hwuart/include/asm-arm/arch-pxa/uncompress.h 2005-03-09 13:38:56.000000000 +0100
@@ -13,6 +13,10 @@
 #define BTUART ((volatile unsigned long *)0x40200000)
 #define STUART ((volatile unsigned long *)0x40700000)

+#ifdef CONFIG_PXA_HWUART
+#define HWUART ((volatile unsigned long *)0x41600000)
+#endif
+
 #define UART FFUART
Received on Wed Mar 09 2005 - 10:15:02 EST

This archive was generated by hypermail 2.2.0 : Mon Jul 25 2005 - 17:20:11 EDT