]> xenbits.xensource.com Git - people/aperard/xen-arm.git/commitdiff
uart with fifo and interrupt, work in progress
authorAnthony PERARD <anthony.perard@citrix.com>
Wed, 23 Jan 2013 17:46:04 +0000 (17:46 +0000)
committerAnthony PERARD <anthony.perard@citrix.com>
Mon, 28 Jan 2013 15:55:21 +0000 (15:55 +0000)
xen/arch/arm/gic.c
xen/drivers/char/exynos5-uart.c

index 165287c80e06344e2c5661ae164397d5356920aa..9a67ca35cf7bb581fbb3a7ae0f32f87074c4fe9c 100644 (file)
@@ -398,7 +398,7 @@ void gic_route_spis(void)
 {
     /* XXX should get these from DT */
     /* UART */
-    gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0);
+    gic_route_irq(32+53, 0, 1u << smp_processor_id(), 0xa0);
 }
 
 void __init release_irq(unsigned int irq)
index bbb9f143472b65017930ae9e209b1a2e1b7fd1d4..ad6dab01022f256de3dd6e96341fbd62fcca9154 100644 (file)
 #include <xen/serial.h>
 #include <xen/init.h>
 #include <xen/irq.h>
+#include <asm/early_printk.h>
+
+// fifo does not work
+#define EXYNOS_UART_USE_FIFO
 
 static struct exynos5_uart {
     unsigned int baud, clock_hz, data_bits, parity, stop_bits, irq;
     volatile uint32_t *regs;
     struct irqaction irqaction;
-    unsigned int fifo;
 } exynos5_com[4] = {{0}};
 
 /* register addresses */
@@ -54,7 +57,9 @@ static struct exynos5_uart {
 #define TXDMA (0x2<<2)
 
 /* UFCON */
-#define FIFO_EN   (0x1<<0)
+#define FIFO_TX_RESET (1<<2)
+#define FIFO_RX_RESET (1<<1)
+#define FIFO_EN   (1<<0)
 
 /* UMCON */
 #define INT_EN (1<<3)
@@ -90,13 +95,34 @@ static void exynos5_uart_interrupt(int irq, void *data, struct cpu_user_regs *re
         {
             // clear all pending interrept
             // but should take care of ERROR and MODEM
-            uart->regs[UINTP] = ALLI;
 
-            if ( status & (RXD) )
+            if (status & ERROR) {
+                int error_bit = uart->regs[UERSTAT] & 0xf;
+                if (error_bit & (1<<0))
+                    printk("uart: overrun error\n");
+                if (error_bit & (1<<1))
+                    printk("uart: parity error\n");
+                if (error_bit & (1<<2))
+                    printk("uart: frame error\n");
+                if (error_bit & (1<<3))
+                    printk("uart: break detected\n");
+                uart->regs[UINTP] = ERROR;
+            }
+
+
+            if ( status & (RXD|ERROR) ) {
+                /* uart->regs[UINTM] |= RXD|ERROR; */
                 serial_rx_interrupt(port, regs);
+                /* uart->regs[UINTM] &= ~(RXD|ERROR); */
+                uart->regs[UINTP] = RXD|ERROR;
+            }
 
-            if ( status & (TXD) )
+            if ( status & (TXD|MODEM) ) {
+                /* uart->regs[UINTM] |= TXD|MODEM; */
                 serial_tx_interrupt(port, regs);
+                /* uart->regs[UINTM] &= ~(TXD|MODEM); */
+                uart->regs[UINTP] = TXD|MODEM;
+            }
 
             status = uart->regs[UINTP];
         } while (status != 0);
@@ -143,11 +169,22 @@ static void __init exynos5_uart_init_preirq(struct serial_port *port)
     uart->regs[UINTM] = ALLI;
     uart->regs[UINTP] = ALLI;
 
-    /* disable FIFO */
-    uart->regs[UFCON] = 0; //FIFO_EN;
+    /* enable FIFO */
+    uart->regs[UFCON] = FIFO_TX_RESET | FIFO_RX_RESET;
+    while (uart->regs[UFCON] & (FIFO_TX_RESET | FIFO_RX_RESET))
+           ;
+    // reset FIFO_TX_RESET | FIFO_RX_RESET | 
+#ifdef EXYNOS_UART_USE_FIFO
+    uart->regs[UFCON] = (0x6<<8)|FIFO_EN;
+#else
+    uart->regs[UFCON] = 0;
+#endif
+
 
     /* Enable the UART for RX and TX */
-    uart->regs[UCON] = RXIRQ|TXIRQ;
+    // level tx/rx inturrupt,only rx
+    // enable rx timeout interrupt
+    uart->regs[UCON] = (0<<9)|(0<<8)|RXIRQ|TXIRQ|(1<<7);
 }
 
 static void __init exynos5_uart_init_postirq(struct serial_port *port)
@@ -162,16 +199,16 @@ static void __init exynos5_uart_init_postirq(struct serial_port *port)
         uart->irqaction.dev_id  = port;
         if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
             printk("ERROR: Failed to allocate exynos5_uart IRQ %d\n", uart->irq);
-    }
 
-    /* Clear pending error interrupts */
-    uart->regs[UINTP] = ALLI;
+        /* Unmask interrupts */
+        uart->regs[UINTM] = 0; //MODEM|TXD|ERROR; // only have rx interrupt
 
-    /* Unmask interrupts */
-    uart->regs[UINTM] = 0;
+        /* Clear pending error interrupts */
+        uart->regs[UINTP] = ALLI;
 
-    /* Enable interrupts */
-    uart->regs[UMCON] |= INT_EN;
+        /* Enable interrupts */
+        uart->regs[UMCON] |= INT_EN;
+    }
 }
 
 static void exynos5_uart_suspend(struct serial_port *port)
@@ -187,8 +224,27 @@ static void exynos5_uart_resume(struct serial_port *port)
 static unsigned int exynos5_uart_tx_ready(struct serial_port *port)
 {
     struct exynos5_uart *uart = port->uart;
-    // return fifo size
-    return uart->regs[UTRSTAT] & TXFE ? 16 : 0;
+
+#ifdef EXYNOS_UART_USE_FIFO
+    // Tx FIFO full
+    if (uart->regs[UFSTAT] & (1<<24))
+        return 0;
+    else
+    {
+        int x = 16 - ((uart->regs[UFSTAT] >> 16) & 0xff);
+        // Tx FIFO count
+        if (x > 0)
+            return x;
+        else if (x == 0)
+            return 0;
+        else {
+            panic("unwanted value: %d\n", x);
+            return 0;
+        }
+    }
+#else
+    return uart->regs[UTRSTAT] & TXFE ? 1 : 0;
+#endif
 }
 
 static void exynos5_uart_putc(struct serial_port *port, char c)
@@ -201,11 +257,21 @@ static int exynos5_uart_getc(struct serial_port *port, char *pc)
 {
     struct exynos5_uart *uart = port->uart;
 
+#ifdef EXYNOS_UART_USE_FIFO
+    // check if rx fifo is full or if there is something in it
+    if ( (uart->regs[UFSTAT] & (1<<8)) || (uart->regs[UFSTAT] & 0xff))
+    {
+        *pc = uart->regs[URXH] & 0xff;
+        return 1;
+    }
+    else
+        return 0;
+#else
     if ( !(uart->regs[UTRSTAT] & RXDR) )
         return 0;
-
     *pc = uart->regs[URXH] & 0xff;
     return 1;
+#endif
 }
 
 static int __init exynos5_uart_irq(struct serial_port *port)
@@ -245,9 +311,8 @@ void __init exynos5_uart_init(int index, unsigned long register_base_address)
     uart->data_bits = 8;
     uart->parity    = PARITY_NONE;
     uart->stop_bits = 1;
-    uart->irq       = 51 + index; /* TODO Need to find this from devicetree */
+    uart->irq       = 32+51 + index; /* TODO Need to find this from devicetree */
     uart->regs      = (uint32_t *) register_base_address;
-    uart->fifo      = 0; // FIFO disabled
 
     /* Register with generic serial driver. */
     serial_register_uart(uart - exynos5_com, &exynos5_uart_driver, uart);