All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH] Xilinx uartlite serial driver
@ 2006-05-11 14:23 Peter Korsgaard
  2006-05-11 22:20 ` Russell King
  2006-08-22 15:13 ` Peter Korsgaard
  0 siblings, 2 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-05-11 14:23 UTC (permalink / raw)
  To: rmk+serial, linux-serial

Hi,

The following patch adds a driver for the Xilinx uartlite serial
controller used in boards with the PPC405 core in the Xilinx V2P/V4
fpgas.

The hardware is very simple (baudrate/start/stopbits fixed and
no break support). See the datasheet for details:

http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf

Comments and suggestions are welcome. I'm especially wondering about
the fact that I'm hijacking the device nodes used by the mpc52xx_uart
driver ..

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
 drivers/serial/Kconfig    |   27 ++
 drivers/serial/Makefile   |    1 
 drivers/serial/uartlite.c |  434 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/serial.h    |    3 
 4 files changed, 464 insertions(+), 1 deletion(-)

Index: linux/drivers/serial/uartlite.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/serial/uartlite.c	2006-05-11 16:08:09.000000000 +0200
@@ -0,0 +1,434 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+/* We use the ttyPSCx device nodes from the mpc52xx_uart driver as it would be
+   VERY unlikely to see a mpc52xx system with a uartlite. Perhaps we should get
+   a real LANANA range in the future */
+#define SERIAL_PSC_MAJOR	204
+#define SERIAL_PSC_MINOR	148
+
+/* For register details see datasheet:
+   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+*/
+#define ULITE_RX		0x00
+#define ULITE_TX		0x04
+#define ULITE_STATUS		0x08
+#define ULITE_CONTROL		0x0c
+
+#define ULITE_STATUS_RXVALID	0x01
+#define ULITE_STATUS_RXFULL	0x02
+#define ULITE_STATUS_TXEMPTY	0x04
+#define ULITE_STATUS_TXFULL	0x08
+#define ULITE_STATUS_IE		0x10
+#define ULITE_STATUS_OVERRUN	0x20
+#define ULITE_STATUS_FRAME	0x40
+#define ULITE_STATUS_PARITY	0x80
+
+#define ULITE_CONTROL_RST_TX	0x01
+#define ULITE_CONTROL_RST_RX	0x02
+#define ULITE_CONTROL_IE	0x10
+
+
+static struct uart_port ports[CONFIG_SERIAL_UARTLITE_NR_UARTS];
+
+
+static inline unsigned int serial_in(struct uart_port *port, int offset)
+{
+	return readb(port->membase + offset);
+}
+
+static inline void serial_out(struct uart_port *port, int offset, int value)
+{
+	writeb(value, port->membase + offset);
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+	ret = serial_in(port, ULITE_STATUS);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int stat;
+
+	stat = serial_in(port, ULITE_STATUS);
+	if (!(stat & ULITE_STATUS_TXFULL)) {
+		serial_out(port, ULITE_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+	/* N/A */
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = (struct uart_port *)dev_id;
+	struct tty_struct *tty = port->info->tty;
+	struct circ_buf *xmit  = &port->info->xmit;
+	int busy;
+
+	do {
+		int stat = serial_in(port, ULITE_STATUS);
+
+		busy = 0;
+
+		if (stat & (ULITE_STATUS_OVERRUN | ULITE_STATUS_FRAME
+			    | ULITE_STATUS_RXVALID)) {
+			busy = 1;
+
+			if (stat & ULITE_STATUS_OVERRUN) {
+				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+				port->icount.overrun++;
+			}
+
+			if (stat & ULITE_STATUS_FRAME) {
+				tty_insert_flip_char(tty, 0, TTY_FRAME);
+				port->icount.frame++;
+			}
+
+			if (stat & ULITE_STATUS_RXVALID) {
+				unsigned char flag = TTY_NORMAL;
+
+				if (stat & ULITE_STATUS_PARITY) {
+					flag = TTY_PARITY; /* still received */
+					port->icount.parity++;
+				}
+
+				tty_insert_flip_char(
+					tty, serial_in(port, ULITE_RX), flag);
+				port->icount.rx++;
+			}
+		}
+
+		if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+			continue;
+
+		if (!(stat & ULITE_STATUS_TXFULL)) {
+			busy = 1;
+			serial_out(port, ULITE_TX, xmit->buf[xmit->tail]);
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+			port->icount.tx++;
+		}
+
+		/* wake up */
+		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+			uart_write_wakeup(port);
+	} while (busy);
+
+	tty_flip_buffer_push(tty);
+
+	return IRQ_HANDLED;
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+	int ret;
+
+	ret = request_irq(port->irq, ulite_isr,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "uartlite", port);
+	if (ret)
+		return ret;
+
+	serial_out(port, ULITE_CONTROL,
+		   ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+	serial_out(port, ULITE_CONTROL, ULITE_CONTROL_IE);
+
+	return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+	serial_out(port, ULITE_CONTROL, 0);
+	free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct termios *termios,
+			      struct termios *old)
+{
+	/* N/A */
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+	port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* we don't want the core code to modify any port params */
+	return -EINVAL;
+}
+
+static struct uart_ops ulite_ops = {
+	.tx_empty	= ulite_tx_empty,
+	.set_mctrl	= ulite_set_mctrl,
+	.get_mctrl	= ulite_get_mctrl,
+	.stop_tx	= ulite_stop_tx,
+	.start_tx	= ulite_start_tx,
+	.stop_rx	= ulite_stop_rx,
+	.enable_ms	= ulite_enable_ms,
+	.break_ctl	= ulite_break_ctl,
+	.startup	= ulite_startup,
+	.shutdown	= ulite_shutdown,
+	.set_termios	= ulite_set_termios,
+	.type		= ulite_type,
+	.release_port	= ulite_release_port,
+	.request_port	= ulite_request_port,
+	.config_port	= ulite_config_port,
+	.verify_port	= ulite_verify_port
+};
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+
+static void ulite_console_write(struct console *co, const char *s,
+				unsigned int count)
+{
+	struct uart_port *port = &ports[co->index];
+	int i;
+
+	/* disable interrupts */
+	serial_out(port, ULITE_CONTROL, 0);
+
+	for (i = 0; i < count; i++) {
+		/* line return handling */
+		if (*s == '\n')
+			serial_out(port, ULITE_TX, '\r');
+
+		serial_out(port, ULITE_TX, *s++);
+
+		/* wait until it's sent */
+		while (!(serial_in(port, ULITE_STATUS)
+			 & ULITE_STATUS_TXEMPTY)) ;
+	}
+
+	/* restore interrupt state */
+	serial_out(port, ULITE_CONTROL, ULITE_CONTROL_IE);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+
+	if (co->index < 0 || co->index >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	port = &ports[co->index];
+
+	/* not initialized yet? */
+	if (!port->type)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+	.name	= "ttyPSC",
+	.write	= ulite_console_write,
+	.device	= uart_console_device,
+	.setup	= ulite_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1, /* Specified on the cmdline (e.g. console=ttyPSC0 ) */
+	.data	= &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+	register_console(&ulite_console);
+	return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "uartlite",
+	.dev_name	= "ttyPSC",
+	.devfs_name	= "ttyPSC",
+	.major		= SERIAL_PSC_MAJOR,
+	.minor		= SERIAL_PSC_MINOR,
+	.nr		= CONFIG_SERIAL_UARTLITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+	.cons		= &ulite_console,
+#endif
+};
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+	struct resource *res, *res2;
+	struct uart_port *port;
+	int ret;
+
+	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	if (ports[pdev->id].iobase)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	port = &ports[pdev->id];
+
+	port->fifosize	= 16;
+	port->regshift	= 2;
+	port->iotype	= UPIO_MEM;
+	port->iobase	= 1; /* mark port in use */
+	port->mapbase	= res->start;
+	port->ops	= &ulite_ops;
+	port->irq	= res2->start;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->dev	= &pdev->dev;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				pdev->name)) {
+		dev_err(&pdev->dev, "Memory region busy\n");
+		ret = -EBUSY;
+		goto request_mem_failed;
+	}
+
+	port->membase = ioremap(res->start, res->end - res->start + 1);
+	if (!port->membase) {
+		dev_err(&pdev->dev, "Unable to map registers\n");
+		ret = -EIO;
+		goto map_failed;
+	}
+
+	uart_add_one_port(&ulite_uart_driver, port);
+	platform_set_drvdata(pdev, port);
+	return 0;
+
+ map_failed:
+	release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+
+	return ret;
+}
+
+static int ulite_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (port)
+		uart_remove_one_port(&ulite_uart_driver, port);
+
+	port->iobase = 0;
+
+	return 0;
+}
+
+static struct platform_driver ulite_platform_driver = {
+	.probe	= ulite_probe,
+	.remove	= ulite_remove,
+	.driver	= {
+		   .owner = THIS_MODULE,
+		   .name  = "uartlite",
+		   },
+};
+
+int __init ulite_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&ulite_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&ulite_platform_driver);
+	if (ret)
+		uart_unregister_driver(&ulite_uart_driver);
+
+	return ret;
+}
+
+void __exit ulite_exit(void)
+{
+	platform_driver_unregister(&ulite_platform_driver);
+	uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
Index: linux/drivers/serial/Kconfig
===================================================================
--- linux.orig/drivers/serial/Kconfig	2006-05-09 16:55:27.000000000 +0200
+++ linux/drivers/serial/Kconfig	2006-05-10 18:02:09.000000000 +0200
@@ -507,6 +507,33 @@
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_UARTLITE
+	tristate "Xilinx uartlite serial port support"
+	depends on PPC32
+	select SERIAL_CORE
+	help
+	  Say Y here if you want to use the Xilinx uartlite serial controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uartlite.ko.
+
+config SERIAL_UARTLITE_NR_UARTS
+	int "Maximum number of Xilinx uartlite serial ports"
+	depends on SERIAL_UARTLITE
+	default "4"
+	help
+	  Set this to the number of serial ports you want the driver
+	  to support.
+
+config SERIAL_UARTLITE_CONSOLE
+	bool "Support for console on Xilinx uartlite serial port"
+	depends on SERIAL_UARTLITE=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Say Y here if you wish to use a Xilinx uartlite as the system
+	  console (the system console is the device which receives all kernel
+	  messages and warnings and which allows logins in single user mode).
+
 config SERIAL_SUNCORE
 	bool
 	depends on SPARC
Index: linux/drivers/serial/Makefile
===================================================================
--- linux.orig/drivers/serial/Makefile	2006-05-09 16:55:27.000000000 +0200
+++ linux/drivers/serial/Makefile	2006-05-09 16:56:02.000000000 +0200
@@ -55,3 +55,4 @@
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
Index: linux/include/linux/serial.h
===================================================================
--- linux.orig/include/linux/serial.h	2006-05-09 16:55:27.000000000 +0200
+++ linux/include/linux/serial.h	2006-05-09 16:56:02.000000000 +0200
@@ -76,7 +76,8 @@
 #define PORT_16654	11
 #define PORT_16850	12
 #define PORT_RSA	13	/* RSA-DV II/S card */
-#define PORT_MAX	13
+#define PORT_UARTLITE	14
+#define PORT_MAX	14
 
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-11 14:23 [RFC][PATCH] Xilinx uartlite serial driver Peter Korsgaard
@ 2006-05-11 22:20 ` Russell King
  2006-05-16  9:48   ` Peter Korsgaard
  2006-08-22 15:13 ` Peter Korsgaard
  1 sibling, 1 reply; 32+ messages in thread
From: Russell King @ 2006-05-11 22:20 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: linux-serial

On Thu, May 11, 2006 at 04:23:08PM +0200, Peter Korsgaard wrote:
> The hardware is very simple (baudrate/start/stopbits fixed and
> no break support). See the datasheet for details:
> 
> http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
> 
> Comments and suggestions are welcome. I'm especially wondering about
> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
> driver ..

That's for the mpc52xx folk to comment about.  I personally don't like
it.

> +static inline unsigned int serial_in(struct uart_port *port, int offset)
> +{
> +	return readb(port->membase + offset);
> +}
> +
> +static inline void serial_out(struct uart_port *port, int offset, int value)
> +{
> +	writeb(value, port->membase + offset);
> +}

Since there's no additional complication here, do you need separate
serial_in/serial_out inline functions?

> +static void ulite_stop_rx(struct uart_port *port)
> +{
> +	/* N/A */

It would probably be a good idea to set a flag so that your interrupt
handler can discard any input received after this function is called,
rather than adding it into the ldisc queue regardless.

> +}
> +
> +static void ulite_enable_ms(struct uart_port *port)
> +{
> +	/* N/A */
> +}
> +
> +static void ulite_break_ctl(struct uart_port *port, int ctl)
> +{
> +	/* N/A */
> +}
> +
> +static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
> +{
> +	struct uart_port *port = (struct uart_port *)dev_id;
> +	struct tty_struct *tty = port->info->tty;
> +	struct circ_buf *xmit  = &port->info->xmit;
> +	int busy;
> +
> +	do {
> +		int stat = serial_in(port, ULITE_STATUS);
> +
> +		busy = 0;
> +
> +		if (stat & (ULITE_STATUS_OVERRUN | ULITE_STATUS_FRAME
> +			    | ULITE_STATUS_RXVALID)) {
> +			busy = 1;
> +
> +			if (stat & ULITE_STATUS_OVERRUN) {
> +				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> +				port->icount.overrun++;
> +			}
> +
> +			if (stat & ULITE_STATUS_FRAME) {
> +				tty_insert_flip_char(tty, 0, TTY_FRAME);
> +				port->icount.frame++;
> +			}

No proper handling of these special conditions - drivers are expected
to take note of the termios settings and do the expected thing.  You
can't rely on the tty layer to discard overrun, parity or frame
conditions if they're not required.

> +static void ulite_console_write(struct console *co, const char *s,
> +				unsigned int count)
> +{
> +	struct uart_port *port = &ports[co->index];
> +	int i;
> +
> +	/* disable interrupts */
> +	serial_out(port, ULITE_CONTROL, 0);
> +
> +	for (i = 0; i < count; i++) {
> +		/* line return handling */
> +		if (*s == '\n')
> +			serial_out(port, ULITE_TX, '\r');
> +
> +		serial_out(port, ULITE_TX, *s++);
> +
> +		/* wait until it's sent */
> +		while (!(serial_in(port, ULITE_STATUS)
> +			 & ULITE_STATUS_TXEMPTY)) ;
> +	}

Should be using uart_console_write().

> +static int __devinit ulite_probe(struct platform_device *pdev)
> +{
> +	struct resource *res, *res2;
> +	struct uart_port *port;
> +	int ret;
> +
> +	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
> +		return -EINVAL;
> +
> +	if (ports[pdev->id].iobase)
> +		return -EBUSY;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (!res2)
> +		return -ENODEV;
> +
> +	port = &ports[pdev->id];
> +
> +	port->fifosize	= 16;
> +	port->regshift	= 2;
> +	port->iotype	= UPIO_MEM;
> +	port->iobase	= 1; /* mark port in use */

No.  If iobase isn't used, set it to zero.

> +	port->mapbase	= res->start;
> +	port->ops	= &ulite_ops;
> +	port->irq	= res2->start;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->dev	= &pdev->dev;
> +
> +	if (!request_mem_region(res->start, res->end - res->start + 1,
> +				pdev->name)) {
> +		dev_err(&pdev->dev, "Memory region busy\n");
> +		ret = -EBUSY;
> +		goto request_mem_failed;
> +	}
> +
> +	port->membase = ioremap(res->start, res->end - res->start + 1);
> +	if (!port->membase) {
> +		dev_err(&pdev->dev, "Unable to map registers\n");
> +		ret = -EIO;
> +		goto map_failed;
> +	}
> +
> +	uart_add_one_port(&ulite_uart_driver, port);
> +	platform_set_drvdata(pdev, port);
> +	return 0;
> +
> + map_failed:
> +	release_mem_region(res->start, res->end - res->start + 1);
> + request_mem_failed:
> +
> +	return ret;
> +}
> +
> +static int ulite_remove(struct platform_device *pdev)
> +{
> +	struct uart_port *port = platform_get_drvdata(pdev);
> +
> +	platform_set_drvdata(pdev, NULL);
> +
> +	if (port)
> +		uart_remove_one_port(&ulite_uart_driver, port);
> +
> +	port->iobase = 0;
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ulite_platform_driver = {
> +	.probe	= ulite_probe,
> +	.remove	= ulite_remove,
> +	.driver	= {
> +		   .owner = THIS_MODULE,
> +		   .name  = "uartlite",
> +		   },
> +};
> +
> +int __init ulite_init(void)
> +{
> +	int ret;
> +
> +	ret = uart_register_driver(&ulite_uart_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&ulite_platform_driver);
> +	if (ret)
> +		uart_unregister_driver(&ulite_uart_driver);
> +
> +	return ret;
> +}
> +
> +void __exit ulite_exit(void)
> +{
> +	platform_driver_unregister(&ulite_platform_driver);
> +	uart_unregister_driver(&ulite_uart_driver);
> +}
> +
> +module_init(ulite_init);
> +module_exit(ulite_exit);
> +
> +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
> +MODULE_DESCRIPTION("Xilinx uartlite serial driver");
> +MODULE_LICENSE("GPL");
> Index: linux/drivers/serial/Kconfig
> ===================================================================
> --- linux.orig/drivers/serial/Kconfig	2006-05-09 16:55:27.000000000 +0200
> +++ linux/drivers/serial/Kconfig	2006-05-10 18:02:09.000000000 +0200
> @@ -507,6 +507,33 @@
>  	  your boot loader (lilo or loadlin) about how to pass options to the
>  	  kernel at boot time.)
>  
> +config SERIAL_UARTLITE
> +	tristate "Xilinx uartlite serial port support"
> +	depends on PPC32
> +	select SERIAL_CORE
> +	help
> +	  Say Y here if you want to use the Xilinx uartlite serial controller.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called uartlite.ko.
> +
> +config SERIAL_UARTLITE_NR_UARTS
> +	int "Maximum number of Xilinx uartlite serial ports"
> +	depends on SERIAL_UARTLITE
> +	default "4"
> +	help
> +	  Set this to the number of serial ports you want the driver
> +	  to support.
> +
> +config SERIAL_UARTLITE_CONSOLE
> +	bool "Support for console on Xilinx uartlite serial port"
> +	depends on SERIAL_UARTLITE=y
> +	select SERIAL_CORE_CONSOLE
> +	help
> +	  Say Y here if you wish to use a Xilinx uartlite as the system
> +	  console (the system console is the device which receives all kernel
> +	  messages and warnings and which allows logins in single user mode).
> +
>  config SERIAL_SUNCORE
>  	bool
>  	depends on SPARC
> Index: linux/drivers/serial/Makefile
> ===================================================================
> --- linux.orig/drivers/serial/Makefile	2006-05-09 16:55:27.000000000 +0200
> +++ linux/drivers/serial/Makefile	2006-05-09 16:56:02.000000000 +0200
> @@ -55,3 +55,4 @@
>  obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
>  obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
>  obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
> +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
> Index: linux/include/linux/serial.h
> ===================================================================
> --- linux.orig/include/linux/serial.h	2006-05-09 16:55:27.000000000 +0200
> +++ linux/include/linux/serial.h	2006-05-09 16:56:02.000000000 +0200
> @@ -76,7 +76,8 @@
>  #define PORT_16654	11
>  #define PORT_16850	12
>  #define PORT_RSA	13	/* RSA-DV II/S card */
> -#define PORT_MAX	13
> +#define PORT_UARTLITE	14
> +#define PORT_MAX	14

The first set of numbers are reserved for the 8250 driver.  Please add
to the _end_ of the port number list.  Also, use serial_core.h rather
than serial.h please.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-11 22:20 ` Russell King
@ 2006-05-16  9:48   ` Peter Korsgaard
  2006-05-16 12:09     ` Sylvain Munaut
  2006-05-16 12:53     ` Russell King
  0 siblings, 2 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-05-16  9:48 UTC (permalink / raw)
  To: Russell King, tnt; +Cc: linux-serial

>>>>> "Russell" == Russell King <rmk@arm.linux.org.uk> writes:

Hi,

Sorry for the slow reply, I've been away all weekend...

 >> Comments and suggestions are welcome. I'm especially wondering about
 >> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
 >> driver ..

 Russell> That's for the mpc52xx folk to comment about.  I personally
 Russel>  don't like> it.

What do you say Sylvain? Reusing device nodes seems pretty common
(pxa.c, at91_serial.c, ..), and I cannot imagine anyone making a
system with uartlite and mpc52xx UARTs ..

 >> +static inline void serial_out(struct uart_port *port, int offset, int

 Russell> Since there's no additional complication here, do you need separate
 Russell> serial_in/serial_out inline functions?

No, removed in updated patch.

 >> +static void ulite_stop_rx(struct uart_port *port)
 >> +{
 >> +	/* N/A */

 Russell> It would probably be a good idea to set a flag so that your interrupt
 Russell> handler can discard any input received after this function is called,
 Russell> rather than adding it into the ldisc queue regardless.

Done in updated patch.

 >> +			if (stat & ULITE_STATUS_OVERRUN) {
 >> +				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 >> +				port->icount.overrun++;
 >> +			}
 >> +
 >> +			if (stat & ULITE_STATUS_FRAME) {
 >> +				tty_insert_flip_char(tty, 0, TTY_FRAME);
 >> +				port->icount.frame++;
 >> +			}

 Russell> No proper handling of these special conditions - drivers are expected
 Russell> to take note of the termios settings and do the expected thing.  You
 Russell> can't rely on the tty layer to discard overrun, parity or frame
 Russell> conditions if they're not required.

Sorry, for some reason I completely missed
Documentation/serial/driver. Fixed in updated patch.

Talking about driver, the following seems wrong (or atleast doesn't
match 8250.c)

The interaction of the iflag bits is as follows (parity error
given as an example):
Parity error      INPCK   IGNPAR
None              n/a     n/a     character received
Yes               n/a     0       character discarded
Yes               0       1       character received, marked as
                                  TTY_NORMAL
Yes               1       1       character received, marked as
                                  TTY_PARITY

The actual behaviour of the code is the inverse of the IGNPAR column
(chars with parity gets discarded if IGNPAR is 1, and sent as
TTY_NORMAL / TTY_PARITY if it's 0).

Looking closer at it, there seems to be a bug in 8250.c if INPCK=0 and
IGNPAR=1. Characters with parity error should get discarded, but they
are forwarded as TTY_NORMAL because the parity bit is masked away
before the ignore_mask check in uart_insert_char.

 >> +static void ulite_console_write(struct console *co, const char *s,

 Russell> Should be using uart_console_write().

The updated patch does.

 >> +static int __devinit ulite_probe(struct platform_device *pdev)
 >> +{
 >> +	struct resource *res, *res2;
 >> +	struct uart_port *port;
 >> +	int ret;
 >> +
 >> +	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
 >> +		return -EINVAL;
 >> +
 >> +	if (ports[pdev->id].iobase)
 >> +		return -EBUSY;
 >> +
 >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 >> +	if (!res)
 >> +		return -ENODEV;
 >> +
 >> +	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 >> +	if (!res2)
 >> +		return -ENODEV;
 >> +
 >> +	port = &ports[pdev->id];
 >> +
 >> +	port->fifosize	= 16;
 >> +	port->regshift	= 2;
 >> +	port->iotype	= UPIO_MEM;
 >> +	port->iobase	= 1; /* mark port in use */

 Russell> No.  If iobase isn't used, set it to zero.

Ok, the updated patch uses membase != 0 to track in use/free.

 >> +++ linux/include/linux/serial.h	2006-05-09 16:56:02.000000000 +0200
 >> @@ -76,7 +76,8 @@
 >> #define PORT_16654	11
 >> #define PORT_16850	12
 >> #define PORT_RSA	13	/* RSA-DV II/S card */
 >> -#define PORT_MAX	13
 >> +#define PORT_UARTLITE	14
 >> +#define PORT_MAX	14

 Russell> The first set of numbers are reserved for the 8250 driver.
 Russell> Please add to the _end_ of the port number list.  Also, use
 Russell> serial_core.h rather than serial.h please.

Updated patch uses serial_core.h

Thanks for the comments!

Updated patch:

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

---
 drivers/serial/Kconfig      |   27 ++
 drivers/serial/Makefile     |    1 
 drivers/serial/uartlite.c   |  497 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/serial_core.h |    3 
 4 files changed, 528 insertions(+)

Index: linux/drivers/serial/uartlite.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/serial/uartlite.c	2006-05-16 12:39:51.000000000 +0200
@@ -0,0 +1,497 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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/delay.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+/* We use the ttyPSCx device nodes from the mpc52xx_uart driver as it would be
+   VERY unlikely to see a mpc52xx system with a uartlite. Perhaps we should get
+   a real LANANA range in the future */
+#define SERIAL_PSC_MAJOR	204
+#define SERIAL_PSC_MINOR	148
+
+/* For register details see datasheet:
+   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+*/
+#define ULITE_RX		0x00
+#define ULITE_TX		0x04
+#define ULITE_STATUS		0x08
+#define ULITE_CONTROL		0x0c
+
+#define ULITE_REGION		16
+
+#define ULITE_STATUS_RXVALID	0x01
+#define ULITE_STATUS_RXFULL	0x02
+#define ULITE_STATUS_TXEMPTY	0x04
+#define ULITE_STATUS_TXFULL	0x08
+#define ULITE_STATUS_IE		0x10
+#define ULITE_STATUS_OVERRUN	0x20
+#define ULITE_STATUS_FRAME	0x40
+#define ULITE_STATUS_PARITY	0x80
+
+#define ULITE_CONTROL_RST_TX	0x01
+#define ULITE_CONTROL_RST_RX	0x02
+#define ULITE_CONTROL_IE	0x10
+
+
+static struct uart_port ports[CONFIG_SERIAL_UARTLITE_NR_UARTS];
+
+
+static int ulite_receive(struct uart_port *port, int stat)
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned char ch = 0;
+	char flag = TTY_NORMAL;
+
+	if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+		     | ULITE_STATUS_FRAME)) == 0)
+		return 0;
+
+	/* stats */
+	if (stat & ULITE_STATUS_RXVALID) {
+		port->icount.rx++;
+		ch = readb(port->membase + ULITE_RX);
+
+		if (stat & ULITE_STATUS_PARITY)
+			port->icount.parity++;
+	}
+
+	if (stat & ULITE_STATUS_OVERRUN)
+		port->icount.overrun++;
+
+	if (stat & ULITE_STATUS_FRAME)
+		port->icount.frame++;
+
+
+	/* drop byte with parity error if IGNPAR specificed */
+	if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+		stat &= ~ULITE_STATUS_RXVALID;
+
+	stat &= port->read_status_mask;
+
+	if (stat & ULITE_STATUS_PARITY)
+		flag = TTY_PARITY;
+
+
+	stat &= ~port->ignore_status_mask;
+
+	if (stat & ULITE_STATUS_RXVALID)
+		tty_insert_flip_char(tty, ch, flag);
+
+	if (stat & ULITE_STATUS_FRAME)
+		tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+	if (stat & ULITE_STATUS_OVERRUN)
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+	return 1;
+}
+
+
+static int ulite_transmit(struct uart_port *port, int stat)
+{
+	struct circ_buf *xmit  = &port->info->xmit;
+
+	if (stat & ULITE_STATUS_TXFULL)
+		return 0;
+
+	if (port->x_char) {
+		writeb(port->x_char, port->membase + ULITE_TX);
+		port->x_char = 0;
+		port->icount.tx++;
+		return 1;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		return 0;
+
+	writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+	port->icount.tx++;
+
+	/* wake up */
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	return 1;
+}
+
+
+static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = (struct uart_port *)dev_id;
+	int busy;
+
+	do {
+		int stat = readb(port->membase + ULITE_STATUS);
+		busy  = ulite_receive(port, stat);
+		busy |= ulite_transmit(port, stat);
+	} while (busy);
+
+	tty_flip_buffer_push(port->info->tty);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+	ret = readb(port->membase + ULITE_STATUS);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+	ulite_transmit(port, readb(port->membase + ULITE_STATUS));
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+	/* don't forward any more data (like !CREAD) */
+	port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+		| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+	/* N/A */
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+	int ret;
+
+	ret = request_irq(port->irq, ulite_isr,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "uartlite", port);
+	if (ret)
+		return ret;
+
+	writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+	       port->membase + ULITE_CONTROL);
+	writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+	return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+	writeb(0, port->membase + ULITE_CONTROL);
+	free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct termios *termios,
+			      struct termios *old)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+		| ULITE_STATUS_TXFULL;
+
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |=
+			ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= ULITE_STATUS_PARITY
+			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+	/* ignore all characters if CREAD is not set */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |=
+			ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+	release_mem_region(port->mapbase, ULITE_REGION);
+	iounmap(port->membase);
+	port->membase = 0;
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+	if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
+		dev_err(port->dev, "Memory region busy\n");
+		return -EBUSY;
+	}
+
+	port->membase = ioremap(port->mapbase, ULITE_REGION);
+	if (!port->membase) {
+		dev_err(port->dev, "Unable to map registers\n");
+		release_mem_region(port->mapbase, ULITE_REGION);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+	ulite_request_port(port);
+	port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* we don't want the core code to modify any port params */
+	return -EINVAL;
+}
+
+static struct uart_ops ulite_ops = {
+	.tx_empty	= ulite_tx_empty,
+	.set_mctrl	= ulite_set_mctrl,
+	.get_mctrl	= ulite_get_mctrl,
+	.stop_tx	= ulite_stop_tx,
+	.start_tx	= ulite_start_tx,
+	.stop_rx	= ulite_stop_rx,
+	.enable_ms	= ulite_enable_ms,
+	.break_ctl	= ulite_break_ctl,
+	.startup	= ulite_startup,
+	.shutdown	= ulite_shutdown,
+	.set_termios	= ulite_set_termios,
+	.type		= ulite_type,
+	.release_port	= ulite_release_port,
+	.request_port	= ulite_request_port,
+	.config_port	= ulite_config_port,
+	.verify_port	= ulite_verify_port
+};
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+	int i;
+
+	/* wait up to 10ms for the character(s) to be sent */
+	for (i=0; i<10000; i++) {
+		if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
+			break;
+		udelay(1);
+	}
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+	ulite_console_wait_tx(port);
+	writeb(ch, port->membase + ULITE_TX);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+				unsigned int count)
+{
+	struct uart_port *port = &ports[co->index];
+	unsigned long flags;
+	unsigned int ier;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else
+		spin_lock_irqsave(&port->lock, flags);
+
+	/* save and disable interrupt */
+	ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
+	writeb(0, port->membase + ULITE_CONTROL);
+
+	uart_console_write(port, s, count, ulite_console_putchar);
+
+	ulite_console_wait_tx(port);
+
+	/* restore interrupt state */
+	if (ier)
+		writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+
+	if (co->index < 0 || co->index >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	port = &ports[co->index];
+
+	/* not initialized yet? */
+	if (!port->membase)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+	.name	= "ttyPSC",
+	.write	= ulite_console_write,
+	.device	= uart_console_device,
+	.setup	= ulite_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1, /* Specified on the cmdline (e.g. console=ttyPSC0 ) */
+	.data	= &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+	register_console(&ulite_console);
+	return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "uartlite",
+	.dev_name	= "ttyPSC",
+	.devfs_name	= "ttyPSC",
+	.major		= SERIAL_PSC_MAJOR,
+	.minor		= SERIAL_PSC_MINOR,
+	.nr		= CONFIG_SERIAL_UARTLITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+	.cons		= &ulite_console,
+#endif
+};
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+	struct resource *res, *res2;
+	struct uart_port *port;
+	int ret;
+
+	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	if (ports[pdev->id].membase)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	port = &ports[pdev->id];
+
+	port->fifosize	= 16;
+	port->regshift	= 2;
+	port->iotype	= UPIO_MEM;
+	port->mapbase	= res->start;
+	port->membase	= 0;
+	port->ops	= &ulite_ops;
+	port->irq	= res2->start;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->dev	= &pdev->dev;
+	port->type	= PORT_UNKNOWN;
+
+	uart_add_one_port(&ulite_uart_driver, port);
+	platform_set_drvdata(pdev, port);
+	return 0;
+
+	return ret;
+}
+
+static int ulite_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (port)
+		uart_remove_one_port(&ulite_uart_driver, port);
+	/* mark port as free */
+	port->membase = 0;
+
+	return 0;
+}
+
+static struct platform_driver ulite_platform_driver = {
+	.probe	= ulite_probe,
+	.remove	= ulite_remove,
+	.driver	= {
+		   .owner = THIS_MODULE,
+		   .name  = "uartlite",
+		   },
+};
+
+int __init ulite_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&ulite_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&ulite_platform_driver);
+	if (ret)
+		uart_unregister_driver(&ulite_uart_driver);
+
+	return ret;
+}
+
+void __exit ulite_exit(void)
+{
+	platform_driver_unregister(&ulite_platform_driver);
+	uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
Index: linux/drivers/serial/Kconfig
===================================================================
--- linux.orig/drivers/serial/Kconfig	2006-05-12 14:21:50.000000000 +0200
+++ linux/drivers/serial/Kconfig	2006-05-16 12:53:04.000000000 +0200
@@ -507,6 +507,33 @@
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_UARTLITE
+	tristate "Xilinx uartlite serial port support"
+	depends on XILINX_VIRTEX
+	select SERIAL_CORE
+	help
+	  Say Y here if you want to use the Xilinx uartlite serial controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uartlite.ko.
+
+config SERIAL_UARTLITE_NR_UARTS
+	int "Maximum number of Xilinx uartlite serial ports"
+	depends on SERIAL_UARTLITE
+	default "4"
+	help
+	  Set this to the number of serial ports you want the driver
+	  to support.
+
+config SERIAL_UARTLITE_CONSOLE
+	bool "Support for console on Xilinx uartlite serial port"
+	depends on SERIAL_UARTLITE=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Say Y here if you wish to use a Xilinx uartlite as the system
+	  console (the system console is the device which receives all kernel
+	  messages and warnings and which allows logins in single user mode).
+
 config SERIAL_SUNCORE
 	bool
 	depends on SPARC
Index: linux/drivers/serial/Makefile
===================================================================
--- linux.orig/drivers/serial/Makefile	2006-05-12 14:21:50.000000000 +0200
+++ linux/drivers/serial/Makefile	2006-05-12 14:22:18.000000000 +0200
@@ -55,3 +55,4 @@
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
Index: linux/include/linux/serial_core.h
===================================================================
--- linux.orig/include/linux/serial_core.h	2006-05-12 14:23:30.000000000 +0200
+++ linux/include/linux/serial_core.h	2006-05-12 14:24:11.000000000 +0200
@@ -130,6 +130,9 @@
 /* SUN4V Hypervisor Console */
 #define PORT_SUNHV	72
 
+/* Xilinx uartlite */
+#define PORT_UARTLITE	73
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>

--
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16  9:48   ` Peter Korsgaard
@ 2006-05-16 12:09     ` Sylvain Munaut
  2006-05-16 12:53     ` Russell King
  1 sibling, 0 replies; 32+ messages in thread
From: Sylvain Munaut @ 2006-05-16 12:09 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: Russell King, linux-serial

Peter Korsgaard wrote:
> Hi,
>
> Sorry for the slow reply, I've been away all weekend...
>
>  >> Comments and suggestions are welcome. I'm especially wondering about
>  >> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
>  >> driver ..
>
>  Russell> That's for the mpc52xx folk to comment about.  I personally
>  Russel>  don't like> it.
>
> What do you say Sylvain? Reusing device nodes seems pretty common
> (pxa.c, at91_serial.c, ..), and I cannot imagine anyone making a
> system with uartlite and mpc52xx UARTs ..
>   

It's true that both devices are never gonna be used together (who
would want to implement a mpc5200 in a fpga ? ;), and personally I don't
really care if you reuse them as it's never gonna create any functional
problems.

The issue is more a "style" issue and if the maintainers allows you to
do that
(even if he doesn't like it ;), then it's fine by me. It's true that it
took me almost
2 month to get official ids ...


    Sylvain

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16  9:48   ` Peter Korsgaard
  2006-05-16 12:09     ` Sylvain Munaut
@ 2006-05-16 12:53     ` Russell King
  2006-05-16 13:03       ` Peter Korsgaard
  2006-05-16 13:03       ` Sylvain Munaut
  1 sibling, 2 replies; 32+ messages in thread
From: Russell King @ 2006-05-16 12:53 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: tnt, linux-serial

On Tue, May 16, 2006 at 11:48:00AM +0200, Peter Korsgaard wrote:
> >>>>> "Russell" == Russell King <rmk@arm.linux.org.uk> writes:
> 
> Hi,
> 
> Sorry for the slow reply, I've been away all weekend...
> 
>  >> Comments and suggestions are welcome. I'm especially wondering about
>  >> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
>  >> driver ..
> 
>  Russell> That's for the mpc52xx folk to comment about.  I personally
>  Russel>  don't like> it.
> 
> What do you say Sylvain? Reusing device nodes seems pretty common
> (pxa.c, at91_serial.c, ..), and I cannot imagine anyone making a
> system with uartlite and mpc52xx UARTs ..

Actually they're wishing they hadn't because they can't interoperate
with standard 16550-based ports without resorting to nasty hacks.
As such they're _both_ transitioning away from using the major 4
space.

> Talking about driver, the following seems wrong (or atleast doesn't
> match 8250.c)
> 
> The interaction of the iflag bits is as follows (parity error
> given as an example):
> Parity error      INPCK   IGNPAR
> None              n/a     n/a     character received
> Yes               n/a     0       character discarded
> Yes               0       1       character received, marked as
>                                   TTY_NORMAL
> Yes               1       1       character received, marked as
>                                   TTY_PARITY

Actually that's wrong.  INPCK controls whether input parity _checking_
is be enabled.  If INPCK is not set, then there is no checking of input
parity, and therefore you don't know if there is an error or not.
IOW, INPCK takes precidence over IGNPAR.

So, this should be:

INPCK	Parity error	IGNPAR	Action
  0	n/a		n/a	character received, marked TTY_NORMAL
  1	0		n/a	character received, marked TTY_NORMAL
  1	1		0	character received, marked TTY_PARITY
  1	1		1	character ignored

which I believe is what 8250 and other ports implement.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16 12:53     ` Russell King
@ 2006-05-16 13:03       ` Peter Korsgaard
  2006-06-02 16:47         ` Russell King
  2006-05-16 13:03       ` Sylvain Munaut
  1 sibling, 1 reply; 32+ messages in thread
From: Peter Korsgaard @ 2006-05-16 13:03 UTC (permalink / raw)
  To: Russell King; +Cc: tnt, linux-serial

>>>>> "Russell" == Russell King <rmk@arm.linux.org.uk> writes:

 >> What do you say Sylvain? Reusing device nodes seems pretty common
 >> (pxa.c, at91_serial.c, ..), and I cannot imagine anyone making a
 >> system with uartlite and mpc52xx UARTs ..

 Russell> Actually they're wishing they hadn't because they can't interoperate
 Russell> with standard 16550-based ports without resorting to nasty hacks.
 Russell> As such they're _both_ transitioning away from using the major 4
 Russell> space.

Ok, but I'm using major 204, not 4, so that shouldn't be an issue.

But ok, I'll apply for a range in the 204 series for the driver. The
question is, how many minors should I get? As the UART is implemented
in a FPGA there isn't really any hard upper bound on how many UARTs a
board could have.

 Russell> Actually that's wrong.  INPCK controls whether input parity
 Russell> _checking_ is be enabled.  If INPCK is not set, then there
 Russell> is no checking of input parity, and therefore you don't know
 Russell> if there is an error or not.

Ok, the following little patch updates Documentation/serial/driver to
match:

Update documentation to match reality. INPCK controls whether input
parity checking is enabled.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

---
 Documentation/serial/driver |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

Index: linux/Documentation/serial/driver
===================================================================
--- linux.orig/Documentation/serial/driver	2006-05-16 16:23:44.000000000 +0200
+++ linux/Documentation/serial/driver	2006-05-16 16:28:00.000000000 +0200
@@ -214,12 +214,13 @@
 	The interaction of the iflag bits is as follows (parity error
 	given as an example):
 	Parity error	INPCK	IGNPAR
-	None		n/a	n/a	character received
-	Yes		n/a	0	character discarded
-	Yes		0	1	character received, marked as
+	n/a		0	n/a	character received, marked as
 					TTY_NORMAL
-	Yes		1	1	character received, marked as
+	None		1	n/a	character received, marked as
+					TTY_NORMAL
+	Yes		1	0	character received, marked as
 					TTY_PARITY
+	Yes		1	1	character discarded
 
 	Other flags may be used (eg, xon/xoff characters) if your
 	hardware supports hardware "soft" flow control.

 Russell> which I believe is what 8250 and other ports implement.

Yes.

Did you have time to look at my updated driver patch?

--
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16 12:53     ` Russell King
  2006-05-16 13:03       ` Peter Korsgaard
@ 2006-05-16 13:03       ` Sylvain Munaut
  2006-05-16 13:07         ` Peter Korsgaard
  1 sibling, 1 reply; 32+ messages in thread
From: Sylvain Munaut @ 2006-05-16 13:03 UTC (permalink / raw)
  To: Russell King; +Cc: Peter Korsgaard, linux-serial

Russell King wrote:
> On Tue, May 16, 2006 at 11:48:00AM +0200, Peter Korsgaard wrote:
>   
>>>>>>> "Russell" == Russell King <rmk@arm.linux.org.uk> writes:
>>>>>>>               
>> Hi,
>>
>> Sorry for the slow reply, I've been away all weekend...
>>
>>  >> Comments and suggestions are welcome. I'm especially wondering about
>>  >> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
>>  >> driver ..
>>
>>  Russell> That's for the mpc52xx folk to comment about.  I personally
>>  Russel>  don't like> it.
>>
>> What do you say Sylvain? Reusing device nodes seems pretty common
>> (pxa.c, at91_serial.c, ..), and I cannot imagine anyone making a
>> system with uartlite and mpc52xx UARTs ..
>>     
>
> Actually they're wishing they hadn't because they can't interoperate
> with standard 16550-based ports without resorting to nasty hacks.
> As such they're _both_ transitioning away from using the major 4
> space.
>   
Yes, I confirm that using the major 4 space is really a bad idea. The
mpc52xx driver
did this, up until the point of people reported very annoying problems
when pcmcia
serial card were presents ;)

I guess the point is : Yes obtaining official minors is not that fast
(depends on 1 guy
apparently and he's busy ;) but it will save you troubles later.


    Sylvain

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16 13:03       ` Sylvain Munaut
@ 2006-05-16 13:07         ` Peter Korsgaard
  0 siblings, 0 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-05-16 13:07 UTC (permalink / raw)
  To: Sylvain Munaut; +Cc: Russell King, linux-serial

>>>>> "Sylvain" == Sylvain Munaut <tnt@246tNt.com> writes:

 Sylvain> Yes, I confirm that using the major 4 space is really a bad
 Sylvain> idea. The mpc52xx driver did this, up until the point of
 Sylvain> people reported very annoying problems when pcmcia serial
 Sylvain> card were presents ;)

Exactly. Using standard 16550 UARTs together with the uartlites is
quite common, that's why I hijacked the 204 range from the mpc52xx
driver instead of the 4 range of the 8250 driver.

But ok, I'll request a separate range for the uartlite driver.

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-16 13:03       ` Peter Korsgaard
@ 2006-06-02 16:47         ` Russell King
  0 siblings, 0 replies; 32+ messages in thread
From: Russell King @ 2006-06-02 16:47 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: tnt, linux-serial

On Tue, May 16, 2006 at 03:03:32PM +0200, Peter Korsgaard wrote:
> Ok, the following little patch updates Documentation/serial/driver to
> match:
> 
> Update documentation to match reality. INPCK controls whether input
> parity checking is enabled.
> 
> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

Thanks, applied.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-05-11 14:23 [RFC][PATCH] Xilinx uartlite serial driver Peter Korsgaard
  2006-05-11 22:20 ` Russell King
@ 2006-08-22 15:13 ` Peter Korsgaard
  2006-09-12 14:33   ` Olof Johansson
  1 sibling, 1 reply; 32+ messages in thread
From: Peter Korsgaard @ 2006-08-22 15:13 UTC (permalink / raw)
  To: rmk+serial, linux-serial; +Cc: linux-kernel

>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:

Hi,

 Peter> The following patch adds a driver for the Xilinx uartlite serial
 Peter> controller used in boards with the PPC405 core in the Xilinx V2P/V4
 Peter> fpgas.

 Peter> The hardware is very simple (baudrate/start/stopbits fixed and
 Peter> no break support). See the datasheet for details:

 Peter> http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf

 Peter> Comments and suggestions are welcome. I'm especially wondering about
 Peter> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
 Peter> driver ..

Ok, I now got a chunk of the 204 major range from LANANA. That afaik
solves the last remaining issue with this..

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

diff -urpN linux-2.6.18-rc4.orig/drivers/serial/Kconfig linux-2.6.18-rc4/drivers/serial/Kconfig
--- linux-2.6.18-rc4.orig/drivers/serial/Kconfig	2006-08-22 16:19:15.000000000 +0200
+++ linux-2.6.18-rc4/drivers/serial/Kconfig	2006-08-22 16:24:25.000000000 +0200
@@ -511,6 +511,33 @@ config SERIAL_IMX_CONSOLE
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_UARTLITE
+	tristate "Xilinx uartlite serial port support"
+	depends on PPC32
+	select SERIAL_CORE
+	help
+	  Say Y here if you want to use the Xilinx uartlite serial controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uartlite.ko.
+
+config SERIAL_UARTLITE_NR_UARTS
+	int "Maximum number of Xilinx uartlite serial ports"
+	depends on SERIAL_UARTLITE
+	default "4"
+	help
+	  Set this to the number of serial ports you want the driver
+	  to support.
+
+config SERIAL_UARTLITE_CONSOLE
+	bool "Support for console on Xilinx uartlite serial port"
+	depends on SERIAL_UARTLITE=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Say Y here if you wish to use a Xilinx uartlite as the system
+	  console (the system console is the device which receives all kernel
+	  messages and warnings and which allows logins in single user mode).
+
 config SERIAL_SUNCORE
 	bool
 	depends on SPARC
diff -urpN linux-2.6.18-rc4.orig/drivers/serial/Makefile linux-2.6.18-rc4/drivers/serial/Makefile
--- linux-2.6.18-rc4.orig/drivers/serial/Makefile	2006-08-22 16:19:15.000000000 +0200
+++ linux-2.6.18-rc4/drivers/serial/Makefile	2006-08-22 16:24:25.000000000 +0200
@@ -55,4 +55,5 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_si
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff -urpN linux-2.6.18-rc4.orig/drivers/serial/uartlite.c linux-2.6.18-rc4/drivers/serial/uartlite.c
--- linux-2.6.18-rc4.orig/drivers/serial/uartlite.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc4/drivers/serial/uartlite.c	2006-08-22 16:48:08.000000000 +0200
@@ -0,0 +1,431 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#define SERIAL_ULITE_MAJOR	204
+#define SERIAL_ULITE_MINOR	187
+
+/* For register details see datasheet:
+   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+*/
+#define ULITE_RX		0x00
+#define ULITE_TX		0x04
+#define ULITE_STATUS		0x08
+#define ULITE_CONTROL		0x0c
+
+#define ULITE_STATUS_RXVALID	0x01
+#define ULITE_STATUS_RXFULL	0x02
+#define ULITE_STATUS_TXEMPTY	0x04
+#define ULITE_STATUS_TXFULL	0x08
+#define ULITE_STATUS_IE		0x10
+#define ULITE_STATUS_OVERRUN	0x20
+#define ULITE_STATUS_FRAME	0x40
+#define ULITE_STATUS_PARITY	0x80
+
+#define ULITE_CONTROL_RST_TX	0x01
+#define ULITE_CONTROL_RST_RX	0x02
+#define ULITE_CONTROL_IE	0x10
+
+
+static struct uart_port ports[CONFIG_SERIAL_UARTLITE_NR_UARTS];
+
+
+static inline unsigned int serial_in(struct uart_port *port, int offset)
+{
+	return readb(port->membase + offset);
+}
+
+static inline void serial_out(struct uart_port *port, int offset, int value)
+{
+	writeb(value, port->membase + offset);
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+	ret = serial_in(port, ULITE_STATUS);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int stat;
+
+	stat = serial_in(port, ULITE_STATUS);
+	if (!(stat & ULITE_STATUS_TXFULL)) {
+		serial_out(port, ULITE_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+	/* N/A */
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = (struct uart_port *)dev_id;
+	struct tty_struct *tty = port->info->tty;
+	struct circ_buf *xmit  = &port->info->xmit;
+	int busy;
+
+	do {
+		int stat = serial_in(port, ULITE_STATUS);
+
+		busy = 0;
+
+		if (stat & (ULITE_STATUS_OVERRUN | ULITE_STATUS_FRAME
+			    | ULITE_STATUS_RXVALID)) {
+			busy = 1;
+
+			if (stat & ULITE_STATUS_OVERRUN) {
+				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+				port->icount.overrun++;
+			}
+
+			if (stat & ULITE_STATUS_FRAME) {
+				tty_insert_flip_char(tty, 0, TTY_FRAME);
+				port->icount.frame++;
+			}
+
+			if (stat & ULITE_STATUS_RXVALID) {
+				unsigned char flag = TTY_NORMAL;
+
+				if (stat & ULITE_STATUS_PARITY) {
+					flag = TTY_PARITY; /* still received */
+					port->icount.parity++;
+				}
+
+				tty_insert_flip_char(
+					tty, serial_in(port, ULITE_RX), flag);
+				port->icount.rx++;
+			}
+		}
+
+		if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+			continue;
+
+		if (!(stat & ULITE_STATUS_TXFULL)) {
+			busy = 1;
+			serial_out(port, ULITE_TX, xmit->buf[xmit->tail]);
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+			port->icount.tx++;
+		}
+
+		/* wake up */
+		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+			uart_write_wakeup(port);
+	} while (busy);
+
+	tty_flip_buffer_push(tty);
+
+	return IRQ_HANDLED;
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+	int ret;
+
+	ret = request_irq(port->irq, ulite_isr,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "uartlite", port);
+	if (ret)
+		return ret;
+
+	serial_out(port, ULITE_CONTROL,
+		   ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+	serial_out(port, ULITE_CONTROL, ULITE_CONTROL_IE);
+
+	return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+	serial_out(port, ULITE_CONTROL, 0);
+	free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct termios *termios,
+			      struct termios *old)
+{
+	/* N/A */
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+	port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* we don't want the core code to modify any port params */
+	return -EINVAL;
+}
+
+static struct uart_ops ulite_ops = {
+	.tx_empty	= ulite_tx_empty,
+	.set_mctrl	= ulite_set_mctrl,
+	.get_mctrl	= ulite_get_mctrl,
+	.stop_tx	= ulite_stop_tx,
+	.start_tx	= ulite_start_tx,
+	.stop_rx	= ulite_stop_rx,
+	.enable_ms	= ulite_enable_ms,
+	.break_ctl	= ulite_break_ctl,
+	.startup	= ulite_startup,
+	.shutdown	= ulite_shutdown,
+	.set_termios	= ulite_set_termios,
+	.type		= ulite_type,
+	.release_port	= ulite_release_port,
+	.request_port	= ulite_request_port,
+	.config_port	= ulite_config_port,
+	.verify_port	= ulite_verify_port
+};
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+
+static void ulite_console_write(struct console *co, const char *s,
+				unsigned int count)
+{
+	struct uart_port *port = &ports[co->index];
+	int i;
+
+	/* disable interrupts */
+	serial_out(port, ULITE_CONTROL, 0);
+
+	for (i = 0; i < count; i++) {
+		/* line return handling */
+		if (*s == '\n')
+			serial_out(port, ULITE_TX, '\r');
+
+		serial_out(port, ULITE_TX, *s++);
+
+		/* wait until it's sent */
+		while (!(serial_in(port, ULITE_STATUS)
+			 & ULITE_STATUS_TXEMPTY)) ;
+	}
+
+	/* restore interrupt state */
+	serial_out(port, ULITE_CONTROL, ULITE_CONTROL_IE);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+
+	if (co->index < 0 || co->index >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	port = &ports[co->index];
+
+	/* not initialized yet? */
+	if (!port->type)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+	.name	= "ttyUL",
+	.write	= ulite_console_write,
+	.device	= uart_console_device,
+	.setup	= ulite_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
+	.data	= &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+	register_console(&ulite_console);
+	return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "uartlite",
+	.dev_name	= "ttyUL",
+	.devfs_name	= "ttyUL",
+	.major		= SERIAL_ULITE_MAJOR,
+	.minor		= SERIAL_ULITE_MINOR,
+	.nr		= CONFIG_SERIAL_UARTLITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+	.cons		= &ulite_console,
+#endif
+};
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+	struct resource *res, *res2;
+	struct uart_port *port;
+	int ret;
+
+	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_UARTLITE_NR_UARTS)
+		return -EINVAL;
+
+	if (ports[pdev->id].iobase)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	port = &ports[pdev->id];
+
+	port->fifosize	= 16;
+	port->regshift	= 2;
+	port->iotype	= UPIO_MEM;
+	port->iobase	= 1; /* mark port in use */
+	port->mapbase	= res->start;
+	port->ops	= &ulite_ops;
+	port->irq	= res2->start;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->dev	= &pdev->dev;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				pdev->name)) {
+		dev_err(&pdev->dev, "Memory region busy\n");
+		ret = -EBUSY;
+		goto request_mem_failed;
+	}
+
+	port->membase = ioremap(res->start, res->end - res->start + 1);
+	if (!port->membase) {
+		dev_err(&pdev->dev, "Unable to map registers\n");
+		ret = -EIO;
+		goto map_failed;
+	}
+
+	uart_add_one_port(&ulite_uart_driver, port);
+	platform_set_drvdata(pdev, port);
+	return 0;
+
+ map_failed:
+	release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+
+	return ret;
+}
+
+static int ulite_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (port)
+		uart_remove_one_port(&ulite_uart_driver, port);
+
+	port->iobase = 0;
+
+	return 0;
+}
+
+static struct platform_driver ulite_platform_driver = {
+	.probe	= ulite_probe,
+	.remove	= ulite_remove,
+	.driver	= {
+		   .owner = THIS_MODULE,
+		   .name  = "uartlite",
+		   },
+};
+
+int __init ulite_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&ulite_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&ulite_platform_driver);
+	if (ret)
+		uart_unregister_driver(&ulite_uart_driver);
+
+	return ret;
+}
+
+void __exit ulite_exit(void)
+{
+	platform_driver_unregister(&ulite_platform_driver);
+	uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
diff -urpN linux-2.6.18-rc4.orig/include/linux/serial.h linux-2.6.18-rc4/include/linux/serial.h
--- linux-2.6.18-rc4.orig/include/linux/serial.h	2006-06-18 03:49:35.000000000 +0200
+++ linux-2.6.18-rc4/include/linux/serial.h	2006-08-22 16:24:25.000000000 +0200
@@ -76,7 +76,8 @@ struct serial_struct {
 #define PORT_16654	11
 #define PORT_16850	12
 #define PORT_RSA	13	/* RSA-DV II/S card */
-#define PORT_MAX	13
+#define PORT_UARTLITE	14
+#define PORT_MAX	14
 
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1
diff -urpN linux-2.6.18-rc4.orig/MAINTAINERS linux-2.6.18-rc4/MAINTAINERS
--- linux-2.6.18-rc4.orig/MAINTAINERS	2006-08-22 16:19:12.000000000 +0200
+++ linux-2.6.18-rc4/MAINTAINERS	2006-08-22 16:41:08.000000000 +0200
@@ -3288,6 +3288,12 @@ L:	xfs@oss.sgi.com
 W:	http://oss.sgi.com/projects/xfs
 S:	Supported
 
+XILINX UARTLITE SERIAL DRIVER
+P:	Peter Korsgaard
+M:	jacmet@sunsite.dk
+L:	linux-serial@vger.kernel.org
+S:	Maintained
+
 X86 3-LEVEL PAGING (PAE) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-08-22 15:13 ` Peter Korsgaard
@ 2006-09-12 14:33   ` Olof Johansson
  2006-09-13  5:56     ` Peter Korsgaard
  0 siblings, 1 reply; 32+ messages in thread
From: Olof Johansson @ 2006-09-12 14:33 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: rmk+serial, linux-serial, linux-kernel

On Tue, 22 Aug 2006 17:13:13 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:

> >>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
> 
> Hi,
> 
>  Peter> The following patch adds a driver for the Xilinx uartlite serial
>  Peter> controller used in boards with the PPC405 core in the Xilinx V2P/V4
>  Peter> fpgas.
> 
>  Peter> The hardware is very simple (baudrate/start/stopbits fixed and
>  Peter> no break support). See the datasheet for details:
> 
>  Peter> http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
> 
>  Peter> Comments and suggestions are welcome. I'm especially wondering about
>  Peter> the fact that I'm hijacking the device nodes used by the mpc52xx_uart
>  Peter> driver ..
> 
> Ok, I now got a chunk of the 204 major range from LANANA. That afaik
> solves the last remaining issue with this..

Hi,

I've been working on getting this running smoothly over the last few days.
In my opinion there's a few pieces missing:

1. There's no early boot console support for PPC. There's another
uartlite patch that's floating around that has this, very useful for
early bringup tasks. I'd like to see this expanded to include that as
well (the regular part of the other driver seems more or less broken
though, so this is a better base driver). That shouldn't stop this part
of the driver to go in though, just possible future work.

2. There seems to be some timeout issues with tx_empty. If I boot a
regular distro with getty, etc, I get veeeery slow console output right
when init starts up. Adding a small default timeout in the init of the
uart code seems to help -- the hanging thread seems to be sleeping in
uart_wait_until_sent(). I picked a value of '5', seems ok. (Also,
without this fix, getty won't start on the port for some reason, it
sits in the same timeout forever, or at least for a very long time).

3. It would be useful to demonstrate how to hook up the device all the
way through to the board port (i.e. add a config option and include it
in the ml403 platform code or similar). It's not hard, but it'd make it
easier for whomever comes next. Of course, with 4xx hopefully soon
moving over to arch/powerpc, this would be taken care of through the
device tree instead.

So, (2) is really the only thing that's needed (IMHO) before this goes
in, but the rest would be useful as well.


-Olof


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-12 14:33   ` Olof Johansson
@ 2006-09-13  5:56     ` Peter Korsgaard
  2006-09-13 13:39       ` Peter Korsgaard
  2006-09-28 10:14       ` David H. Lynch Jr.
  0 siblings, 2 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-09-13  5:56 UTC (permalink / raw)
  To: Olof Johansson; +Cc: rmk+serial, linux-serial, linux-kernel

>>>>> "Olof" == Olof Johansson <olof@lixom.net> writes:

Hi Olof, thanks for looking into the driver..

 Olof> In my opinion there's a few pieces missing:

 Olof> 1. There's no early boot console support for PPC. There's another
 Olof> uartlite patch that's floating around that has this, very useful for
 Olof> early bringup tasks. I'd like to see this expanded to include that as
 Olof> well (the regular part of the other driver seems more or less broken
 Olof> though, so this is a better base driver). That shouldn't stop this part
 Olof> of the driver to go in though, just possible future work.

True. The board I have an uartlite on also has a 8250 so it hasn't
been an issue for me so far - But it would indeed be a nice
addition. Adding new stuff to arch/ppc at this moment isn't that
sensible, so perhaps it makes most sense to wait til 4xx is supported
under arch/powerpc?

 Olof> 2. There seems to be some timeout issues with tx_empty. If I boot a
 Olof> regular distro with getty, etc, I get veeeery slow console output right
 Olof> when init starts up. Adding a small default timeout in the init of the
 Olof> uart code seems to help -- the hanging thread seems to be sleeping in
 Olof> uart_wait_until_sent(). I picked a value of '5', seems ok. (Also,
 Olof> without this fix, getty won't start on the port for some reason, it
 Olof> sits in the same timeout forever, or at least for a very long time).

Huh, that's odd - I haven't noticed that. I'll test it again and get
back to you.

 Olof> 3. It would be useful to demonstrate how to hook up the device all the
 Olof> way through to the board port (i.e. add a config option and include it
 Olof> in the ml403 platform code or similar). It's not hard, but it'd make it
 Olof> easier for whomever comes next. Of course, with 4xx hopefully soon
 Olof> moving over to arch/powerpc, this would be taken care of through the
 Olof> device tree instead.

Yes - Afaik none of the Xilinx boards comes with uartlites
configured so it's not usable out-of-the-box, but you can ofcause do a
setup with the proper #ifdefs like the 8250 stuff in virtex.c.

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13  5:56     ` Peter Korsgaard
@ 2006-09-13 13:39       ` Peter Korsgaard
  2006-09-13 15:01         ` Olof Johansson
  2006-10-19 23:06         ` Olof Johansson
  2006-09-28 10:14       ` David H. Lynch Jr.
  1 sibling, 2 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-09-13 13:39 UTC (permalink / raw)
  To: Olof Johansson; +Cc: rmk+serial, linux-serial, linux-kernel

>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:

 Olof> 2. There seems to be some timeout issues with tx_empty.

 Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
 Peter> back to you.

Ahh, found it - I didn't update the uart timeout in set_termios so it
used a very long timeout. Please give the updated patch a try.

Additional changes:
- Actually add the fixes I did in May on request of Russell
- Update for 2.6.18 (devfs and new IRQF defines)
- Removed the SERIAL_UARTLITE_NR_UARTS config option as we only have 4
  minors reserved with lanana anyway.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Kconfig linux-2.6.18-rc7/drivers/serial/Kconfig
--- linux-2.6.18-rc7.orig/drivers/serial/Kconfig	2006-09-13 15:01:24.000000000 +0200
+++ linux-2.6.18-rc7/drivers/serial/Kconfig	2006-09-13 15:01:51.000000000 +0200
@@ -511,6 +511,25 @@ config SERIAL_IMX_CONSOLE
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_UARTLITE
+	tristate "Xilinx uartlite serial port support"
+	depends on PPC32
+	select SERIAL_CORE
+	help
+	  Say Y here if you want to use the Xilinx uartlite serial controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called uartlite.ko.
+
+config SERIAL_UARTLITE_CONSOLE
+	bool "Support for console on Xilinx uartlite serial port"
+	depends on SERIAL_UARTLITE=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Say Y here if you wish to use a Xilinx uartlite as the system
+	  console (the system console is the device which receives all kernel
+	  messages and warnings and which allows logins in single user mode).
+
 config SERIAL_SUNCORE
 	bool
 	depends on SPARC
diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Makefile linux-2.6.18-rc7/drivers/serial/Makefile
--- linux-2.6.18-rc7.orig/drivers/serial/Makefile	2006-09-13 15:01:24.000000000 +0200
+++ linux-2.6.18-rc7/drivers/serial/Makefile	2006-09-13 15:01:51.000000000 +0200
@@ -55,4 +55,5 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_si
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff -urpN linux-2.6.18-rc7.orig/drivers/serial/uartlite.c linux-2.6.18-rc7/drivers/serial/uartlite.c
--- linux-2.6.18-rc7.orig/drivers/serial/uartlite.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc7/drivers/serial/uartlite.c	2006-09-13 15:01:51.000000000 +0200
@@ -0,0 +1,496 @@
+/*
+ * uartlite.c: Serial driver for Xilinx uartlite serial controller
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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/platform_device.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#define ULITE_MAJOR		204
+#define ULITE_MINOR		187
+#define ULITE_NR_UARTS		4
+
+/* For register details see datasheet:
+   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+*/
+#define ULITE_RX		0x00
+#define ULITE_TX		0x04
+#define ULITE_STATUS		0x08
+#define ULITE_CONTROL		0x0c
+
+#define ULITE_REGION		16
+
+#define ULITE_STATUS_RXVALID	0x01
+#define ULITE_STATUS_RXFULL	0x02
+#define ULITE_STATUS_TXEMPTY	0x04
+#define ULITE_STATUS_TXFULL	0x08
+#define ULITE_STATUS_IE		0x10
+#define ULITE_STATUS_OVERRUN	0x20
+#define ULITE_STATUS_FRAME	0x40
+#define ULITE_STATUS_PARITY	0x80
+
+#define ULITE_CONTROL_RST_TX	0x01
+#define ULITE_CONTROL_RST_RX	0x02
+#define ULITE_CONTROL_IE	0x10
+
+
+static struct uart_port ports[ULITE_NR_UARTS];
+
+static int ulite_receive(struct uart_port *port, int stat)
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned char ch = 0;
+	char flag = TTY_NORMAL;
+
+	if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+		     | ULITE_STATUS_FRAME)) == 0)
+		return 0;
+
+	/* stats */
+	if (stat & ULITE_STATUS_RXVALID) {
+		port->icount.rx++;
+		ch = readb(port->membase + ULITE_RX);
+
+		if (stat & ULITE_STATUS_PARITY)
+			port->icount.parity++;
+	}
+
+	if (stat & ULITE_STATUS_OVERRUN)
+		port->icount.overrun++;
+
+	if (stat & ULITE_STATUS_FRAME)
+		port->icount.frame++;
+
+
+	/* drop byte with parity error if IGNPAR specificed */
+	if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+		stat &= ~ULITE_STATUS_RXVALID;
+
+	stat &= port->read_status_mask;
+
+	if (stat & ULITE_STATUS_PARITY)
+		flag = TTY_PARITY;
+
+
+	stat &= ~port->ignore_status_mask;
+
+	if (stat & ULITE_STATUS_RXVALID)
+		tty_insert_flip_char(tty, ch, flag);
+
+	if (stat & ULITE_STATUS_FRAME)
+		tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+	if (stat & ULITE_STATUS_OVERRUN)
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+	return 1;
+}
+
+static int ulite_transmit(struct uart_port *port, int stat)
+{
+	struct circ_buf *xmit  = &port->info->xmit;
+
+	if (stat & ULITE_STATUS_TXFULL)
+		return 0;
+
+	if (port->x_char) {
+		writeb(port->x_char, port->membase + ULITE_TX);
+		port->x_char = 0;
+		port->icount.tx++;
+		return 1;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		return 0;
+
+	writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+	port->icount.tx++;
+
+	/* wake up */
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	return 1;
+}
+
+static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = (struct uart_port *)dev_id;
+	int busy;
+
+	do {
+		int stat = readb(port->membase + ULITE_STATUS);
+		busy  = ulite_receive(port, stat);
+		busy |= ulite_transmit(port, stat);
+	} while (busy);
+
+	tty_flip_buffer_push(port->info->tty);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int ulite_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+	ret = readb(port->membase + ULITE_STATUS);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ulite_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* N/A */
+}
+
+static void ulite_stop_tx(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_start_tx(struct uart_port *port)
+{
+	ulite_transmit(port, readb(port->membase + ULITE_STATUS));
+}
+
+static void ulite_stop_rx(struct uart_port *port)
+{
+	/* don't forward any more data (like !CREAD) */
+	port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+		| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+}
+
+static void ulite_enable_ms(struct uart_port *port)
+{
+	/* N/A */
+}
+
+static void ulite_break_ctl(struct uart_port *port, int ctl)
+{
+	/* N/A */
+}
+
+static int ulite_startup(struct uart_port *port)
+{
+	int ret;
+
+	ret = request_irq(port->irq, ulite_isr,
+			  IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port);
+	if (ret)
+		return ret;
+
+	writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+	       port->membase + ULITE_CONTROL);
+	writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+	return 0;
+}
+
+static void ulite_shutdown(struct uart_port *port)
+{
+	writeb(0, port->membase + ULITE_CONTROL);
+	free_irq(port->irq, port);
+}
+
+static void ulite_set_termios(struct uart_port *port, struct termios *termios,
+			      struct termios *old)
+{
+	unsigned long flags;
+	unsigned int baud;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+		| ULITE_STATUS_TXFULL;
+
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |=
+			ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= ULITE_STATUS_PARITY
+			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+	/* ignore all characters if CREAD is not set */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |=
+			ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+	/* update timeout */
+	baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ulite_type(struct uart_port *port)
+{
+	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
+}
+
+static void ulite_release_port(struct uart_port *port)
+{
+	release_mem_region(port->mapbase, ULITE_REGION);
+	iounmap(port->membase);
+	port->membase = 0;
+}
+
+static int ulite_request_port(struct uart_port *port)
+{
+	if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
+		dev_err(port->dev, "Memory region busy\n");
+		return -EBUSY;
+	}
+
+	port->membase = ioremap(port->mapbase, ULITE_REGION);
+	if (!port->membase) {
+		dev_err(port->dev, "Unable to map registers\n");
+		release_mem_region(port->mapbase, ULITE_REGION);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void ulite_config_port(struct uart_port *port, int flags)
+{
+	ulite_request_port(port);
+	port->type = PORT_UARTLITE;
+}
+
+static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* we don't want the core code to modify any port params */
+	return -EINVAL;
+}
+
+static struct uart_ops ulite_ops = {
+	.tx_empty	= ulite_tx_empty,
+	.set_mctrl	= ulite_set_mctrl,
+	.get_mctrl	= ulite_get_mctrl,
+	.stop_tx	= ulite_stop_tx,
+	.start_tx	= ulite_start_tx,
+	.stop_rx	= ulite_stop_rx,
+	.enable_ms	= ulite_enable_ms,
+	.break_ctl	= ulite_break_ctl,
+	.startup	= ulite_startup,
+	.shutdown	= ulite_shutdown,
+	.set_termios	= ulite_set_termios,
+	.type		= ulite_type,
+	.release_port	= ulite_release_port,
+	.request_port	= ulite_request_port,
+	.config_port	= ulite_config_port,
+	.verify_port	= ulite_verify_port
+};
+
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+	int i;
+
+	/* wait up to 10ms for the character(s) to be sent */
+	for (i=0; i<10000; i++) {
+		if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
+			break;
+		udelay(1);
+	}
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+	ulite_console_wait_tx(port);
+	writeb(ch, port->membase + ULITE_TX);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+				unsigned int count)
+{
+	struct uart_port *port = &ports[co->index];
+	unsigned long flags;
+	unsigned int ier;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else
+		spin_lock_irqsave(&port->lock, flags);
+
+	/* save and disable interrupt */
+	ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
+	writeb(0, port->membase + ULITE_CONTROL);
+
+	uart_console_write(port, s, count, ulite_console_putchar);
+
+	ulite_console_wait_tx(port);
+
+	/* restore interrupt state */
+	if (ier)
+		writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+
+	if (co->index < 0 || co->index >= ULITE_NR_UARTS)
+		return -EINVAL;
+
+	port = &ports[co->index];
+
+	/* not initialized yet? */
+	if (!port->membase)
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct uart_driver ulite_uart_driver;
+
+static struct console ulite_console = {
+	.name	= "ttyUL",
+	.write	= ulite_console_write,
+	.device	= uart_console_device,
+	.setup	= ulite_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
+	.data	= &ulite_uart_driver,
+};
+
+static int __init ulite_console_init(void)
+{
+	register_console(&ulite_console);
+	return 0;
+}
+
+console_initcall(ulite_console_init);
+
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+static struct uart_driver ulite_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "uartlite",
+	.dev_name	= "ttyUL",
+	.major		= ULITE_MAJOR,
+	.minor		= ULITE_MINOR,
+	.nr		= ULITE_NR_UARTS,
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+	.cons		= &ulite_console,
+#endif
+};
+
+static int __devinit ulite_probe(struct platform_device *pdev)
+{
+	struct resource *res, *res2;
+	struct uart_port *port;
+
+	if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+		return -EINVAL;
+
+	if (ports[pdev->id].membase)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	port = &ports[pdev->id];
+
+	port->fifosize	= 16;
+	port->regshift	= 2;
+	port->iotype	= UPIO_MEM;
+	port->iobase	= 1; /* mark port in use */
+	port->mapbase	= res->start;
+	port->membase	= 0;
+	port->ops	= &ulite_ops;
+	port->irq	= res2->start;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->dev	= &pdev->dev;
+	port->type	= PORT_UNKNOWN;
+
+	uart_add_one_port(&ulite_uart_driver, port);
+	platform_set_drvdata(pdev, port);
+
+	return 0;
+}
+
+static int ulite_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (port)
+		uart_remove_one_port(&ulite_uart_driver, port);
+
+	/* mark port as free */
+	port->membase = 0;
+
+	return 0;
+}
+
+static struct platform_driver ulite_platform_driver = {
+	.probe	= ulite_probe,
+	.remove	= ulite_remove,
+	.driver	= {
+		   .owner = THIS_MODULE,
+		   .name  = "uartlite",
+		   },
+};
+
+int __init ulite_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&ulite_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&ulite_platform_driver);
+	if (ret)
+		uart_unregister_driver(&ulite_uart_driver);
+
+	return ret;
+}
+
+void __exit ulite_exit(void)
+{
+	platform_driver_unregister(&ulite_platform_driver);
+	uart_unregister_driver(&ulite_uart_driver);
+}
+
+module_init(ulite_init);
+module_exit(ulite_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Xilinx uartlite serial driver");
+MODULE_LICENSE("GPL");
diff -urpN linux-2.6.18-rc7.orig/include/linux/serial_core.h linux-2.6.18-rc7/include/linux/serial_core.h
--- linux-2.6.18-rc7.orig/include/linux/serial_core.h	2006-09-13 15:01:25.000000000 +0200
+++ linux-2.6.18-rc7/include/linux/serial_core.h	2006-09-13 15:01:51.000000000 +0200
@@ -132,6 +132,8 @@
 
 #define PORT_S3C2412	73
 
+/* Xilinx uartlite */
+#define PORT_UARTLITE	74
 
 #ifdef __KERNEL__
 
diff -urpN linux-2.6.18-rc7.orig/MAINTAINERS linux-2.6.18-rc7/MAINTAINERS
--- linux-2.6.18-rc7.orig/MAINTAINERS	2006-09-13 15:01:20.000000000 +0200
+++ linux-2.6.18-rc7/MAINTAINERS	2006-09-13 15:01:51.000000000 +0200
@@ -3303,6 +3303,12 @@ W:	http://oss.sgi.com/projects/xfs
 T:	git git://oss.sgi.com:8090/xfs/xfs-2.6
 S:	Supported
 
+XILINX UARTLITE SERIAL DRIVER
+P:	Peter Korsgaard
+M:	jacmet@sunsite.dk
+L:	linux-serial@vger.kernel.org
+S:	Maintained
+
 X86 3-LEVEL PAGING (PAE) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 13:39       ` Peter Korsgaard
@ 2006-09-13 15:01         ` Olof Johansson
  2006-09-29 19:04           ` David H. Lynch Jr.
                             ` (4 more replies)
  2006-10-19 23:06         ` Olof Johansson
  1 sibling, 5 replies; 32+ messages in thread
From: Olof Johansson @ 2006-09-13 15:01 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: rmk+serial, linux-serial, linux-kernel

On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:

> >>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
> 
>  Olof> 2. There seems to be some timeout issues with tx_empty.
> 
>  Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
>  Peter> back to you.
> 
> Ahh, found it - I didn't update the uart timeout in set_termios so it
> used a very long timeout. Please give the updated patch a try.

Looks good. Thanks.

> Additional changes:
> - Actually add the fixes I did in May on request of Russell
> - Update for 2.6.18 (devfs and new IRQF defines)
> - Removed the SERIAL_UARTLITE_NR_UARTS config option as we only have 4
>   minors reserved with lanana anyway.
> 
> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

Acked-by: Olof Johansson <olof@lixom.net>

> 
> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Kconfig linux-2.6.18-rc7/drivers/serial/Kconfig
> --- linux-2.6.18-rc7.orig/drivers/serial/Kconfig	2006-09-13 15:01:24.000000000 +0200
> +++ linux-2.6.18-rc7/drivers/serial/Kconfig	2006-09-13 15:01:51.000000000 +0200
> @@ -511,6 +511,25 @@ config SERIAL_IMX_CONSOLE
>  	  your boot loader (lilo or loadlin) about how to pass options to the
>  	  kernel at boot time.)
>  
> +config SERIAL_UARTLITE
> +	tristate "Xilinx uartlite serial port support"
> +	depends on PPC32
> +	select SERIAL_CORE
> +	help
> +	  Say Y here if you want to use the Xilinx uartlite serial controller.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called uartlite.ko.
> +
> +config SERIAL_UARTLITE_CONSOLE
> +	bool "Support for console on Xilinx uartlite serial port"
> +	depends on SERIAL_UARTLITE=y
> +	select SERIAL_CORE_CONSOLE
> +	help
> +	  Say Y here if you wish to use a Xilinx uartlite as the system
> +	  console (the system console is the device which receives all kernel
> +	  messages and warnings and which allows logins in single user mode).
> +
>  config SERIAL_SUNCORE
>  	bool
>  	depends on SPARC
> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Makefile linux-2.6.18-rc7/drivers/serial/Makefile
> --- linux-2.6.18-rc7.orig/drivers/serial/Makefile	2006-09-13 15:01:24.000000000 +0200
> +++ linux-2.6.18-rc7/drivers/serial/Makefile	2006-09-13 15:01:51.000000000 +0200
> @@ -55,4 +55,5 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_si
>  obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
>  obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
>  obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
> +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
>  obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/uartlite.c linux-2.6.18-rc7/drivers/serial/uartlite.c
> --- linux-2.6.18-rc7.orig/drivers/serial/uartlite.c	1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.18-rc7/drivers/serial/uartlite.c	2006-09-13 15:01:51.000000000 +0200
> @@ -0,0 +1,496 @@
> +/*
> + * uartlite.c: Serial driver for Xilinx uartlite serial controller
> + *
> + * Peter Korsgaard <jacmet@sunsite.dk>
> + *
> + * 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/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/console.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/tty.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <asm/io.h>
> +
> +#define ULITE_MAJOR		204
> +#define ULITE_MINOR		187
> +#define ULITE_NR_UARTS		4
> +
> +/* For register details see datasheet:
> +   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
> +*/
> +#define ULITE_RX		0x00
> +#define ULITE_TX		0x04
> +#define ULITE_STATUS		0x08
> +#define ULITE_CONTROL		0x0c
> +
> +#define ULITE_REGION		16
> +
> +#define ULITE_STATUS_RXVALID	0x01
> +#define ULITE_STATUS_RXFULL	0x02
> +#define ULITE_STATUS_TXEMPTY	0x04
> +#define ULITE_STATUS_TXFULL	0x08
> +#define ULITE_STATUS_IE		0x10
> +#define ULITE_STATUS_OVERRUN	0x20
> +#define ULITE_STATUS_FRAME	0x40
> +#define ULITE_STATUS_PARITY	0x80
> +
> +#define ULITE_CONTROL_RST_TX	0x01
> +#define ULITE_CONTROL_RST_RX	0x02
> +#define ULITE_CONTROL_IE	0x10
> +
> +
> +static struct uart_port ports[ULITE_NR_UARTS];
> +
> +static int ulite_receive(struct uart_port *port, int stat)
> +{
> +	struct tty_struct *tty = port->info->tty;
> +	unsigned char ch = 0;
> +	char flag = TTY_NORMAL;
> +
> +	if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
> +		     | ULITE_STATUS_FRAME)) == 0)
> +		return 0;
> +
> +	/* stats */
> +	if (stat & ULITE_STATUS_RXVALID) {
> +		port->icount.rx++;
> +		ch = readb(port->membase + ULITE_RX);
> +
> +		if (stat & ULITE_STATUS_PARITY)
> +			port->icount.parity++;
> +	}
> +
> +	if (stat & ULITE_STATUS_OVERRUN)
> +		port->icount.overrun++;
> +
> +	if (stat & ULITE_STATUS_FRAME)
> +		port->icount.frame++;
> +
> +
> +	/* drop byte with parity error if IGNPAR specificed */
> +	if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
> +		stat &= ~ULITE_STATUS_RXVALID;
> +
> +	stat &= port->read_status_mask;
> +
> +	if (stat & ULITE_STATUS_PARITY)
> +		flag = TTY_PARITY;
> +
> +
> +	stat &= ~port->ignore_status_mask;
> +
> +	if (stat & ULITE_STATUS_RXVALID)
> +		tty_insert_flip_char(tty, ch, flag);
> +
> +	if (stat & ULITE_STATUS_FRAME)
> +		tty_insert_flip_char(tty, 0, TTY_FRAME);
> +
> +	if (stat & ULITE_STATUS_OVERRUN)
> +		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> +
> +	return 1;
> +}
> +
> +static int ulite_transmit(struct uart_port *port, int stat)
> +{
> +	struct circ_buf *xmit  = &port->info->xmit;
> +
> +	if (stat & ULITE_STATUS_TXFULL)
> +		return 0;
> +
> +	if (port->x_char) {
> +		writeb(port->x_char, port->membase + ULITE_TX);
> +		port->x_char = 0;
> +		port->icount.tx++;
> +		return 1;
> +	}
> +
> +	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
> +		return 0;
> +
> +	writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX);
> +	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
> +	port->icount.tx++;
> +
> +	/* wake up */
> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +		uart_write_wakeup(port);
> +
> +	return 1;
> +}
> +
> +static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
> +{
> +	struct uart_port *port = (struct uart_port *)dev_id;
> +	int busy;
> +
> +	do {
> +		int stat = readb(port->membase + ULITE_STATUS);
> +		busy  = ulite_receive(port, stat);
> +		busy |= ulite_transmit(port, stat);
> +	} while (busy);
> +
> +	tty_flip_buffer_push(port->info->tty);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static unsigned int ulite_tx_empty(struct uart_port *port)
> +{
> +	unsigned long flags;
> +	unsigned int ret;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	ret = readb(port->membase + ULITE_STATUS);
> +	spin_unlock_irqrestore(&port->lock, flags);
> +
> +	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
> +}
> +
> +static unsigned int ulite_get_mctrl(struct uart_port *port)
> +{
> +	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
> +}
> +
> +static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +	/* N/A */
> +}
> +
> +static void ulite_stop_tx(struct uart_port *port)
> +{
> +	/* N/A */
> +}
> +
> +static void ulite_start_tx(struct uart_port *port)
> +{
> +	ulite_transmit(port, readb(port->membase + ULITE_STATUS));
> +}
> +
> +static void ulite_stop_rx(struct uart_port *port)
> +{
> +	/* don't forward any more data (like !CREAD) */
> +	port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
> +		| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +}
> +
> +static void ulite_enable_ms(struct uart_port *port)
> +{
> +	/* N/A */
> +}
> +
> +static void ulite_break_ctl(struct uart_port *port, int ctl)
> +{
> +	/* N/A */
> +}
> +
> +static int ulite_startup(struct uart_port *port)
> +{
> +	int ret;
> +
> +	ret = request_irq(port->irq, ulite_isr,
> +			  IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port);
> +	if (ret)
> +		return ret;
> +
> +	writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
> +	       port->membase + ULITE_CONTROL);
> +	writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
> +
> +	return 0;
> +}
> +
> +static void ulite_shutdown(struct uart_port *port)
> +{
> +	writeb(0, port->membase + ULITE_CONTROL);
> +	free_irq(port->irq, port);
> +}
> +
> +static void ulite_set_termios(struct uart_port *port, struct termios *termios,
> +			      struct termios *old)
> +{
> +	unsigned long flags;
> +	unsigned int baud;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
> +		| ULITE_STATUS_TXFULL;
> +
> +	if (termios->c_iflag & INPCK)
> +		port->read_status_mask |=
> +			ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
> +
> +	port->ignore_status_mask = 0;
> +	if (termios->c_iflag & IGNPAR)
> +		port->ignore_status_mask |= ULITE_STATUS_PARITY
> +			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +
> +	/* ignore all characters if CREAD is not set */
> +	if ((termios->c_cflag & CREAD) == 0)
> +		port->ignore_status_mask |=
> +			ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
> +			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
> +
> +	/* update timeout */
> +	baud = uart_get_baud_rate(port, termios, old, 0, 460800);
> +	uart_update_timeout(port, termios->c_cflag, baud);
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *ulite_type(struct uart_port *port)
> +{
> +	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
> +}
> +
> +static void ulite_release_port(struct uart_port *port)
> +{
> +	release_mem_region(port->mapbase, ULITE_REGION);
> +	iounmap(port->membase);
> +	port->membase = 0;
> +}
> +
> +static int ulite_request_port(struct uart_port *port)
> +{
> +	if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
> +		dev_err(port->dev, "Memory region busy\n");
> +		return -EBUSY;
> +	}
> +
> +	port->membase = ioremap(port->mapbase, ULITE_REGION);
> +	if (!port->membase) {
> +		dev_err(port->dev, "Unable to map registers\n");
> +		release_mem_region(port->mapbase, ULITE_REGION);
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static void ulite_config_port(struct uart_port *port, int flags)
> +{
> +	ulite_request_port(port);
> +	port->type = PORT_UARTLITE;
> +}
> +
> +static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +	/* we don't want the core code to modify any port params */
> +	return -EINVAL;
> +}
> +
> +static struct uart_ops ulite_ops = {
> +	.tx_empty	= ulite_tx_empty,
> +	.set_mctrl	= ulite_set_mctrl,
> +	.get_mctrl	= ulite_get_mctrl,
> +	.stop_tx	= ulite_stop_tx,
> +	.start_tx	= ulite_start_tx,
> +	.stop_rx	= ulite_stop_rx,
> +	.enable_ms	= ulite_enable_ms,
> +	.break_ctl	= ulite_break_ctl,
> +	.startup	= ulite_startup,
> +	.shutdown	= ulite_shutdown,
> +	.set_termios	= ulite_set_termios,
> +	.type		= ulite_type,
> +	.release_port	= ulite_release_port,
> +	.request_port	= ulite_request_port,
> +	.config_port	= ulite_config_port,
> +	.verify_port	= ulite_verify_port
> +};
> +
> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
> +static void ulite_console_wait_tx(struct uart_port *port)
> +{
> +	int i;
> +
> +	/* wait up to 10ms for the character(s) to be sent */
> +	for (i=0; i<10000; i++) {
> +		if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
> +			break;
> +		udelay(1);
> +	}
> +}
> +
> +static void ulite_console_putchar(struct uart_port *port, int ch)
> +{
> +	ulite_console_wait_tx(port);
> +	writeb(ch, port->membase + ULITE_TX);
> +}
> +
> +static void ulite_console_write(struct console *co, const char *s,
> +				unsigned int count)
> +{
> +	struct uart_port *port = &ports[co->index];
> +	unsigned long flags;
> +	unsigned int ier;
> +	int locked = 1;
> +
> +	if (oops_in_progress) {
> +		locked = spin_trylock_irqsave(&port->lock, flags);
> +	} else
> +		spin_lock_irqsave(&port->lock, flags);
> +
> +	/* save and disable interrupt */
> +	ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
> +	writeb(0, port->membase + ULITE_CONTROL);
> +
> +	uart_console_write(port, s, count, ulite_console_putchar);
> +
> +	ulite_console_wait_tx(port);
> +
> +	/* restore interrupt state */
> +	if (ier)
> +		writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
> +
> +	if (locked)
> +		spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int __init ulite_console_setup(struct console *co, char *options)
> +{
> +	struct uart_port *port;
> +
> +	if (co->index < 0 || co->index >= ULITE_NR_UARTS)
> +		return -EINVAL;
> +
> +	port = &ports[co->index];
> +
> +	/* not initialized yet? */
> +	if (!port->membase)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static struct uart_driver ulite_uart_driver;
> +
> +static struct console ulite_console = {
> +	.name	= "ttyUL",
> +	.write	= ulite_console_write,
> +	.device	= uart_console_device,
> +	.setup	= ulite_console_setup,
> +	.flags	= CON_PRINTBUFFER,
> +	.index	= -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
> +	.data	= &ulite_uart_driver,
> +};
> +
> +static int __init ulite_console_init(void)
> +{
> +	register_console(&ulite_console);
> +	return 0;
> +}
> +
> +console_initcall(ulite_console_init);
> +
> +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
> +
> +static struct uart_driver ulite_uart_driver = {
> +	.owner		= THIS_MODULE,
> +	.driver_name	= "uartlite",
> +	.dev_name	= "ttyUL",
> +	.major		= ULITE_MAJOR,
> +	.minor		= ULITE_MINOR,
> +	.nr		= ULITE_NR_UARTS,
> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
> +	.cons		= &ulite_console,
> +#endif
> +};
> +
> +static int __devinit ulite_probe(struct platform_device *pdev)
> +{
> +	struct resource *res, *res2;
> +	struct uart_port *port;
> +
> +	if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
> +		return -EINVAL;
> +
> +	if (ports[pdev->id].membase)
> +		return -EBUSY;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (!res2)
> +		return -ENODEV;
> +
> +	port = &ports[pdev->id];
> +
> +	port->fifosize	= 16;
> +	port->regshift	= 2;
> +	port->iotype	= UPIO_MEM;
> +	port->iobase	= 1; /* mark port in use */
> +	port->mapbase	= res->start;
> +	port->membase	= 0;
> +	port->ops	= &ulite_ops;
> +	port->irq	= res2->start;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->dev	= &pdev->dev;
> +	port->type	= PORT_UNKNOWN;
> +
> +	uart_add_one_port(&ulite_uart_driver, port);
> +	platform_set_drvdata(pdev, port);
> +
> +	return 0;
> +}
> +
> +static int ulite_remove(struct platform_device *pdev)
> +{
> +	struct uart_port *port = platform_get_drvdata(pdev);
> +
> +	platform_set_drvdata(pdev, NULL);
> +
> +	if (port)
> +		uart_remove_one_port(&ulite_uart_driver, port);
> +
> +	/* mark port as free */
> +	port->membase = 0;
> +
> +	return 0;
> +}
> +
> +static struct platform_driver ulite_platform_driver = {
> +	.probe	= ulite_probe,
> +	.remove	= ulite_remove,
> +	.driver	= {
> +		   .owner = THIS_MODULE,
> +		   .name  = "uartlite",
> +		   },
> +};
> +
> +int __init ulite_init(void)
> +{
> +	int ret;
> +
> +	ret = uart_register_driver(&ulite_uart_driver);
> +	if (ret)
> +		return ret;
> +
> +	ret = platform_driver_register(&ulite_platform_driver);
> +	if (ret)
> +		uart_unregister_driver(&ulite_uart_driver);
> +
> +	return ret;
> +}
> +
> +void __exit ulite_exit(void)
> +{
> +	platform_driver_unregister(&ulite_platform_driver);
> +	uart_unregister_driver(&ulite_uart_driver);
> +}
> +
> +module_init(ulite_init);
> +module_exit(ulite_exit);
> +
> +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
> +MODULE_DESCRIPTION("Xilinx uartlite serial driver");
> +MODULE_LICENSE("GPL");
> diff -urpN linux-2.6.18-rc7.orig/include/linux/serial_core.h linux-2.6.18-rc7/include/linux/serial_core.h
> --- linux-2.6.18-rc7.orig/include/linux/serial_core.h	2006-09-13 15:01:25.000000000 +0200
> +++ linux-2.6.18-rc7/include/linux/serial_core.h	2006-09-13 15:01:51.000000000 +0200
> @@ -132,6 +132,8 @@
>  
>  #define PORT_S3C2412	73
>  
> +/* Xilinx uartlite */
> +#define PORT_UARTLITE	74
>  
>  #ifdef __KERNEL__
>  
> diff -urpN linux-2.6.18-rc7.orig/MAINTAINERS linux-2.6.18-rc7/MAINTAINERS
> --- linux-2.6.18-rc7.orig/MAINTAINERS	2006-09-13 15:01:20.000000000 +0200
> +++ linux-2.6.18-rc7/MAINTAINERS	2006-09-13 15:01:51.000000000 +0200
> @@ -3303,6 +3303,12 @@ W:	http://oss.sgi.com/projects/xfs
>  T:	git git://oss.sgi.com:8090/xfs/xfs-2.6
>  S:	Supported
>  
> +XILINX UARTLITE SERIAL DRIVER
> +P:	Peter Korsgaard
> +M:	jacmet@sunsite.dk
> +L:	linux-serial@vger.kernel.org
> +S:	Maintained
> +
>  X86 3-LEVEL PAGING (PAE) SUPPORT
>  P:	Ingo Molnar
>  M:	mingo@redhat.com
> 

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13  5:56     ` Peter Korsgaard
  2006-09-13 13:39       ` Peter Korsgaard
@ 2006-09-28 10:14       ` David H. Lynch Jr.
  2006-10-04 15:34         ` Peter Korsgaard
  1 sibling, 1 reply; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-09-28 10:14 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>
>  Olof> 1. There's no early boot console support for PPC. There's another
>  Olof> uartlite patch that's floating around that has this, very useful for
>  Olof> early bringup tasks. I'd like to see this expanded to include that as
>  Olof> well (the regular part of the other driver seems more or less broken
>  Olof> though, so this is a better base driver). That shouldn't stop this part
>  Olof> of the driver to go in though, just possible future work.
>   
    There is more than one UartLite driver. I have one from someone else 
that includes DCR support.
    I wrote one that includes early boot console support - which is 
fairly trivial.
    I will try to separate out my early boot console patches - would 
this be the appropriate place to post them ?
   I beleive my driver is the one Peter  believes is broken.
> True. The board I have an uartlite on also has a 8250 so it hasn't
> been an issue for me so far - But it would indeed be a nice
> addition. Adding new stuff to arch/ppc at this moment isn't that
> sensible, so perhaps it makes most sense to wait til 4xx is supported
> under arch/powerpc?
>   
       I can't quite understand why one would build a Xilinx FPGA with both.

>
>  Olof> 3. It would be useful to demonstrate how to hook up the device all the
>  Olof> way through to the board port (i.e. add a config option and include it
>  Olof> in the ml403 platform code or similar). It's not hard, but it'd make it
>  Olof> easier for whomever comes next. Of course, with 4xx hopefully soon
>  Olof> moving over to arch/powerpc, this would be taken care of through the
>  Olof> device tree instead.
>
> Yes - Afaik none of the Xilinx boards comes with uartlites
> configured so it's not usable out-of-the-box, but you can ofcause do a
> setup with the proper #ifdefs like the 8250 stuff in virtex.c.
>   
    If Peter's driver is likely to get accepted I have all of the 
platform device code done for my own driver I can move it to his.
    I did a BSP for the Pico E12/E14, they use either UartLite out of 
the box, or a pseudo serial device they call the Keyhole
    that can be used if the E12/E14 are hosted (they are CF/Cardbus 
cards respectively)



-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 15:01         ` Olof Johansson
@ 2006-09-29 19:04           ` David H. Lynch Jr.
  2006-09-29 19:57           ` David H. Lynch Jr.
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-09-29 19:04 UTC (permalink / raw)
  To: linux-serial

Olof Johansson wrote:
> On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>   
>>>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
>>>>>>>               
>>  Olof> 2. There seems to be some timeout issues with tx_empty.
>>
>>  Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
>>  Peter> back to you.
>>
>> Ahh, found it - I didn't update the uart timeout in set_termios so it
>> used a very long timeout. Please give the updated patch a try.
>>     
>
> Looks good. Thanks.
>   

Peter;
    You force the port regshift value to 2 in your init code, but then
you ignore it and hard code the register offsets preshifted.
    I have never actually seen a UartLite implimentation with a shift
other than 2. But I have seen BSP's for other OS's with UartLites defaulting
    to a shift of 0. I am not an FPGA firmware guy, but I beleive you
can build them that way.
    Also there is no provision for running the UartLite without using
interrupts.
    The Pico E12/E14 frequently use FPGA firmare that does not include a
PIC.
     Some implimentations of the UartLite use dcr instead of memory
mapped ports.
   

>   
>> Additional changes:
>> - Actually add the fixes I did in May on request of Russell
>> - Update for 2.6.18 (devfs and new IRQF defines)
>> - Removed the SERIAL_UARTLITE_NR_UARTS config option as we only have 4
>>   minors reserved with lanana anyway.
>>
>> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
>>     
>
> Acked-by: Olof Johansson <olof@lixom.net>
>
>   
>> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Kconfig linux-2.6.18-rc7/drivers/serial/Kconfig
>> --- linux-2.6.18-rc7.orig/drivers/serial/Kconfig	2006-09-13 15:01:24.000000000 +0200
>> +++ linux-2.6.18-rc7/drivers/serial/Kconfig	2006-09-13 15:01:51.000000000 +0200
>> @@ -511,6 +511,25 @@ config SERIAL_IMX_CONSOLE
>>  	  your boot loader (lilo or loadlin) about how to pass options to the
>>  	  kernel at boot time.)
>>  
>> +config SERIAL_UARTLITE
>> +	tristate "Xilinx uartlite serial port support"
>> +	depends on PPC32
>> +	select SERIAL_CORE
>> +	help
>> +	  Say Y here if you want to use the Xilinx uartlite serial controller.
>> +
>> +	  To compile this driver as a module, choose M here: the
>> +	  module will be called uartlite.ko.
>> +
>> +config SERIAL_UARTLITE_CONSOLE
>> +	bool "Support for console on Xilinx uartlite serial port"
>> +	depends on SERIAL_UARTLITE=y
>> +	select SERIAL_CORE_CONSOLE
>> +	help
>> +	  Say Y here if you wish to use a Xilinx uartlite as the system
>> +	  console (the system console is the device which receives all kernel
>> +	  messages and warnings and which allows logins in single user mode).
>> +
>>  config SERIAL_SUNCORE
>>  	bool
>>  	depends on SPARC
>> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/Makefile linux-2.6.18-rc7/drivers/serial/Makefile
>> --- linux-2.6.18-rc7.orig/drivers/serial/Makefile	2006-09-13 15:01:24.000000000 +0200
>> +++ linux-2.6.18-rc7/drivers/serial/Makefile	2006-09-13 15:01:51.000000000 +0200
>> @@ -55,4 +55,5 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_si
>>  obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
>>  obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
>>  obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
>> +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
>>  obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
>> diff -urpN linux-2.6.18-rc7.orig/drivers/serial/uartlite.c linux-2.6.18-rc7/drivers/serial/uartlite.c
>> --- linux-2.6.18-rc7.orig/drivers/serial/uartlite.c	1970-01-01 01:00:00.000000000 +0100
>> +++ linux-2.6.18-rc7/drivers/serial/uartlite.c	2006-09-13 15:01:51.000000000 +0200
>> @@ -0,0 +1,496 @@
>> +/*
>> + * uartlite.c: Serial driver for Xilinx uartlite serial controller
>> + *
>> + * Peter Korsgaard <jacmet@sunsite.dk>
>> + *
>> + * 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/platform_device.h>
>> +#include <linux/module.h>
>> +#include <linux/console.h>
>> +#include <linux/serial.h>
>> +#include <linux/serial_core.h>
>> +#include <linux/tty.h>
>> +#include <linux/delay.h>
>> +#include <linux/interrupt.h>
>> +#include <asm/io.h>
>> +
>> +#define ULITE_MAJOR		204
>> +#define ULITE_MINOR		187
>> +#define ULITE_NR_UARTS		4
>> +
>> +/* For register details see datasheet:
>> +   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
>> +*/
>> +#define ULITE_RX		0x00
>> +#define ULITE_TX		0x04
>> +#define ULITE_STATUS		0x08
>> +#define ULITE_CONTROL		0x0c
>> +
>> +#define ULITE_REGION		16
>> +
>> +#define ULITE_STATUS_RXVALID	0x01
>> +#define ULITE_STATUS_RXFULL	0x02
>> +#define ULITE_STATUS_TXEMPTY	0x04
>> +#define ULITE_STATUS_TXFULL	0x08
>> +#define ULITE_STATUS_IE		0x10
>> +#define ULITE_STATUS_OVERRUN	0x20
>> +#define ULITE_STATUS_FRAME	0x40
>> +#define ULITE_STATUS_PARITY	0x80
>> +
>> +#define ULITE_CONTROL_RST_TX	0x01
>> +#define ULITE_CONTROL_RST_RX	0x02
>> +#define ULITE_CONTROL_IE	0x10
>> +
>> +
>> +static struct uart_port ports[ULITE_NR_UARTS];
>> +
>> +static int ulite_receive(struct uart_port *port, int stat)
>> +{
>> +	struct tty_struct *tty = port->info->tty;
>> +	unsigned char ch = 0;
>> +	char flag = TTY_NORMAL;
>> +
>> +	if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
>> +		     | ULITE_STATUS_FRAME)) == 0)
>> +		return 0;
>> +
>> +	/* stats */
>> +	if (stat & ULITE_STATUS_RXVALID) {
>> +		port->icount.rx++;
>> +		ch = readb(port->membase + ULITE_RX);
>> +
>> +		if (stat & ULITE_STATUS_PARITY)
>> +			port->icount.parity++;
>> +	}
>> +
>> +	if (stat & ULITE_STATUS_OVERRUN)
>> +		port->icount.overrun++;
>> +
>> +	if (stat & ULITE_STATUS_FRAME)
>> +		port->icount.frame++;
>> +
>> +
>> +	/* drop byte with parity error if IGNPAR specificed */
>> +	if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
>> +		stat &= ~ULITE_STATUS_RXVALID;
>> +
>> +	stat &= port->read_status_mask;
>> +
>> +	if (stat & ULITE_STATUS_PARITY)
>> +		flag = TTY_PARITY;
>> +
>> +
>> +	stat &= ~port->ignore_status_mask;
>> +
>> +	if (stat & ULITE_STATUS_RXVALID)
>> +		tty_insert_flip_char(tty, ch, flag);
>> +
>> +	if (stat & ULITE_STATUS_FRAME)
>> +		tty_insert_flip_char(tty, 0, TTY_FRAME);
>> +
>> +	if (stat & ULITE_STATUS_OVERRUN)
>> +		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
>> +
>> +	return 1;
>> +}
>> +
>> +static int ulite_transmit(struct uart_port *port, int stat)
>> +{
>> +	struct circ_buf *xmit  = &port->info->xmit;
>> +
>> +	if (stat & ULITE_STATUS_TXFULL)
>> +		return 0;
>> +
>> +	if (port->x_char) {
>> +		writeb(port->x_char, port->membase + ULITE_TX);
>> +		port->x_char = 0;
>> +		port->icount.tx++;
>> +		return 1;
>> +	}
>> +
>> +	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
>> +		return 0;
>> +
>> +	writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX);
>> +	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
>> +	port->icount.tx++;
>> +
>> +	/* wake up */
>> +	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
>> +		uart_write_wakeup(port);
>> +
>> +	return 1;
>> +}
>> +
>> +static irqreturn_t ulite_isr(int irq, void *dev_id, struct pt_regs *regs)
>> +{
>> +	struct uart_port *port = (struct uart_port *)dev_id;
>> +	int busy;
>> +
>> +	do {
>> +		int stat = readb(port->membase + ULITE_STATUS);
>> +		busy  = ulite_receive(port, stat);
>> +		busy |= ulite_transmit(port, stat);
>> +	} while (busy);
>> +
>> +	tty_flip_buffer_push(port->info->tty);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static unsigned int ulite_tx_empty(struct uart_port *port)
>> +{
>> +	unsigned long flags;
>> +	unsigned int ret;
>> +
>> +	spin_lock_irqsave(&port->lock, flags);
>> +	ret = readb(port->membase + ULITE_STATUS);
>> +	spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +	return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
>> +}
>> +
>> +static unsigned int ulite_get_mctrl(struct uart_port *port)
>> +{
>> +	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
>> +}
>> +
>> +static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl)
>> +{
>> +	/* N/A */
>> +}
>> +
>> +static void ulite_stop_tx(struct uart_port *port)
>> +{
>> +	/* N/A */
>> +}
>> +
>> +static void ulite_start_tx(struct uart_port *port)
>> +{
>> +	ulite_transmit(port, readb(port->membase + ULITE_STATUS));
>> +}
>> +
>> +static void ulite_stop_rx(struct uart_port *port)
>> +{
>> +	/* don't forward any more data (like !CREAD) */
>> +	port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
>> +		| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
>> +}
>> +
>> +static void ulite_enable_ms(struct uart_port *port)
>> +{
>> +	/* N/A */
>> +}
>> +
>> +static void ulite_break_ctl(struct uart_port *port, int ctl)
>> +{
>> +	/* N/A */
>> +}
>> +
>> +static int ulite_startup(struct uart_port *port)
>> +{
>> +	int ret;
>> +
>> +	ret = request_irq(port->irq, ulite_isr,
>> +			  IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "uartlite", port);
>> +	if (ret)
>> +		return ret;
>> +
>> +	writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
>> +	       port->membase + ULITE_CONTROL);
>> +	writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
>> +
>> +	return 0;
>> +}
>> +
>> +static void ulite_shutdown(struct uart_port *port)
>> +{
>> +	writeb(0, port->membase + ULITE_CONTROL);
>> +	free_irq(port->irq, port);
>> +}
>> +
>> +static void ulite_set_termios(struct uart_port *port, struct termios *termios,
>> +			      struct termios *old)
>> +{
>> +	unsigned long flags;
>> +	unsigned int baud;
>> +
>> +	spin_lock_irqsave(&port->lock, flags);
>> +
>> +	port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
>> +		| ULITE_STATUS_TXFULL;
>> +
>> +	if (termios->c_iflag & INPCK)
>> +		port->read_status_mask |=
>> +			ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
>> +
>> +	port->ignore_status_mask = 0;
>> +	if (termios->c_iflag & IGNPAR)
>> +		port->ignore_status_mask |= ULITE_STATUS_PARITY
>> +			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
>> +
>> +	/* ignore all characters if CREAD is not set */
>> +	if ((termios->c_cflag & CREAD) == 0)
>> +		port->ignore_status_mask |=
>> +			ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
>> +			| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
>> +
>> +	/* update timeout */
>> +	baud = uart_get_baud_rate(port, termios, old, 0, 460800);
>> +	uart_update_timeout(port, termios->c_cflag, baud);
>> +
>> +	spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
>> +static const char *ulite_type(struct uart_port *port)
>> +{
>> +	return port->type == PORT_UARTLITE ? "uartlite" : NULL;
>> +}
>> +
>> +static void ulite_release_port(struct uart_port *port)
>> +{
>> +	release_mem_region(port->mapbase, ULITE_REGION);
>> +	iounmap(port->membase);
>> +	port->membase = 0;
>> +}
>> +
>> +static int ulite_request_port(struct uart_port *port)
>> +{
>> +	if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
>> +		dev_err(port->dev, "Memory region busy\n");
>> +		return -EBUSY;
>> +	}
>> +
>> +	port->membase = ioremap(port->mapbase, ULITE_REGION);
>> +	if (!port->membase) {
>> +		dev_err(port->dev, "Unable to map registers\n");
>> +		release_mem_region(port->mapbase, ULITE_REGION);
>> +		return -EBUSY;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void ulite_config_port(struct uart_port *port, int flags)
>> +{
>> +	ulite_request_port(port);
>> +	port->type = PORT_UARTLITE;
>> +}
>> +
>> +static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
>> +{
>> +	/* we don't want the core code to modify any port params */
>> +	return -EINVAL;
>> +}
>> +
>> +static struct uart_ops ulite_ops = {
>> +	.tx_empty	= ulite_tx_empty,
>> +	.set_mctrl	= ulite_set_mctrl,
>> +	.get_mctrl	= ulite_get_mctrl,
>> +	.stop_tx	= ulite_stop_tx,
>> +	.start_tx	= ulite_start_tx,
>> +	.stop_rx	= ulite_stop_rx,
>> +	.enable_ms	= ulite_enable_ms,
>> +	.break_ctl	= ulite_break_ctl,
>> +	.startup	= ulite_startup,
>> +	.shutdown	= ulite_shutdown,
>> +	.set_termios	= ulite_set_termios,
>> +	.type		= ulite_type,
>> +	.release_port	= ulite_release_port,
>> +	.request_port	= ulite_request_port,
>> +	.config_port	= ulite_config_port,
>> +	.verify_port	= ulite_verify_port
>> +};
>> +
>> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
>> +static void ulite_console_wait_tx(struct uart_port *port)
>> +{
>> +	int i;
>> +
>> +	/* wait up to 10ms for the character(s) to be sent */
>> +	for (i=0; i<10000; i++) {
>> +		if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
>> +			break;
>> +		udelay(1);
>> +	}
>> +}
>> +
>> +static void ulite_console_putchar(struct uart_port *port, int ch)
>> +{
>> +	ulite_console_wait_tx(port);
>> +	writeb(ch, port->membase + ULITE_TX);
>> +}
>> +
>> +static void ulite_console_write(struct console *co, const char *s,
>> +				unsigned int count)
>> +{
>> +	struct uart_port *port = &ports[co->index];
>> +	unsigned long flags;
>> +	unsigned int ier;
>> +	int locked = 1;
>> +
>> +	if (oops_in_progress) {
>> +		locked = spin_trylock_irqsave(&port->lock, flags);
>> +	} else
>> +		spin_lock_irqsave(&port->lock, flags);
>> +
>> +	/* save and disable interrupt */
>> +	ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
>> +	writeb(0, port->membase + ULITE_CONTROL);
>> +
>> +	uart_console_write(port, s, count, ulite_console_putchar);
>> +
>> +	ulite_console_wait_tx(port);
>> +
>> +	/* restore interrupt state */
>> +	if (ier)
>> +		writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
>> +
>> +	if (locked)
>> +		spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
>> +static int __init ulite_console_setup(struct console *co, char *options)
>> +{
>> +	struct uart_port *port;
>> +
>> +	if (co->index < 0 || co->index >= ULITE_NR_UARTS)
>> +		return -EINVAL;
>> +
>> +	port = &ports[co->index];
>> +
>> +	/* not initialized yet? */
>> +	if (!port->membase)
>> +		return -ENODEV;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct uart_driver ulite_uart_driver;
>> +
>> +static struct console ulite_console = {
>> +	.name	= "ttyUL",
>> +	.write	= ulite_console_write,
>> +	.device	= uart_console_device,
>> +	.setup	= ulite_console_setup,
>> +	.flags	= CON_PRINTBUFFER,
>> +	.index	= -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */
>> +	.data	= &ulite_uart_driver,
>> +};
>> +
>> +static int __init ulite_console_init(void)
>> +{
>> +	register_console(&ulite_console);
>> +	return 0;
>> +}
>> +
>> +console_initcall(ulite_console_init);
>> +
>> +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
>> +
>> +static struct uart_driver ulite_uart_driver = {
>> +	.owner		= THIS_MODULE,
>> +	.driver_name	= "uartlite",
>> +	.dev_name	= "ttyUL",
>> +	.major		= ULITE_MAJOR,
>> +	.minor		= ULITE_MINOR,
>> +	.nr		= ULITE_NR_UARTS,
>> +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
>> +	.cons		= &ulite_console,
>> +#endif
>> +};
>> +
>> +static int __devinit ulite_probe(struct platform_device *pdev)
>> +{
>> +	struct resource *res, *res2;
>> +	struct uart_port *port;
>> +
>> +	if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
>> +		return -EINVAL;
>> +
>> +	if (ports[pdev->id].membase)
>> +		return -EBUSY;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!res)
>> +		return -ENODEV;
>> +
>> +	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +	if (!res2)
>> +		return -ENODEV;
>> +
>> +	port = &ports[pdev->id];
>> +
>> +	port->fifosize	= 16;
>> +	port->regshift	= 2;
>> +	port->iotype	= UPIO_MEM;
>> +	port->iobase	= 1; /* mark port in use */
>> +	port->mapbase	= res->start;
>> +	port->membase	= 0;
>> +	port->ops	= &ulite_ops;
>> +	port->irq	= res2->start;
>> +	port->flags	= UPF_BOOT_AUTOCONF;
>> +	port->dev	= &pdev->dev;
>> +	port->type	= PORT_UNKNOWN;
>> +
>> +	uart_add_one_port(&ulite_uart_driver, port);
>> +	platform_set_drvdata(pdev, port);
>> +
>> +	return 0;
>> +}
>> +
>> +static int ulite_remove(struct platform_device *pdev)
>> +{
>> +	struct uart_port *port = platform_get_drvdata(pdev);
>> +
>> +	platform_set_drvdata(pdev, NULL);
>> +
>> +	if (port)
>> +		uart_remove_one_port(&ulite_uart_driver, port);
>> +
>> +	/* mark port as free */
>> +	port->membase = 0;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver ulite_platform_driver = {
>> +	.probe	= ulite_probe,
>> +	.remove	= ulite_remove,
>> +	.driver	= {
>> +		   .owner = THIS_MODULE,
>> +		   .name  = "uartlite",
>> +		   },
>> +};
>> +
>> +int __init ulite_init(void)
>> +{
>> +	int ret;
>> +
>> +	ret = uart_register_driver(&ulite_uart_driver);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = platform_driver_register(&ulite_platform_driver);
>> +	if (ret)
>> +		uart_unregister_driver(&ulite_uart_driver);
>> +
>> +	return ret;
>> +}
>> +
>> +void __exit ulite_exit(void)
>> +{
>> +	platform_driver_unregister(&ulite_platform_driver);
>> +	uart_unregister_driver(&ulite_uart_driver);
>> +}
>> +
>> +module_init(ulite_init);
>> +module_exit(ulite_exit);
>> +
>> +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
>> +MODULE_DESCRIPTION("Xilinx uartlite serial driver");
>> +MODULE_LICENSE("GPL");
>> diff -urpN linux-2.6.18-rc7.orig/include/linux/serial_core.h linux-2.6.18-rc7/include/linux/serial_core.h
>> --- linux-2.6.18-rc7.orig/include/linux/serial_core.h	2006-09-13 15:01:25.000000000 +0200
>> +++ linux-2.6.18-rc7/include/linux/serial_core.h	2006-09-13 15:01:51.000000000 +0200
>> @@ -132,6 +132,8 @@
>>  
>>  #define PORT_S3C2412	73
>>  
>> +/* Xilinx uartlite */
>> +#define PORT_UARTLITE	74
>>  
>>  #ifdef __KERNEL__
>>  
>> diff -urpN linux-2.6.18-rc7.orig/MAINTAINERS linux-2.6.18-rc7/MAINTAINERS
>> --- linux-2.6.18-rc7.orig/MAINTAINERS	2006-09-13 15:01:20.000000000 +0200
>> +++ linux-2.6.18-rc7/MAINTAINERS	2006-09-13 15:01:51.000000000 +0200
>> @@ -3303,6 +3303,12 @@ W:	http://oss.sgi.com/projects/xfs
>>  T:	git git://oss.sgi.com:8090/xfs/xfs-2.6
>>  S:	Supported
>>  
>> +XILINX UARTLITE SERIAL DRIVER
>> +P:	Peter Korsgaard
>> +M:	jacmet@sunsite.dk
>> +L:	linux-serial@vger.kernel.org
>> +S:	Maintained
>> +
>>  X86 3-LEVEL PAGING (PAE) SUPPORT
>>  P:	Ingo Molnar
>>  M:	mingo@redhat.com
>>
>>     
> -
> To unsubscribe from this list: send the line "unsubscribe linux-serial" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>   


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 15:01         ` Olof Johansson
  2006-09-29 19:04           ` David H. Lynch Jr.
@ 2006-09-29 19:57           ` David H. Lynch Jr.
  2006-10-04 15:45             ` Peter Korsgaard
  2006-09-30  9:25           ` David H. Lynch Jr.
                             ` (2 subsequent siblings)
  4 siblings, 1 reply; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-09-29 19:57 UTC (permalink / raw)
  To: linux-serial, jacmet

Olof Johansson wrote:
> On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>   
>>>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
>>>>>>>               
>>  Olof> 2. There seems to be some timeout issues with tx_empty.
>>
>>  Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
>>  Peter> back to you.
>>
>> Ahh, found it - I didn't update the uart timeout in set_termios so it
>> used a very long timeout. Please give the updated patch a try.
>>     
>
> Looks good. Thanks.
>   

Peter;
	I am trying to switch from my driver to yours - as it appears yours is
on the way to getting accepted.
	
	I have been dropping my issues/comments as I go onto the list as I
encounter problems.


	You need an "early_serial_setup()" routine inside the
CONFIG_SERIAL_UARTLITE_CONSOLE code.


#if defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
int __init
early_serial_setup(struct uart_port *port)
{
	
	if (port->line >= ARRAY_SIZE(ulite_ports))
		return -ENODEV;

	ulite_init_ports();
	ulite_ports[port->line].port	= *port;
	ulite_ports[port->line].port.ops	= &ulite_pops;
	return 0;
}
#endif

ulite_init_ports() loops through all the ports in ulite_ports and sets
up the port data - similiar to your code in ulite_probe().




-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too
numerous to list.

"Any intelligent fool can make things bigger and more complex... It
takes a touch of genius - and a lot of courage to move in the opposite
direction."
Albert Einstein



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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 15:01         ` Olof Johansson
  2006-09-29 19:04           ` David H. Lynch Jr.
  2006-09-29 19:57           ` David H. Lynch Jr.
@ 2006-09-30  9:25           ` David H. Lynch Jr.
  2006-10-04 16:01             ` Peter Korsgaard
  2006-10-03 10:27           ` David H. Lynch Jr.
       [not found]           ` <451CDA3D.2060109@dlasys.net>
  4 siblings, 1 reply; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-09-30  9:25 UTC (permalink / raw)
  To: linux-serial, jacmet

Olof Johansson wrote:
> On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>   
>>>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
>>>>>>>               
>>  Olof> 2. There seems to be some timeout issues with tx_empty.
>>
>>  Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
>>  Peter> back to you.
>>
>> Ahh, found it - I didn't update the uart timeout in set_termios so it
>> used a very long timeout. Please give the updated patch a try.
>>     
>
> Looks good. Thanks.
>   

Peter;
	
	I have been working to move from my UartLite driver to yours.

	Aside from the missing early_serial_setup() routine which was fairly
easy to add, as well as adding a timer to poll IO to keep things working
if there was no UartLite interrupt, I have encounter a few other issues.

	Your ulite_console_write performance is pretty slow - almost an order
of magnitude slower than what I am seeing in my driver. I beleive it is
because you are waiting for the Tx FIFO to be empty before and after
sending each character rather than only waiting while the Tx FIFO is full.

	That may also be an issue in the rest of the driver but I have been
unable to get it to through registering the driver.
	I suspect that is because your driver is a platform driver, but you did
not provide patches to the arch/ppc/platforms/4xx/virtex.* or
xilinx_ml???.* to setup the platform device structure.
	If you could provide a copy I would appreciate it.
	
	



-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too
numerous to list.

"Any intelligent fool can make things bigger and more complex... It
takes a touch of genius - and a lot of courage to move in the opposite
direction."
Albert Einstein




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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 15:01         ` Olof Johansson
                             ` (2 preceding siblings ...)
  2006-09-30  9:25           ` David H. Lynch Jr.
@ 2006-10-03 10:27           ` David H. Lynch Jr.
       [not found]           ` <451CDA3D.2060109@dlasys.net>
  4 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-03 10:27 UTC (permalink / raw)
  To: linux-serial, jacmet

Olof Johansson wrote:
> On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>   
>>>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
>>>>>>>               
>>  Olof> 2. There seems to be some timeout issues with tx_empty.
>>
>>  Peter> Huh, that's odd - I haven't noticed that. I'll test it again and get
>>  Peter> back to you.
>>
>> Ahh, found it - I didn't update the uart timeout in set_termios so it
>> used a very long timeout. Please give the updated patch a try.
>>     
>
> Looks good. Thanks.
>   

Peter;

	I spent the better part of the past 4 days trying to move to your driver.
	
	The ulite_console_write() performance issue seems to be related to
using uart_console_write() to output the string. I can recreate the
problem - though not quite as bad, in my own driver by using that
instead of a simple internal puts(). It is possible that some paramater
or something needs tweeked somewhere to make uart_console_write()
perform better. That is beyond my current knowledge. I would hope there
is something because it appears serial console drivers are to be using
uart_console_write(), and I have seen tty's run faster than what I get
with it.

	I am supporting the Pico E series of boards. They frequently do not
have a PIC and therefor no serial interupts. Your driver does not have
any support for running polled, and adding working polling was less than
trivial. That is critical for my environment.

	I was having sufficient problems, I reverted to your base driver
without any of my own patches and tried to get it working using an E12
with interrupt support.
	Once your driver switched from the ulite_console output to fully up and
interrupt driven, it started dropping characters all over.
	I was never able to get any permutation of your driver to accept input.
	The missing early_serial_setup(struct uart_port*) routine I mentioned
earlier, seems to be somewhat less critical than I thought.
providing a completely empty stub seems to keep make happy and as best
as I can tell works.
	That said numerous ppc, mips, and a few other boards call
early_serial_setup() either for KGDB support or for early console text
support - passing a uart_port structure. Typically this only for 8250's
or the few other serial ports with boot to bash serial support. But I
have code to provide boot-bash UartLite support.
	This raises another issue. Your driver pulls memory and irq information
from platform device structures using IORESOURCE_MEM and IORESOURCE_IRQ
- perfectly resonable, but most of the 8250 based systems - particularly
the XILINX ml300, and ml403 have a uart_port structure embedded in their
platform data instead, and that is consistent with what
early_serial_setup() passes to the driver. A quick grep of
drivers/serial seemed to indicate no consistency passing configuration
data. But boot-bash serial IO will be easier if you follow the pattern
used for the 8250 in the Xilinx ml300/ml403.

	Finally, for boot-bash serial support it makes sense to extract the
register/bit defines into a separate include/linux/serial_uartlite.h
as there will be other code that uses them. I deliberately chose to name
all the values exactly as the 8250 defines - even thought I do not like
some of the names, UART_LSR_THRE means the same thing in every driver I
deal with wither it is an 8250, UartLite, Keyhole or even in another OS.
But that is personal preference.

	Eventually, I gave up and reverted back to my own driver. Patching
yours for early serial, tracking down the input problem, the output
problem, and adding polling was a larger undertaking, considering I have
a driver that works for me. Your driver did provoke me to check
my own in a pure interrupt driven environment and I have a problem of
my own their I need to fix.

	
	





-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too
numerous to list.

"Any intelligent fool can make things bigger and more complex... It
takes a touch of genius - and a lot of courage to move in the opposite
direction."
Albert Einstein



-
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-28 10:14       ` David H. Lynch Jr.
@ 2006-10-04 15:34         ` Peter Korsgaard
  0 siblings, 0 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-04 15:34 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-serial

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

Sorry for the delay, I've been ill..

 David>    There is more than one UartLite driver. I have one from someone
 David> else that includes DCR support.
 David>    I wrote one that includes early boot console support - which is
 David> fairly trivial.

Yes, I know (after writing mine). That's why getting the driver
mainline is important, otherwise people will keep on reinventing the
wheel..

 David>    I will try to separate out my early boot console patches - would
 David> this be the appropriate place to post them ?

Yes, presumably once the base driver goes in.

 David>   I beleive my driver is the one Peter  believes is broken.

Me? I don't even think I ever tried your driver..

 David>       I can't quite understand why one would build a Xilinx FPGA with both.

We have done it several times. 16550s for when you need full
functionality (changeable baudrate, control lines, ..) and uartlites
for dedicated links.

 David>    If Peter's driver is likely to get accepted I have all of the
 David> platform device code done for my own driver I can move it to his.
 David>    I did a BSP for the Pico E12/E14, they use either UartLite out of
 David> the box, or a pseudo serial device they call the Keyhole
 David>    that can be used if the E12/E14 are hosted (they are CF/Cardbus
 David> cards respectively)

Ok, but where would you add it? The ML300/403 boards are afaik the
only ones in mainline.

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
       [not found]           ` <451CDA3D.2060109@dlasys.net>
@ 2006-10-04 15:41             ` Peter Korsgaard
  2006-10-06  4:13               ` David H. Lynch Jr.
                                 ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-04 15:41 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-serial

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

Hi,

 David>     You force the port regshift value to 2 in your init code,
 David> but then you ignore it and hard code the register offsets
 David> preshifted.

Yes, the regshift value is not used by the driver, I just kept the
initialization as documentation. The Xilinx IP block afaik cannot be
configured with a different regshift value than 2, so I hardcoded
it.

We can change that if it would ever be a problem, but there's
unfortunately no clean way of representing this in the
device/ressource data, so I would prefer to leave that out unless it's
needed.

 David> Also there is no provision for running the UartLite without
 David> using interrupts.  The Pico E12/E14 frequently use FPGA
 David> firmare that does not include a PIC.  Some implimentations of
 David> the UartLite use dcr instead of memory mapped ports.
   
No - again like the early serial stuff that's something that can be
added once the base driver is mainlined if there's demand.

Does polling even work decently with the small fifo size of the
uartlite?

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-29 19:57           ` David H. Lynch Jr.
@ 2006-10-04 15:45             ` Peter Korsgaard
  2006-10-06  4:14               ` David H. Lynch Jr.
  0 siblings, 1 reply; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-04 15:45 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-serial

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

Hi,

 David> 	You need an "early_serial_setup()" routine inside the
 David> CONFIG_SERIAL_UARTLITE_CONSOLE code.

Isn't that just for early serial support?

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-30  9:25           ` David H. Lynch Jr.
@ 2006-10-04 16:01             ` Peter Korsgaard
  2006-10-06  4:15               ` David H. Lynch Jr.
  0 siblings, 1 reply; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-04 16:01 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-serial

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

Hi,

 David> 	Your ulite_console_write performance is pretty slow -
 David> almost an order of magnitude slower than what I am seeing in
 David> my driver. I beleive it is because you are waiting for the Tx
 David> FIFO to be empty before and after sending each character
 David> rather than only waiting while the Tx FIFO is full.

Really? The implementation is basically a copy of 8250.c, so I would
imagine that would get similar performance. Perhaps it's related to
your specific setup?

The driver only waits before sending a character, not afterwards.

 David> 	That may also be an issue in the rest of the driver but I have been
 David> unable to get it to through registering the driver.
 David> 	I suspect that is because your driver is a platform driver, but you did
 David> not provide patches to the arch/ppc/platforms/4xx/virtex.* or
 David> xilinx_ml???.* to setup the platform device structure.

No, because the Xilinx boards don't have any uartlite devices.

 David> 	If you could provide a copy I would appreciate it.

Sure, just add something like this to your board code (with your base
address/irq ofcause):
	
static struct resource uartlite_resources[] = {
       [0] = {
           .start  = 0xa1000003,
           .end    = 0xa1000012,
           .flags  = IORESOURCE_MEM,
       },
       [1] = {
           .start  = 2,
           .end    = 2,
           .flags  = IORESOURCE_IRQ,
       },
};

static struct platform_device uartlite = {
       .name              = "uartlite",
       .id                = 0,
       .num_resources     = ARRAY_SIZE(uartlite_resources),
       .resource          = uartlite_resources,
       .dev.platform_data = 0,
};

static struct platform_device *my_devices[] __initdata = {
       &uartlite,
       .
       .
       .
};

static int __init
my_platform_add_devices(void)
{
        return platform_add_devices(my_devices, ARRAY_SIZE(my_devices));

}

arch_initcall(my_platform_add_devices);

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-04 15:41             ` Peter Korsgaard
@ 2006-10-06  4:13               ` David H. Lynch Jr.
  2006-10-06  4:14               ` David H. Lynch Jr.
  2006-10-06  4:14               ` David H. Lynch Jr.
  2 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-06  4:13 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>  David>     You force the port regshift value to 2 in your init code,
>  David> but then you ignore it and hard code the register offsets
>  David> preshifted.
>
> Yes, the regshift value is not used by the driver, I just kept the
> initialization as documentation. The Xilinx IP block afaik cannot be
> configured with a different regshift value than 2, so I hardcoded
> it.
>
> We can change that if it would ever be a problem, but there's
> unfortunately no clean way of representing this in the
> device/ressource data, so I would prefer to leave that out unless it's
> needed.
>   
    That is actually one of my more major issues. I am NOT the right 
person to speak for what direction things are going.
    But the majority of drivers - platform device based or otherwise, 
pass arround a uart_port structure with the irq, addresses, etc.
    the uart_port struct has provisions for a regshift - as well as 
other things.

    DCR is another issue. I have never personally seen a UartLite DCR 
implimentation, but I have a driver from somebody else that started from 
mine, that assumes
    DCR instead of memory mapped ports. I think the Xilinx Gigabit 
Reference System Design connects the UartLite via DCR.
   
    I think DCR has to be a consideration. I do not KNOW that there is a 
UartLite implimentation with a regshift other than 2.
    But I have seen occasional code that uses different values - The 
GreenHills Integrity UartLite driver
    has it as a configurable parameter.

 

     If your driver is going to become the officail UartLite driver, 
even if it does not already work with every UartLite implimentation, it 
still should not start with assumptions that
    are going to make supporting others difficult.
   
      Given:

         1). a resolution to the configuration issues - reconciling the 
IORESOURCE_MEM/IRQ stuff with the uart_port passing of 
early_serial_setup() and other drivers, as well as passing
    additional parameters such as a dcr option and a regshift - and I am 
NOT claiming to know that answer, only recognizing there is an issue.

         2). figuring out why your driver drops outbound characters and 
fails to receive anything on my hardware.

    I would be happy to provide patches to your driver to deal with the 
regshift issue, the early serial issue, and operating polled without an 
IRQ - the latter of which is critical atleast for my board,
    or you can pull them out of the patch I posted on linuxppc-embedded 
in January,
    or I will send you a current copy

    But I spent 4 days trying to find just the dropped xmit character 
problem, without success. My driver works on my hardware doing polled IO 
- whether the firmware supports interrupts or not, and  I the stock 
GreenHills integrity driver works interrupt driven on my hardware (with 
interrupt enabled firmware).

    I would like to see a driver get into the kernel distribution that 
has boot-bash serial support, and polled IO, and works on my hardware.
    And I will provide my code as a resource and whatever time I can 
come up with to help get that.
   
    But anything less requires me to yank whatever is in the kernel and 
replace it with my driver.
    I have a real production board, with live clients, that uses the 
UartLite as the sole serial device, one way or another I have to have 
something that works for me.

    Interrupt driven support, DCR, and regshift support are extras - but 
I am sure they matter to someone else.

>  David> Also there is no provision for running the UartLite without
>  David> using interrupts.  The Pico E12/E14 frequently use FPGA
>  David> firmare that does not include a PIC.  Some implimentations of
>  David> the UartLite use dcr instead of memory mapped ports.
>    
> No - again like the early serial stuff that's something that can be
> added once the base driver is mainlined if there's demand.
>
> Does polling even work decently with the small fifo size of the
> uartlite?
>
>   


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-04 15:41             ` Peter Korsgaard
  2006-10-06  4:13               ` David H. Lynch Jr.
@ 2006-10-06  4:14               ` David H. Lynch Jr.
  2006-10-06  4:14               ` David H. Lynch Jr.
  2 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-06  4:14 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>  David>     You force the port regshift value to 2 in your init code,
>  David> but then you ignore it and hard code the register offsets
>  David> preshifted.
>
> Yes, the regshift value is not used by the driver, I just kept the
> initialization as documentation. The Xilinx IP block afaik cannot be
> configured with a different regshift value than 2, so I hardcoded
> it.
>
> We can change that if it would ever be a problem, but there's
> unfortunately no clean way of representing this in the
> device/ressource data, so I would prefer to leave that out unless it's
> needed.
>   
    That is actually one of my more major issues. I am NOT the right 
person to speak for what direction things are going.
    But the majority of drivers - platform device based or otherwise, 
pass arround a uart_port structure with the irq, addresses, etc.
    the uart_port struct has provisions for a regshift - as well as 
other things.

    DCR is another issue. I have never personally seen a UartLite DCR 
implimentation, but I have a driver from somebody else that started from 
mine, that assumes
    DCR instead of memory mapped ports. I think the Xilinx Gigabit 
Reference System Design connects the UartLite via DCR.
   
    I think DCR has to be a consideration. I do not KNOW that there is a 
UartLite implimentation with a regshift other than 2.
    But I have seen occasional code that uses different values - The 
GreenHills Integrity UartLite driver
    has it as a configurable parameter.

 

     If your driver is going to become the officail UartLite driver, 
even if it does not already work with every UartLite implimentation, it 
still should not start with assumptions that
    are going to make supporting others difficult.
   
      Given:

         1). a resolution to the configuration issues - reconciling the 
IORESOURCE_MEM/IRQ stuff with the uart_port passing of 
early_serial_setup() and other drivers, as well as passing
    additional parameters such as a dcr option and a regshift - and I am 
NOT claiming to know that answer, only recognizing there is an issue.

         2). figuring out why your driver drops outbound characters and 
fails to receive anything on my hardware.

    I would be happy to provide patches to your driver to deal with the 
regshift issue, the early serial issue, and operating polled without an 
IRQ - the latter of which is critical atleast for my board,
    or you can pull them out of the patch I posted on linuxppc-embedded 
in January,
    or I will send you a current copy

    But I spent 4 days trying to find just the dropped xmit character 
problem, without success. My driver works on my hardware doing polled IO 
- whether the firmware supports interrupts or not, and  I the stock 
GreenHills integrity driver works interrupt driven on my hardware (with 
interrupt enabled firmware).

    I would like to see a driver get into the kernel distribution that 
has boot-bash serial support, and polled IO, and works on my hardware.
    And I will provide my code as a resource and whatever time I can 
come up with to help get that.
   
    But anything less requires me to yank whatever is in the kernel and 
replace it with my driver.
    I have a real production board, with live clients, that uses the 
UartLite as the sole serial device, one way or another I have to have 
something that works for me.

    Interrupt driven support, DCR, and regshift support are extras - but 
I am sure they matter to someone else.

>  David> Also there is no provision for running the UartLite without
>  David> using interrupts.  The Pico E12/E14 frequently use FPGA
>  David> firmare that does not include a PIC.  Some implimentations of
>  David> the UartLite use dcr instead of memory mapped ports.
>    
> No - again like the early serial stuff that's something that can be
> added once the base driver is mainlined if there's demand.
>
> Does polling even work decently with the small fifo size of the
> uartlite?
>
>   


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-04 15:41             ` Peter Korsgaard
  2006-10-06  4:13               ` David H. Lynch Jr.
  2006-10-06  4:14               ` David H. Lynch Jr.
@ 2006-10-06  4:14               ` David H. Lynch Jr.
  2 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-06  4:14 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>  David>     You force the port regshift value to 2 in your init code,
>  David> but then you ignore it and hard code the register offsets
>  David> preshifted.
>
> Yes, the regshift value is not used by the driver, I just kept the
> initialization as documentation. The Xilinx IP block afaik cannot be
> configured with a different regshift value than 2, so I hardcoded
> it.
>
> We can change that if it would ever be a problem, but there's
> unfortunately no clean way of representing this in the
> device/ressource data, so I would prefer to leave that out unless it's
> needed.
>   
    That is actually one of my more major issues. I am NOT the right 
person to speak for what direction things are going.
    But the majority of drivers - platform device based or otherwise, 
pass arround a uart_port structure with the irq, addresses, etc.
    the uart_port struct has provisions for a regshift - as well as 
other things.

    DCR is another issue. I have never personally seen a UartLite DCR 
implimentation, but I have a driver from somebody else that started from 
mine, that assumes
    DCR instead of memory mapped ports. I think the Xilinx Gigabit 
Reference System Design connects the UartLite via DCR.
   
    I think DCR has to be a consideration. I do not KNOW that there is a 
UartLite implimentation with a regshift other than 2.
    But I have seen occasional code that uses different values - The 
GreenHills Integrity UartLite driver
    has it as a configurable parameter.

     If your driver is going to become the officail UartLite driver, 
even if it does not already work with every UartLite implimentation, it 
still should not start with assumptions that
    are going to make supporting others difficult.
   
  




>  David> Also there is no provision for running the UartLite without
>  David> using interrupts.  The Pico E12/E14 frequently use FPGA
>  David> firmare that does not include a PIC.  Some implimentations of
>  David> the UartLite use dcr instead of memory mapped ports.
>    
> No - again like the early serial stuff that's something that can be
> added once the base driver is mainlined if there's demand.
>
> Does polling even work decently with the small fifo size of the
> uartlite?
>
>   


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-04 15:45             ` Peter Korsgaard
@ 2006-10-06  4:14               ` David H. Lynch Jr.
  0 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-06  4:14 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>  David> 	You need an "early_serial_setup()" routine inside the
>  David> CONFIG_SERIAL_UARTLITE_CONSOLE code.
>
> Isn't that just for early serial support?
>
>   
    Honestly,  I can not tell. It is implimented in 8250.c, and I think 
some other drivers. I think it was  related to early_serial. But I think 
that is now moved into the main driver, not a separate early_serial driver.
    I stubbed it out to nothing just to make the linker happy and 
noticed no obvious difference in behavior. But due to printk buffering, 
it might be very hard to see a difference - unless there was an early 
failure.

    What I know is that:
                 the ml403 8250 support (as well as many other drivers), 
impliment it
                 that they pass a uart_port structure
                 and that it may be called for each port,
               
    I beleive that it may be more important than the uartlite_tty.c and 
uartlite_dbg.c that get used very breifly by much earlier code.
    But I am just guessing.
   
    I know that my driver impliments it and as a result I usually see 
messages up to the moment of failure when there is a failure, and do not 
get into a bind because they are stuck in a printk buffer.




 





-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-04 16:01             ` Peter Korsgaard
@ 2006-10-06  4:15               ` David H. Lynch Jr.
  0 siblings, 0 replies; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-06  4:15 UTC (permalink / raw)
  To: linux-serial

Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>  David> 	Your ulite_console_write performance is pretty slow -
>  David> almost an order of magnitude slower than what I am seeing in
>  David> my driver. I beleive it is because you are waiting for the Tx
>  David> FIFO to be empty before and after sending each character
>  David> rather than only waiting while the Tx FIFO is full.
>
> Really? The implementation is basically a copy of 8250.c, so I would
> imagine that would get similar performance. Perhaps it's related to
> your specific setup?
>
> The driver only waits before sending a character, not afterwards.
>   

    From your code:
    there is a call to ulite_console_wait_tx() in each call to 
ulite_console_putchar() and a call after uart_console_write()
    However as I later determined that is NOT the problem. Either 
uart_console_write() is very slow, or there is a parameter wrong - 
probably in uart_port.
    But if you have something wrong there. So do I because when I switch 
my code to uase uart_console_write() instead of the a manual 
implimentation of puts (what older drivers use, including older 8250's)
    I get the same problem. I think my driver using uart_console_write() 
may be faster - but that may be wishful thinking. Both are abysmal 
compared to a simple puts loop. The difference is dramatic.

+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void ulite_console_wait_tx(struct uart_port *port)
+{
+	int i;
+
+	/* wait up to 10ms for the character(s) to be sent */
+	for (i=0; i<10000; i++) {
+		if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
+			break;
+		udelay(1);
+	}
+}
+
+static void ulite_console_putchar(struct uart_port *port, int ch)
+{
+	ulite_console_wait_tx(port);
+	writeb(ch, port->membase + ULITE_TX);
+}
+
+static void ulite_console_write(struct console *co, const char *s,
+				unsigned int count)
+{
+	struct uart_port *port = &ports[co->index];
+	unsigned long flags;
+	unsigned int ier;
+	int locked = 1;
+
+	if (oops_in_progress) {
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	} else
+		spin_lock_irqsave(&port->lock, flags);
+
+	/* save and disable interrupt */
+	ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
+	writeb(0, port->membase + ULITE_CONTROL);
+
+	uart_console_write(port, s, count, ulite_console_putchar);
+
+	ulite_console_wait_tx(port);
+
+	/* restore interrupt state */
+	if (ier)
+		writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+




>  David> 	That may also be an issue in the rest of the driver but I have been
>  David> unable to get it to through registering the driver.
>  David> 	I suspect that is because your driver is a platform driver, but you did
>  David> not provide patches to the arch/ppc/platforms/4xx/virtex.* or
>  David> xilinx_ml???.* to setup the platform device structure.
>
> No, because the Xilinx boards don't have any uartlite devices.
>
>  David> 	If you could provide a copy I would appreciate it.
>
> Sure, just add something like this to your board code (with your base
> address/irq ofcause):
> 	
> static struct resource uartlite_resources[] = {
>        [0] = {
>            .start  = 0xa1000003,
>            .end    = 0xa1000012,
>            .flags  = IORESOURCE_MEM,
>        },
>        [1] = {
>            .start  = 2,
>            .end    = 2,
>            .flags  = IORESOURCE_IRQ,
>        },
> };
>
> static struct platform_device uartlite = {
>        .name              = "uartlite",
>        .id                = 0,
>        .num_resources     = ARRAY_SIZE(uartlite_resources),
>        .resource          = uartlite_resources,
>        .dev.platform_data = 0,
> };
>
> static struct platform_device *my_devices[] __initdata = {
>        &uartlite,
>        .
>        .
>        .
> };
>
> static int __init
> my_platform_add_devices(void)
> {
>         return platform_add_devices(my_devices, ARRAY_SIZE(my_devices));
>
> }
>
> arch_initcall(my_platform_add_devices);
>
>   


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-09-13 13:39       ` Peter Korsgaard
  2006-09-13 15:01         ` Olof Johansson
@ 2006-10-19 23:06         ` Olof Johansson
  2006-10-20 12:22           ` Peter Korsgaard
  1 sibling, 1 reply; 32+ messages in thread
From: Olof Johansson @ 2006-10-19 23:06 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: rmk+serial, linux-serial, linux-kernel

On Wed, 13 Sep 2006 15:39:09 +0200 Peter Korsgaard <jacmet@sunsite.dk> wrote:

> +static int __devinit ulite_probe(struct platform_device *pdev)
[...]
> +	port = &ports[pdev->id];
> +
> +	port->fifosize	= 16;
> +	port->regshift	= 2;
> +	port->iotype	= UPIO_MEM;
> +	port->iobase	= 1; /* mark port in use */
> +	port->mapbase	= res->start;
> +	port->membase	= 0;
> +	port->ops	= &ulite_ops;
> +	port->irq	= res2->start;
> +	port->flags	= UPF_BOOT_AUTOCONF;
> +	port->dev	= &pdev->dev;
> +	port->type	= PORT_UNKNOWN;

Hi Peter,

You never fill in the 'line' member here, so probing of a second
uartlite port will fail.

Add:
	port->line	 = pdev->id;


-Olof

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-19 23:06         ` Olof Johansson
@ 2006-10-20 12:22           ` Peter Korsgaard
  0 siblings, 0 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-20 12:22 UTC (permalink / raw)
  To: Olof Johansson; +Cc: rmk+serial, linux-serial, linux-kernel

>>>>> "Olof" == Olof Johansson <olof@lixom.net> writes:

 >> +static int __devinit ulite_probe(struct platform_device *pdev)

 Olof> You never fill in the 'line' member here, so probing of a second
 Olof> uartlite port will fail.

Ah yes, sorry about that. I'll send a patch to Andrew.

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
  2006-10-13 14:12 David H. Lynch Jr.
@ 2006-10-13 14:45 ` Peter Korsgaard
  0 siblings, 0 replies; 32+ messages in thread
From: Peter Korsgaard @ 2006-10-13 14:45 UTC (permalink / raw)
  To: David H. Lynch Jr.; +Cc: linux-serial

>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:

Hi,

 David>     I do not care about DCR,  but as the responsible party for the only
 David> board I am aware of that does use the uartlite as its
 David>     primary serial device, which typically does not have interrupt
 David> support, that is something I care about alot.

Ok. Patches are welcome.

-- 
Bye, Peter Korsgaard

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

* Re: [RFC][PATCH] Xilinx uartlite serial driver
@ 2006-10-13 14:12 David H. Lynch Jr.
  2006-10-13 14:45 ` Peter Korsgaard
  0 siblings, 1 reply; 32+ messages in thread
From: David H. Lynch Jr. @ 2006-10-13 14:12 UTC (permalink / raw)
  To: linux-serial


Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>             
>
> Hi,
>
>
>  David> Also there is no provision for running the UartLite without
>  David> using interrupts.  The Pico E12/E14 frequently use FPGA
>  David> firmare that does not include a PIC.  Some implimentations of
>  David> the UartLite use dcr instead of memory mapped ports.
>    
> No - again like the early serial stuff that's something that can be
> added once the base driver is mainlined if there's demand.
>
> Does polling even work decently with the small fifo size of the
> uartlite?
>
>   
     I do not care about DCR,  but as the responsible party for the only
board I am aware of that does use the uartlite as its
     primary serial device, which typically does not have interrupt
support, that is something I care about alot.

     You can poll a serial port on an 8080 running 1Mhz with a serial
port with no fifo.
     16 bytes on a 300Mhz PPC is heaven. Works fine at 115K baud.



-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too 
numerous to list.

"Any intelligent fool can make things bigger and more complex... It 
takes a touch of genius - and a lot of courage to move in the opposite 
direction."
Albert Einstein

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

end of thread, other threads:[~2006-10-20 12:23 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-11 14:23 [RFC][PATCH] Xilinx uartlite serial driver Peter Korsgaard
2006-05-11 22:20 ` Russell King
2006-05-16  9:48   ` Peter Korsgaard
2006-05-16 12:09     ` Sylvain Munaut
2006-05-16 12:53     ` Russell King
2006-05-16 13:03       ` Peter Korsgaard
2006-06-02 16:47         ` Russell King
2006-05-16 13:03       ` Sylvain Munaut
2006-05-16 13:07         ` Peter Korsgaard
2006-08-22 15:13 ` Peter Korsgaard
2006-09-12 14:33   ` Olof Johansson
2006-09-13  5:56     ` Peter Korsgaard
2006-09-13 13:39       ` Peter Korsgaard
2006-09-13 15:01         ` Olof Johansson
2006-09-29 19:04           ` David H. Lynch Jr.
2006-09-29 19:57           ` David H. Lynch Jr.
2006-10-04 15:45             ` Peter Korsgaard
2006-10-06  4:14               ` David H. Lynch Jr.
2006-09-30  9:25           ` David H. Lynch Jr.
2006-10-04 16:01             ` Peter Korsgaard
2006-10-06  4:15               ` David H. Lynch Jr.
2006-10-03 10:27           ` David H. Lynch Jr.
     [not found]           ` <451CDA3D.2060109@dlasys.net>
2006-10-04 15:41             ` Peter Korsgaard
2006-10-06  4:13               ` David H. Lynch Jr.
2006-10-06  4:14               ` David H. Lynch Jr.
2006-10-06  4:14               ` David H. Lynch Jr.
2006-10-19 23:06         ` Olof Johansson
2006-10-20 12:22           ` Peter Korsgaard
2006-09-28 10:14       ` David H. Lynch Jr.
2006-10-04 15:34         ` Peter Korsgaard
2006-10-13 14:12 David H. Lynch Jr.
2006-10-13 14:45 ` Peter Korsgaard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.