#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 */
#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)
{
// 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);
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)
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)
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)
{
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)
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);