From: "David Bolcsfoldi" <dbolcsfoldi@gmail.com>
To: linuxppc-embedded@ozlabs.org
Subject: [PATCH] Xilinx UART Lite 2.6.18 driver
Date: Tue, 10 Oct 2006 13:49:08 -0700 [thread overview]
Message-ID: <609d5c8e0610101349w64cdd4ecjc5359ad8d1f5d635@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 271 bytes --]
Hi,
here's a set of patches that adds support for Xilinx UART lite
devices. It has been tested on an ML403-FX using xapp902
(ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox userspace.
This is my first patch for the Linux kernel, so please be gentle :-)
David
[-- Attachment #2: xuartlite_tty.c.patch --]
[-- Type: text/x-patch, Size: 3565 bytes --]
diff -urN 2.6.18/arch/ppc/boot/simple/Makefile patched/arch/ppc/boot/simple/Makefile
--- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/simple/Makefile 2006-10-07 10:34:32.000000000 -0700
@@ -205,6 +205,7 @@
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_XUL_CONSOLE) += xuartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff -urN 2.6.18/arch/ppc/boot/simple/misc.c patched/arch/ppc/boot/simple/misc.c
--- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/simple/misc.c 2006-10-07 10:27:34.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
diff -urN 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c patched/arch/ppc/boot/simple/xuartlite_tty.c
--- 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c 1969-12-31 16:00:00.000000000 -0800
+++ patched/arch/ppc/boot/simple/xuartlite_tty.c 2006-10-07 10:29:30.000000000 -0700
@@ -0,0 +1,74 @@
+/*
+ * Xilinx UART Lite support.
+ * Right now it only works over UART0 and none other.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
+#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
+#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
+#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
+#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
+
+static inline int is_xmit_full(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
+}
+
+static inline int is_recv_empty(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
+ default:
+ goto out;
+ }
+
+out:
+ return -1;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
+ out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_TX_FIFO_OFFSET), c);
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+ return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_RX_FIFO_OFFSET));
+}
+
+int serial_tstc(unsigned long com_port)
+{
+ return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+}
+
[-- Attachment #3: misc-common.c.patch --]
[-- Type: text/x-patch, Size: 2118 bytes --]
diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c patched/arch/ppc/boot/common/misc-common.c
--- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/common/misc-common.c 2006-10-07 10:33:28.000000000 -0700
@@ -57,7 +57,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
[-- Attachment #4: virtex.c.patch --]
[-- Type: text/x-patch, Size: 316 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/virtex.c 2006-10-07 11:21:18.000000000 -0700
@@ -52,5 +52,10 @@
.id = 0,
.dev.platform_data = serial_platform_data,
},
+
+ [VIRTEX_XUL_UART] = {
+ .name = "xul_uart",
+ .id = 0,
+ },
};
[-- Attachment #5: virtex.h.patch --]
[-- Type: text/x-patch, Size: 386 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/virtex.h 2006-10-07 10:35:31.000000000 -0700
@@ -27,7 +27,9 @@
/* Device type enumeration for platform bus definitions */
#ifndef __ASSEMBLY__
enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
+ VIRTEX_UART,
+ VIRTEX_XUL_UART,
+ NUM_PPC_SYS_DEVS,
};
#endif
[-- Attachment #6: xuartlite.c.patch --]
[-- Type: text/x-patch, Size: 19936 bytes --]
diff -urN 2.6.18/drivers/serial/Kconfig patched/drivers/serial/Kconfig
--- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
+++ patched/drivers/serial/Kconfig 2006-10-07 10:50:20.000000000 -0700
@@ -959,4 +959,22 @@
If you have enabled the serial port on the Motorola IMX
CPU you can make it the console by answering Y to this option.
+config SERIAL_XUL
+ tristate "Xilinx UART Lite serial support"
+ depends on XILINX_ML403
+ select SERIAL_CORE
+ help
+ This driver supports the Xilinx UART Lite serial ports. If you would
+ like to use them, you must answer Y or M to this option. Note that
+ for use as console, it must be included in the kernel and not as a
+ module.
+
+config SERIAL_XUL_CONSOLE
+ bool "Console on a Xilinx UART Lite serial port"
+ depends on SERIAL_XUL
+ select SERIAL_CORE_CONSOLE
+ help
+ Select this option if you'd like to use the UART Lite serial port
+ of the Xilinx ML403 board as a console.
+
endmenu
diff -urN 2.6.18/drivers/serial/Makefile patched/drivers/serial/Makefile
--- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
+++ patched/drivers/serial/Makefile 2006-10-07 10:51:02.000000000 -0700
@@ -56,3 +56,4 @@
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_XUL) += xuartlite.o
diff -urN 2.6.18/drivers/serial/xuartlite.c patched/drivers/serial/xuartlite.c
--- 2.6.18/drivers/serial/xuartlite.c 1969-12-31 16:00:00.000000000 -0800
+++ patched/drivers/serial/xuartlite.c 2006-10-10 11:08:08.000000000 -0700
@@ -0,0 +1,723 @@
+/*
+ * drivers/serial/xuartlite.c
+ *
+ * Driver for Xilinx UART Lite device.
+ *
+ * This driver has only been tested with the Xilinx ML403-FX board using the plb_temac
+ * reference design with on UART port.
+ *
+ * This driver is loosely based off the mpc52xx_uart driver.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#if defined(CONFIG_SERIAL_XUL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SERIAL_XUL_MAJOR 204
+#define SERIAL_XUL_MINOR 187
+
+/*
+ * Keeps various tidbits about the serial port taken
+ * from xparameters.h
+ * */
+
+struct xul_uart_data {
+ int baud;
+ int parity;
+ int bits;
+ int flow;
+ int uartclk;
+ int irq;
+ int mapbase;
+ int size;
+};
+
+static struct xul_uart_data xul_data[XPAR_XUARTLITE_NUM_INSTANCES] = {
+ {
+ .baud = XPAR_XUL_UART_0_BAUDRATE,
+#if (XPAR_XUL_UART_0_USE_PARITY != 0)
+ .parity = 'y',
+#else
+ .parity = 'n',
+#endif /* XPAR_XUL_UART_0_USE_PARITY */
+ .bits = XPAR_XUL_UART_0_DATA_BITS,
+ .flow = 'n',
+ .uartclk = 100000000 / 16, /* PLB speed / 16 */
+ .irq = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .mapbase = XPAR_XUL_UART_0_BASEADDR,
+ .size = (XPAR_XUL_UART_0_HIGHADDR - XPAR_XUL_UART_0_BASEADDR) + 1
+ }
+
+ /* Add next uart here */
+};
+
+static const long ISR_PASS_LIMIT = 255;
+static struct uart_port xul_uart_ports[XPAR_XUARTLITE_NUM_INSTANCES];
+
+#define XUL(port) ((unsigned int)((port)->membase))
+
+#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
+#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
+#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
+#define XUL_CONTROL_REG_OFFSET 12 /* control register, write only */
+
+#define XUL_CR_ENABLE_INTR 0x10 /* enable interrupt */
+#define XUL_CR_FIFO_RX_RESET 0x02 /* reset receive FIFO */
+#define XUL_CR_FIFO_TX_RESET 0x01 /* reset transmit FIFO */
+
+#define XUL_SR_PARITY_ERROR 0x80
+#define XUL_SR_FRAMING_ERROR 0x40
+#define XUL_SR_OVERRUN_ERROR 0x20
+#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
+#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
+#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t xul_uart_int(int irq,void *dev_id,struct pt_regs *regs);
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port) (0)
+#endif
+
+/* ======================================================================== */
+/* UART operations */
+/* ======================================================================== */
+
+static int
+xul_uart_int_tx_chars(struct uart_port *port);
+
+static inline int is_xmit_empty(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_EMPTY) == XUL_SR_TX_FIFO_EMPTY);
+}
+
+static inline int is_recv_empty(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
+}
+
+static inline int is_xmit_full(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
+}
+
+static inline void xmit_char(struct uart_port *port, char c)
+{
+ while(is_xmit_full(port));
+ out_be32((volatile unsigned *) (XUL(port) + XUL_TX_FIFO_OFFSET), c);
+}
+
+static inline char recv_char(struct uart_port *port)
+{
+ while(is_recv_empty(port));
+ return in_be32((volatile unsigned *) (XUL(port) + XUL_RX_FIFO_OFFSET));
+}
+
+static unsigned int
+xul_uart_tx_empty(struct uart_port *port)
+{
+ return ((is_xmit_empty(port)) ? TIOCSER_TEMT : 0);
+}
+
+static void
+xul_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* Not implemented */
+}
+
+static unsigned int
+xul_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void
+xul_uart_stop_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+}
+
+static void
+xul_uart_start_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+ xul_uart_int_tx_chars(port);
+}
+
+static void
+xul_uart_send_xchar(struct uart_port *port, char ch)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->x_char = ch;
+
+ if (ch) {
+ xmit_char(port, ch);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+xul_uart_stop_rx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+}
+
+static void
+xul_uart_enable_ms(struct uart_port *port)
+{
+ /* Not implemented */
+}
+
+static void
+xul_uart_break_ctl(struct uart_port *port, int ctl)
+{
+ /* Not implemented */
+}
+
+static int
+xul_uart_startup(struct uart_port *port)
+{
+ int ret;
+
+ /* Request IRQ */
+ ret = request_irq(port->irq, xul_uart_int,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM, "xul_uart", port);
+ if (ret)
+ return ret;
+
+ /* Reset/activate the port, clear and enable interrupts */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_ENABLE_INTR); /* Enable interrupt */
+
+ return 0;
+}
+
+static void
+xul_uart_shutdown(struct uart_port *port)
+{
+ /* Shut down the port, interrupt and all */
+
+ /* Disable interrupt bu clearing control register */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
+
+ /* Release interrupt */
+ free_irq(port->irq, port);
+}
+
+static void
+xul_uart_set_termios(struct uart_port *port, struct termios *new,
+ struct termios *old)
+{
+ /* Nothing can be set, fixed at IP block generation */
+}
+
+static const char *
+xul_uart_type(struct uart_port *port)
+{
+ return port->type == PORT_XUL ? "ttyXUL" : NULL;
+}
+
+static void
+xul_uart_release_port(struct uart_port *port)
+{
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ release_mem_region(port->mapbase, xul_data[port->line].size);
+}
+
+static int
+xul_uart_request_port(struct uart_port *port)
+{
+ int mem_region;
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, xul_data[port->line].size);
+ }
+
+ if (!port->membase) {
+ return -EINVAL;
+ }
+
+ mem_region = request_mem_region(port->mapbase, xul_data[port->line].size, "xul_uart") != NULL ? 0 : -EBUSY;
+ return 0;
+}
+
+static void
+xul_uart_config_port(struct uart_port *port, int flags)
+{
+ if ( (flags & UART_CONFIG_TYPE) &&
+ (xul_uart_request_port(port) == 0) )
+ port->type = PORT_XUL;
+}
+
+static int
+xul_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if ( ser->type != PORT_UNKNOWN && ser->type != PORT_XUL ) {
+ printk(KERN_WARNING "xul_uart_verify_port(1)\n");
+ return -EINVAL;
+ }
+
+ if ( (ser->irq != port->irq) ||
+ (ser->io_type != SERIAL_IO_MEM) ||
+ (ser->baud_base != port->uartclk) ||
+ (ser->iomem_base != (void*)port->mapbase) ||
+ (ser->hub6 != 0 ) ) {
+ printk(KERN_WARNING "xul_uart_verify_port(1)\n");
+ }
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static struct uart_ops xul_uart_ops = {
+ .tx_empty = xul_uart_tx_empty,
+ .set_mctrl = xul_uart_set_mctrl,
+ .get_mctrl = xul_uart_get_mctrl,
+ .stop_tx = xul_uart_stop_tx,
+ .start_tx = xul_uart_start_tx,
+ .send_xchar = xul_uart_send_xchar,
+ .stop_rx = xul_uart_stop_rx,
+ .enable_ms = xul_uart_enable_ms,
+ .break_ctl = xul_uart_break_ctl,
+ .startup = xul_uart_startup,
+ .shutdown = xul_uart_shutdown,
+ .set_termios = xul_uart_set_termios,
+/* .pm = xul_uart_pm, Not supported yet */
+/* .set_wake = xul_uart_set_wake, Not supported yet */
+ .type = xul_uart_type,
+ .release_port = xul_uart_release_port,
+ .request_port = xul_uart_request_port,
+ .config_port = xul_uart_config_port,
+ .verify_port = xul_uart_verify_port
+};
+
+
+/* ======================================================================== */
+/* Interrupt handling */
+/* ======================================================================== */
+
+static int
+xul_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned char ch, flag;
+ unsigned long status;
+
+ status = in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET));
+
+ /* While we can read, do so ! */
+ if ((status & XUL_SR_RX_FIFO_VALID_DATA) == XUL_SR_RX_FIFO_VALID_DATA) {
+
+ /* Get the char */
+ ch = recv_char(port);
+
+ /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+ if (uart_handle_sysrq_char(port, ch, regs)) {
+ port->sysrq = 0;
+ continue;
+ }
+#endif
+ /* Store it */
+
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & XUL_SR_PARITY_ERROR)
+ flag = TTY_PARITY;
+ else if (status & XUL_SR_FRAMING_ERROR)
+ flag = TTY_FRAME;
+
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (status & XUL_SR_OVERRUN_ERROR) {
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ }
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
+
+ return 0;
+}
+
+static int
+xul_uart_int_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ /* Process out of band chars */
+ if (port->x_char) {
+ xmit_char(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return 1;
+ }
+
+ /* Nothing to do ? */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ xul_uart_stop_tx(port);
+ return 0;
+ }
+
+ /* Send chars */
+ while (is_xmit_full(port) == 0) {
+ xmit_char(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ /* Wake up */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ uart_write_wakeup(port);
+ }
+
+ /* Maybe we're done after all */
+ if (uart_circ_empty(xmit)) {
+ xul_uart_stop_tx(port);
+ return 0;
+ }
+
+ return 1;
+}
+
+static irqreturn_t
+xul_uart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = (struct uart_port *) dev_id;
+ unsigned long pass = ISR_PASS_LIMIT;
+ unsigned int keepgoing;
+
+ if ( irq != port->irq ) {
+ printk( KERN_WARNING
+ "xul_uart_int : " \
+ "Received wrong int %d. Waiting for %d\n",
+ irq, port->irq);
+ return IRQ_NONE;
+ }
+
+ spin_lock(&port->lock);
+
+ /* While we have stuff to do, we continue */
+ do {
+ /* If we don't find anything to do, we stop */
+ keepgoing = 0;
+
+ /* Do we need to receive chars ? */
+ if (is_recv_empty(port) == 0) {
+ keepgoing |= xul_uart_int_rx_chars(port, regs);
+ }
+
+ /* Do we need to send chars ? */
+ if (is_xmit_empty(port)) {
+ keepgoing |= xul_uart_int_tx_chars(port);
+ }
+
+ /* Limit number of iteration */
+ if ( !(--pass) )
+ keepgoing = 0;
+
+ } while (keepgoing);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Utility routines
+ */
+
+static void __init xul_uart_init_ports(void)
+{
+ int i;
+ static int once = 1;
+
+ /* Initialize ports only once */
+ if (!once)
+ return;
+ once = 0;
+
+ for (i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
+ struct uart_port *xup = &xul_uart_ports[i];
+
+ xup->line = i;
+ spin_lock_init(&xup->lock);
+ xup->uartclk = xul_data[i].uartclk / 16;
+ xup->fifosize = 16;
+ xup->iotype = UPIO_MEM;
+ xup->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ xup->ops = &xul_uart_ops;
+ xup->irq = xul_data[i].irq;
+ xup->mapbase = xul_data[i].mapbase;
+ }
+}
+
+static void __init xul_uart_register_ports(struct uart_driver *driver)
+{
+ int i, ret;
+
+ for(i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
+ struct uart_port *port = &xul_uart_ports[i];
+ /* Add the port to the uart sub-system */
+ ret = uart_add_one_port(driver, port);
+ }
+}
+
+/* ======================================================================== */
+/* Console ( if applicable ) */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_XUL_CONSOLE
+
+static void
+xul_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &xul_uart_ports[co->index];
+ unsigned int i, j;
+
+ /* Disable interrupts */
+
+ spin_lock(&port->lock);
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+ spin_unlock(&port->lock);
+
+ /* Wait the TX buffer to be empty */
+ j = 5000000; /* Maximum wait */
+ while (!(is_xmit_empty(port)) &&
+ --j)
+ udelay(1);
+
+ for (i = 0; i < count; i++, s++) {
+ if (*s == '\n')
+ xmit_char(port, '\r');
+
+ xmit_char(port, *s);
+ }
+
+ /* Restore interrupt state */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+}
+
+static int __init
+xul_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud;
+ int bits;
+ int parity;
+ int flow;
+
+ if (co->index < 0 || co->index >= XPAR_XUARTLITE_NUM_INSTANCES)
+ return -EINVAL;
+
+ port = &xul_uart_ports[co->index];
+
+ /* We ioremap ourself */
+ port->membase = ioremap(port->mapbase, xul_data[co->index].size);
+
+ if (port->membase == NULL) {
+ return -EINVAL;
+ }
+
+ port->flags &= ~UPF_IOREMAP;
+
+ baud = xul_data[co->index].baud;
+ parity = xul_data[co->index].parity;
+ bits = xul_data[co->index].bits;
+ flow = xul_data[co->index].flow;
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver xul_uart_driver;
+
+static struct console xul_console = {
+ .name = "ttyXUL",
+ .write = xul_console_write,
+ .device = uart_console_device,
+ .setup = xul_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1, /* Specified on the cmdline (e.g. console=ttyXUL0 ) */
+ .data = &xul_uart_driver,
+};
+
+
+static int __init
+xul_console_init(void)
+{
+ xul_uart_init_ports();
+ register_console(&xul_console);
+ return 0;
+}
+
+console_initcall(xul_console_init);
+
+#define XUL_CONSOLE &xul_console
+#else
+#define XUL_CONSOLE NULL
+#endif
+
+
+/* ======================================================================== */
+/* UART Driver */
+/* ======================================================================== */
+
+static struct uart_driver xul_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "xul_uart",
+ .dev_name = "ttyXUL",
+ .major = SERIAL_XUL_MAJOR,
+ .minor = SERIAL_XUL_MINOR,
+ .nr = XPAR_XUARTLITE_NUM_INSTANCES,
+ .cons = XUL_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+xul_uart_probe(struct platform_device *dev)
+{
+ /* Probe does nothing */
+ return 0;
+}
+
+static int
+xul_uart_remove(struct platform_device *dev)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ if (port)
+ uart_remove_one_port(&xul_uart_driver, port);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+xul_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ if (port)
+ uart_suspend_port(&xul_uart_driver, port);
+
+ return 0;
+}
+
+static int
+xul_uart_resume(struct platform_device *dev)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ if (port)
+ uart_resume_port(&xul_uart_driver, port);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver xul_uart_platform_driver = {
+ .probe = xul_uart_probe,
+ .remove = xul_uart_remove,
+#ifdef CONFIG_PM
+ .suspend = xul_uart_suspend,
+ .resume = xul_uart_resume,
+#endif
+ .driver = {
+ .name = "xul_uart"
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+xul_uart_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: Xilinx UART Lite driver\n");
+
+ xul_uart_init_ports();
+
+ ret = uart_register_driver(&xul_uart_driver);
+
+ if (ret == 0) {
+ xul_uart_register_ports(&xul_uart_driver);
+
+ ret = platform_driver_register(&xul_uart_platform_driver);
+
+ if (ret) {
+ printk(KERN_WARNING "platform_driver_register failed! :%i\n", ret);
+ uart_unregister_driver(&xul_uart_driver);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit
+xul_uart_exit(void)
+{
+ platform_driver_unregister(&xul_uart_platform_driver);
+ uart_unregister_driver(&xul_uart_driver);
+}
+
+
+module_init(xul_uart_init);
+module_exit(xul_uart_exit);
+
+MODULE_AUTHOR("David Bolcsfoldi <dbolcsfoldi@gmail.com>");
+MODULE_DESCRIPTION("Xilinx UART Lite");
+MODULE_LICENSE("GPL");
+
[-- Attachment #7: xilinx_ml403.c.patch --]
[-- Type: text/x-patch, Size: 290 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-07 10:41:50.000000000 -0700
@@ -69,6 +69,7 @@
.device_list = (enum ppc_sys_devices[])
{
VIRTEX_UART,
+ VIRTEX_XUL_UART,
},
},
};
[-- Attachment #8: serial_core.h.patch --]
[-- Type: text/x-patch, Size: 268 bytes --]
--- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
+++ patched/include/linux/serial_core.h 2006-10-07 10:52:24.000000000 -0700
@@ -132,6 +132,8 @@
#define PORT_S3C2412 73
+/* Xilinx UART Lite */
+#define PORT_XUL 74
#ifdef __KERNEL__
next reply other threads:[~2006-10-10 20:49 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-10-10 20:49 David Bolcsfoldi [this message]
2006-10-10 22:04 ` [PATCH] Xilinx UART Lite 2.6.18 driver Grant Likely
2006-10-11 22:06 ` David H. Lynch Jr.
2006-10-12 10:34 ` Peter Korsgaard
2006-10-12 21:12 ` David Bolcsfoldi
2006-10-13 5:21 ` David Bolcsfoldi
2006-10-13 7:04 ` David H. Lynch Jr.
2006-10-13 7:22 ` Peter Korsgaard
[not found] ` <45329C42.3030000@dlasys.net>
2006-10-16 19:42 ` Peter Korsgaard
2006-10-13 7:11 ` Peter Korsgaard
2006-10-15 23:48 ` David Bolcsfoldi
2006-10-20 19:41 ` Peter Korsgaard
2006-10-27 15:03 ` Peter Korsgaard
2006-10-28 3:29 ` David H. Lynch Jr.
2006-10-30 8:23 ` Peter Korsgaard
2006-10-31 17:26 ` David H. Lynch Jr.
2006-10-30 19:45 ` David Bolcsfoldi
2006-11-06 15:44 ` Peter Korsgaard
2006-10-13 6:48 ` David H. Lynch Jr.
2006-10-13 7:15 ` Peter Korsgaard
2006-10-15 21:02 ` David H. Lynch Jr.
2006-10-16 19:49 ` Peter Korsgaard
2006-10-16 19:52 ` Peter Korsgaard
2006-10-13 7:08 ` Peter Korsgaard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=609d5c8e0610101349w64cdd4ecjc5359ad8d1f5d635@mail.gmail.com \
--to=dbolcsfoldi@gmail.com \
--cc=linuxppc-embedded@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).