linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Xilinx UART Lite 2.6.18 driver
@ 2006-10-10 20:49 David Bolcsfoldi
  2006-10-10 22:04 ` Grant Likely
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-10 20:49 UTC (permalink / raw)
  To: linuxppc-embedded

[-- 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__
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2006-11-06 15:44 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-10 20:49 [PATCH] Xilinx UART Lite 2.6.18 driver David Bolcsfoldi
2006-10-10 22:04 ` 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

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).