* [PATCH] Xilinx UART Lite 2.6.18 driver
@ 2006-10-10 20:49 David Bolcsfoldi
2006-10-10 22:04 ` Grant Likely
` (2 more replies)
0 siblings, 3 replies; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-10 20:49 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 271 bytes --]
Hi,
here's a set of patches that adds support for Xilinx UART lite
devices. It has been tested on an ML403-FX using xapp902
(ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox userspace.
This is my first patch for the Linux kernel, so please be gentle :-)
David
[-- Attachment #2: xuartlite_tty.c.patch --]
[-- Type: text/x-patch, Size: 3565 bytes --]
diff -urN 2.6.18/arch/ppc/boot/simple/Makefile patched/arch/ppc/boot/simple/Makefile
--- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/simple/Makefile 2006-10-07 10:34:32.000000000 -0700
@@ -205,6 +205,7 @@
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_XUL_CONSOLE) += xuartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff -urN 2.6.18/arch/ppc/boot/simple/misc.c patched/arch/ppc/boot/simple/misc.c
--- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/simple/misc.c 2006-10-07 10:27:34.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
diff -urN 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c patched/arch/ppc/boot/simple/xuartlite_tty.c
--- 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c 1969-12-31 16:00:00.000000000 -0800
+++ patched/arch/ppc/boot/simple/xuartlite_tty.c 2006-10-07 10:29:30.000000000 -0700
@@ -0,0 +1,74 @@
+/*
+ * Xilinx UART Lite support.
+ * Right now it only works over UART0 and none other.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
+#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
+#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
+#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
+#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
+
+static inline int is_xmit_full(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
+}
+
+static inline int is_recv_empty(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
+ default:
+ goto out;
+ }
+
+out:
+ return -1;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
+ out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_TX_FIFO_OFFSET), c);
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+ return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_RX_FIFO_OFFSET));
+}
+
+int serial_tstc(unsigned long com_port)
+{
+ return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+}
+
[-- Attachment #3: misc-common.c.patch --]
[-- Type: text/x-patch, Size: 2118 bytes --]
diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c patched/arch/ppc/boot/common/misc-common.c
--- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/boot/common/misc-common.c 2006-10-07 10:33:28.000000000 -0700
@@ -57,7 +57,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_XUL_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
[-- Attachment #4: virtex.c.patch --]
[-- Type: text/x-patch, Size: 316 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/virtex.c 2006-10-07 11:21:18.000000000 -0700
@@ -52,5 +52,10 @@
.id = 0,
.dev.platform_data = serial_platform_data,
},
+
+ [VIRTEX_XUL_UART] = {
+ .name = "xul_uart",
+ .id = 0,
+ },
};
[-- Attachment #5: virtex.h.patch --]
[-- Type: text/x-patch, Size: 386 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/virtex.h 2006-10-07 10:35:31.000000000 -0700
@@ -27,7 +27,9 @@
/* Device type enumeration for platform bus definitions */
#ifndef __ASSEMBLY__
enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
+ VIRTEX_UART,
+ VIRTEX_XUL_UART,
+ NUM_PPC_SYS_DEVS,
};
#endif
[-- Attachment #6: xuartlite.c.patch --]
[-- Type: text/x-patch, Size: 19936 bytes --]
diff -urN 2.6.18/drivers/serial/Kconfig patched/drivers/serial/Kconfig
--- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
+++ patched/drivers/serial/Kconfig 2006-10-07 10:50:20.000000000 -0700
@@ -959,4 +959,22 @@
If you have enabled the serial port on the Motorola IMX
CPU you can make it the console by answering Y to this option.
+config SERIAL_XUL
+ tristate "Xilinx UART Lite serial support"
+ depends on XILINX_ML403
+ select SERIAL_CORE
+ help
+ This driver supports the Xilinx UART Lite serial ports. If you would
+ like to use them, you must answer Y or M to this option. Note that
+ for use as console, it must be included in the kernel and not as a
+ module.
+
+config SERIAL_XUL_CONSOLE
+ bool "Console on a Xilinx UART Lite serial port"
+ depends on SERIAL_XUL
+ select SERIAL_CORE_CONSOLE
+ help
+ Select this option if you'd like to use the UART Lite serial port
+ of the Xilinx ML403 board as a console.
+
endmenu
diff -urN 2.6.18/drivers/serial/Makefile patched/drivers/serial/Makefile
--- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
+++ patched/drivers/serial/Makefile 2006-10-07 10:51:02.000000000 -0700
@@ -56,3 +56,4 @@
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_XUL) += xuartlite.o
diff -urN 2.6.18/drivers/serial/xuartlite.c patched/drivers/serial/xuartlite.c
--- 2.6.18/drivers/serial/xuartlite.c 1969-12-31 16:00:00.000000000 -0800
+++ patched/drivers/serial/xuartlite.c 2006-10-10 11:08:08.000000000 -0700
@@ -0,0 +1,723 @@
+/*
+ * drivers/serial/xuartlite.c
+ *
+ * Driver for Xilinx UART Lite device.
+ *
+ * This driver has only been tested with the Xilinx ML403-FX board using the plb_temac
+ * reference design with on UART port.
+ *
+ * This driver is loosely based off the mpc52xx_uart driver.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#if defined(CONFIG_SERIAL_XUL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SERIAL_XUL_MAJOR 204
+#define SERIAL_XUL_MINOR 187
+
+/*
+ * Keeps various tidbits about the serial port taken
+ * from xparameters.h
+ * */
+
+struct xul_uart_data {
+ int baud;
+ int parity;
+ int bits;
+ int flow;
+ int uartclk;
+ int irq;
+ int mapbase;
+ int size;
+};
+
+static struct xul_uart_data xul_data[XPAR_XUARTLITE_NUM_INSTANCES] = {
+ {
+ .baud = XPAR_XUL_UART_0_BAUDRATE,
+#if (XPAR_XUL_UART_0_USE_PARITY != 0)
+ .parity = 'y',
+#else
+ .parity = 'n',
+#endif /* XPAR_XUL_UART_0_USE_PARITY */
+ .bits = XPAR_XUL_UART_0_DATA_BITS,
+ .flow = 'n',
+ .uartclk = 100000000 / 16, /* PLB speed / 16 */
+ .irq = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .mapbase = XPAR_XUL_UART_0_BASEADDR,
+ .size = (XPAR_XUL_UART_0_HIGHADDR - XPAR_XUL_UART_0_BASEADDR) + 1
+ }
+
+ /* Add next uart here */
+};
+
+static const long ISR_PASS_LIMIT = 255;
+static struct uart_port xul_uart_ports[XPAR_XUARTLITE_NUM_INSTANCES];
+
+#define XUL(port) ((unsigned int)((port)->membase))
+
+#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
+#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
+#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
+#define XUL_CONTROL_REG_OFFSET 12 /* control register, write only */
+
+#define XUL_CR_ENABLE_INTR 0x10 /* enable interrupt */
+#define XUL_CR_FIFO_RX_RESET 0x02 /* reset receive FIFO */
+#define XUL_CR_FIFO_TX_RESET 0x01 /* reset transmit FIFO */
+
+#define XUL_SR_PARITY_ERROR 0x80
+#define XUL_SR_FRAMING_ERROR 0x40
+#define XUL_SR_OVERRUN_ERROR 0x20
+#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
+#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
+#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
+
+/* Forward declaration of the interruption handling routine */
+static irqreturn_t xul_uart_int(int irq,void *dev_id,struct pt_regs *regs);
+
+/* Simple macro to test if a port is console or not. This one is taken
+ * for serial_core.c and maybe should be moved to serial_core.h ? */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
+#else
+#define uart_console(port) (0)
+#endif
+
+/* ======================================================================== */
+/* UART operations */
+/* ======================================================================== */
+
+static int
+xul_uart_int_tx_chars(struct uart_port *port);
+
+static inline int is_xmit_empty(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_EMPTY) == XUL_SR_TX_FIFO_EMPTY);
+}
+
+static inline int is_recv_empty(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
+}
+
+static inline int is_xmit_full(struct uart_port *port)
+{
+ return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
+}
+
+static inline void xmit_char(struct uart_port *port, char c)
+{
+ while(is_xmit_full(port));
+ out_be32((volatile unsigned *) (XUL(port) + XUL_TX_FIFO_OFFSET), c);
+}
+
+static inline char recv_char(struct uart_port *port)
+{
+ while(is_recv_empty(port));
+ return in_be32((volatile unsigned *) (XUL(port) + XUL_RX_FIFO_OFFSET));
+}
+
+static unsigned int
+xul_uart_tx_empty(struct uart_port *port)
+{
+ return ((is_xmit_empty(port)) ? TIOCSER_TEMT : 0);
+}
+
+static void
+xul_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* Not implemented */
+}
+
+static unsigned int
+xul_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void
+xul_uart_stop_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+}
+
+static void
+xul_uart_start_tx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+ xul_uart_int_tx_chars(port);
+}
+
+static void
+xul_uart_send_xchar(struct uart_port *port, char ch)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->x_char = ch;
+
+ if (ch) {
+ xmit_char(port, ch);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void
+xul_uart_stop_rx(struct uart_port *port)
+{
+ /* port->lock taken by caller */
+}
+
+static void
+xul_uart_enable_ms(struct uart_port *port)
+{
+ /* Not implemented */
+}
+
+static void
+xul_uart_break_ctl(struct uart_port *port, int ctl)
+{
+ /* Not implemented */
+}
+
+static int
+xul_uart_startup(struct uart_port *port)
+{
+ int ret;
+
+ /* Request IRQ */
+ ret = request_irq(port->irq, xul_uart_int,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM, "xul_uart", port);
+ if (ret)
+ return ret;
+
+ /* Reset/activate the port, clear and enable interrupts */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_ENABLE_INTR); /* Enable interrupt */
+
+ return 0;
+}
+
+static void
+xul_uart_shutdown(struct uart_port *port)
+{
+ /* Shut down the port, interrupt and all */
+
+ /* Disable interrupt bu clearing control register */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
+
+ /* Release interrupt */
+ free_irq(port->irq, port);
+}
+
+static void
+xul_uart_set_termios(struct uart_port *port, struct termios *new,
+ struct termios *old)
+{
+ /* Nothing can be set, fixed at IP block generation */
+}
+
+static const char *
+xul_uart_type(struct uart_port *port)
+{
+ return port->type == PORT_XUL ? "ttyXUL" : NULL;
+}
+
+static void
+xul_uart_release_port(struct uart_port *port)
+{
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ release_mem_region(port->mapbase, xul_data[port->line].size);
+}
+
+static int
+xul_uart_request_port(struct uart_port *port)
+{
+ int mem_region;
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, xul_data[port->line].size);
+ }
+
+ if (!port->membase) {
+ return -EINVAL;
+ }
+
+ mem_region = request_mem_region(port->mapbase, xul_data[port->line].size, "xul_uart") != NULL ? 0 : -EBUSY;
+ return 0;
+}
+
+static void
+xul_uart_config_port(struct uart_port *port, int flags)
+{
+ if ( (flags & UART_CONFIG_TYPE) &&
+ (xul_uart_request_port(port) == 0) )
+ port->type = PORT_XUL;
+}
+
+static int
+xul_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if ( ser->type != PORT_UNKNOWN && ser->type != PORT_XUL ) {
+ printk(KERN_WARNING "xul_uart_verify_port(1)\n");
+ return -EINVAL;
+ }
+
+ if ( (ser->irq != port->irq) ||
+ (ser->io_type != SERIAL_IO_MEM) ||
+ (ser->baud_base != port->uartclk) ||
+ (ser->iomem_base != (void*)port->mapbase) ||
+ (ser->hub6 != 0 ) ) {
+ printk(KERN_WARNING "xul_uart_verify_port(1)\n");
+ }
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static struct uart_ops xul_uart_ops = {
+ .tx_empty = xul_uart_tx_empty,
+ .set_mctrl = xul_uart_set_mctrl,
+ .get_mctrl = xul_uart_get_mctrl,
+ .stop_tx = xul_uart_stop_tx,
+ .start_tx = xul_uart_start_tx,
+ .send_xchar = xul_uart_send_xchar,
+ .stop_rx = xul_uart_stop_rx,
+ .enable_ms = xul_uart_enable_ms,
+ .break_ctl = xul_uart_break_ctl,
+ .startup = xul_uart_startup,
+ .shutdown = xul_uart_shutdown,
+ .set_termios = xul_uart_set_termios,
+/* .pm = xul_uart_pm, Not supported yet */
+/* .set_wake = xul_uart_set_wake, Not supported yet */
+ .type = xul_uart_type,
+ .release_port = xul_uart_release_port,
+ .request_port = xul_uart_request_port,
+ .config_port = xul_uart_config_port,
+ .verify_port = xul_uart_verify_port
+};
+
+
+/* ======================================================================== */
+/* Interrupt handling */
+/* ======================================================================== */
+
+static int
+xul_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned char ch, flag;
+ unsigned long status;
+
+ status = in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET));
+
+ /* While we can read, do so ! */
+ if ((status & XUL_SR_RX_FIFO_VALID_DATA) == XUL_SR_RX_FIFO_VALID_DATA) {
+
+ /* Get the char */
+ ch = recv_char(port);
+
+ /* Handle sysreq char */
+#ifdef SUPPORT_SYSRQ
+ if (uart_handle_sysrq_char(port, ch, regs)) {
+ port->sysrq = 0;
+ continue;
+ }
+#endif
+ /* Store it */
+
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & XUL_SR_PARITY_ERROR)
+ flag = TTY_PARITY;
+ else if (status & XUL_SR_FRAMING_ERROR)
+ flag = TTY_FRAME;
+
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (status & XUL_SR_OVERRUN_ERROR) {
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ }
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
+
+ return 0;
+}
+
+static int
+xul_uart_int_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ /* Process out of band chars */
+ if (port->x_char) {
+ xmit_char(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return 1;
+ }
+
+ /* Nothing to do ? */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ xul_uart_stop_tx(port);
+ return 0;
+ }
+
+ /* Send chars */
+ while (is_xmit_full(port) == 0) {
+ xmit_char(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ /* Wake up */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ uart_write_wakeup(port);
+ }
+
+ /* Maybe we're done after all */
+ if (uart_circ_empty(xmit)) {
+ xul_uart_stop_tx(port);
+ return 0;
+ }
+
+ return 1;
+}
+
+static irqreturn_t
+xul_uart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct uart_port *port = (struct uart_port *) dev_id;
+ unsigned long pass = ISR_PASS_LIMIT;
+ unsigned int keepgoing;
+
+ if ( irq != port->irq ) {
+ printk( KERN_WARNING
+ "xul_uart_int : " \
+ "Received wrong int %d. Waiting for %d\n",
+ irq, port->irq);
+ return IRQ_NONE;
+ }
+
+ spin_lock(&port->lock);
+
+ /* While we have stuff to do, we continue */
+ do {
+ /* If we don't find anything to do, we stop */
+ keepgoing = 0;
+
+ /* Do we need to receive chars ? */
+ if (is_recv_empty(port) == 0) {
+ keepgoing |= xul_uart_int_rx_chars(port, regs);
+ }
+
+ /* Do we need to send chars ? */
+ if (is_xmit_empty(port)) {
+ keepgoing |= xul_uart_int_tx_chars(port);
+ }
+
+ /* Limit number of iteration */
+ if ( !(--pass) )
+ keepgoing = 0;
+
+ } while (keepgoing);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Utility routines
+ */
+
+static void __init xul_uart_init_ports(void)
+{
+ int i;
+ static int once = 1;
+
+ /* Initialize ports only once */
+ if (!once)
+ return;
+ once = 0;
+
+ for (i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
+ struct uart_port *xup = &xul_uart_ports[i];
+
+ xup->line = i;
+ spin_lock_init(&xup->lock);
+ xup->uartclk = xul_data[i].uartclk / 16;
+ xup->fifosize = 16;
+ xup->iotype = UPIO_MEM;
+ xup->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ xup->ops = &xul_uart_ops;
+ xup->irq = xul_data[i].irq;
+ xup->mapbase = xul_data[i].mapbase;
+ }
+}
+
+static void __init xul_uart_register_ports(struct uart_driver *driver)
+{
+ int i, ret;
+
+ for(i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
+ struct uart_port *port = &xul_uart_ports[i];
+ /* Add the port to the uart sub-system */
+ ret = uart_add_one_port(driver, port);
+ }
+}
+
+/* ======================================================================== */
+/* Console ( if applicable ) */
+/* ======================================================================== */
+
+#ifdef CONFIG_SERIAL_XUL_CONSOLE
+
+static void
+xul_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &xul_uart_ports[co->index];
+ unsigned int i, j;
+
+ /* Disable interrupts */
+
+ spin_lock(&port->lock);
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+ spin_unlock(&port->lock);
+
+ /* Wait the TX buffer to be empty */
+ j = 5000000; /* Maximum wait */
+ while (!(is_xmit_empty(port)) &&
+ --j)
+ udelay(1);
+
+ for (i = 0; i < count; i++, s++) {
+ if (*s == '\n')
+ xmit_char(port, '\r');
+
+ xmit_char(port, *s);
+ }
+
+ /* Restore interrupt state */
+ out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
+}
+
+static int __init
+xul_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud;
+ int bits;
+ int parity;
+ int flow;
+
+ if (co->index < 0 || co->index >= XPAR_XUARTLITE_NUM_INSTANCES)
+ return -EINVAL;
+
+ port = &xul_uart_ports[co->index];
+
+ /* We ioremap ourself */
+ port->membase = ioremap(port->mapbase, xul_data[co->index].size);
+
+ if (port->membase == NULL) {
+ return -EINVAL;
+ }
+
+ port->flags &= ~UPF_IOREMAP;
+
+ baud = xul_data[co->index].baud;
+ parity = xul_data[co->index].parity;
+ bits = xul_data[co->index].bits;
+ flow = xul_data[co->index].flow;
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver xul_uart_driver;
+
+static struct console xul_console = {
+ .name = "ttyXUL",
+ .write = xul_console_write,
+ .device = uart_console_device,
+ .setup = xul_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1, /* Specified on the cmdline (e.g. console=ttyXUL0 ) */
+ .data = &xul_uart_driver,
+};
+
+
+static int __init
+xul_console_init(void)
+{
+ xul_uart_init_ports();
+ register_console(&xul_console);
+ return 0;
+}
+
+console_initcall(xul_console_init);
+
+#define XUL_CONSOLE &xul_console
+#else
+#define XUL_CONSOLE NULL
+#endif
+
+
+/* ======================================================================== */
+/* UART Driver */
+/* ======================================================================== */
+
+static struct uart_driver xul_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "xul_uart",
+ .dev_name = "ttyXUL",
+ .major = SERIAL_XUL_MAJOR,
+ .minor = SERIAL_XUL_MINOR,
+ .nr = XPAR_XUARTLITE_NUM_INSTANCES,
+ .cons = XUL_CONSOLE,
+};
+
+
+/* ======================================================================== */
+/* Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+xul_uart_probe(struct platform_device *dev)
+{
+ /* Probe does nothing */
+ return 0;
+}
+
+static int
+xul_uart_remove(struct platform_device *dev)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ if (port)
+ uart_remove_one_port(&xul_uart_driver, port);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+xul_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ if (port)
+ uart_suspend_port(&xul_uart_driver, port);
+
+ return 0;
+}
+
+static int
+xul_uart_resume(struct platform_device *dev)
+{
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+
+ if (port)
+ uart_resume_port(&xul_uart_driver, port);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver xul_uart_platform_driver = {
+ .probe = xul_uart_probe,
+ .remove = xul_uart_remove,
+#ifdef CONFIG_PM
+ .suspend = xul_uart_suspend,
+ .resume = xul_uart_resume,
+#endif
+ .driver = {
+ .name = "xul_uart"
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+xul_uart_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: Xilinx UART Lite driver\n");
+
+ xul_uart_init_ports();
+
+ ret = uart_register_driver(&xul_uart_driver);
+
+ if (ret == 0) {
+ xul_uart_register_ports(&xul_uart_driver);
+
+ ret = platform_driver_register(&xul_uart_platform_driver);
+
+ if (ret) {
+ printk(KERN_WARNING "platform_driver_register failed! :%i\n", ret);
+ uart_unregister_driver(&xul_uart_driver);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit
+xul_uart_exit(void)
+{
+ platform_driver_unregister(&xul_uart_platform_driver);
+ uart_unregister_driver(&xul_uart_driver);
+}
+
+
+module_init(xul_uart_init);
+module_exit(xul_uart_exit);
+
+MODULE_AUTHOR("David Bolcsfoldi <dbolcsfoldi@gmail.com>");
+MODULE_DESCRIPTION("Xilinx UART Lite");
+MODULE_LICENSE("GPL");
+
[-- Attachment #7: xilinx_ml403.c.patch --]
[-- Type: text/x-patch, Size: 290 bytes --]
--- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04 14:31:15.000000000 -0700
+++ patched/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-07 10:41:50.000000000 -0700
@@ -69,6 +69,7 @@
.device_list = (enum ppc_sys_devices[])
{
VIRTEX_UART,
+ VIRTEX_XUL_UART,
},
},
};
[-- Attachment #8: serial_core.h.patch --]
[-- Type: text/x-patch, Size: 268 bytes --]
--- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
+++ patched/include/linux/serial_core.h 2006-10-07 10:52:24.000000000 -0700
@@ -132,6 +132,8 @@
#define PORT_S3C2412 73
+/* Xilinx UART Lite */
+#define PORT_XUL 74
#ifdef __KERNEL__
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-10 20:49 [PATCH] Xilinx UART Lite 2.6.18 driver David Bolcsfoldi
@ 2006-10-10 22:04 ` Grant Likely
2006-10-11 22:06 ` David H. Lynch Jr.
2006-10-12 10:34 ` Peter Korsgaard
2 siblings, 0 replies; 24+ messages in thread
From: Grant Likely @ 2006-10-10 22:04 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
On 10/10/06, David Bolcsfoldi <dbolcsfoldi@gmail.com> wrote:
> Hi,
>
> here's a set of patches that adds support for Xilinx UART lite
> devices. It has been tested on an ML403-FX using xapp902
> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox userspace.
>
> This is my first patch for the Linux kernel, so please be gentle :-)
Okay; here goes. :)
First off; it is easiest to review patches when they are sent inline,
one per email. When they are attachements, they have to be extracted
and copied back into an email to comment on them. Also, most of the
patches here are pretty minor. You can roll all of them up into a
single patch (or two if you want to separate the boot wrapper driver
and the full driver)
Other generic comments:
- Try to keep lines under 80 character long.
xuartlite_tty.c.patch: These changes look pretty good
misc-common.c.patch: ok
virtex.h.patch: ok
xilinx_ml403.c.patch: ok
serial_core.h: ok
virtex.c.patch:
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/platforms/4xx/virtex.c 2006-10-07 11:21:18.000000000 -0700
> @@ -52,5 +52,10 @@
> .id = 0,
> .dev.platform_data = serial_platform_data,
> },
> +
> + [VIRTEX_XUL_UART] = {
> + .name = "xul_uart",
> + .id = 0,
> + },
> };
You need to add a pointer to a table of available UartLites her.
Include base addresses/irq# in the table. There is no point adding
something to the platform bus if you don't describe the devices that
are available. Use the .dev.platform_data value. It's a void*
pointer available for your driver.
xuartlite.c.patch:
> diff -urN 2.6.18/drivers/serial/xuartlite.c patched/drivers/serial/xuartlite.c
> --- 2.6.18/drivers/serial/xuartlite.c 1969-12-31 16:00:00.000000000 -0800
> +++ patched/drivers/serial/xuartlite.c 2006-10-10 11:08:08.000000000 -0700
> @@ -0,0 +1,723 @@
<snip>
> +
> +#include <asm/delay.h>
> +#include <asm/io.h>
> +#include <platforms/4xx/xparameters/xparameters.h>
I'd like to move away from drivers including xparameters.h. We're
moving towards using the flattened device tree to populate the
platform bus for xilinx devices. arch/ppc doesn't use the device
tree, but it does populate the platform bus. Device drivers should
get base addresses, irqs, etc from the platform bus instead of
xparams.
> +
> +#if defined(CONFIG_SERIAL_XUL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/serial_core.h>
> +
> +#define SERIAL_XUL_MAJOR 204
> +#define SERIAL_XUL_MINOR 187
Have you added you new major/minor pair to Documentation/devices.txt?
> +
> +/*
> + * Keeps various tidbits about the serial port taken
> + * from xparameters.h
> + * */
> +
> +struct xul_uart_data {
> + int baud;
> + int parity;
> + int bits;
> + int flow;
> + int uartclk;
> + int irq;
> + int mapbase;
> + int size;
> +};
> +
> +static struct xul_uart_data xul_data[XPAR_XUARTLITE_NUM_INSTANCES] = {
> + {
> + .baud = XPAR_XUL_UART_0_BAUDRATE,
> +#if (XPAR_XUL_UART_0_USE_PARITY != 0)
> + .parity = 'y',
> +#else
> + .parity = 'n',
> +#endif /* XPAR_XUL_UART_0_USE_PARITY */
> + .bits = XPAR_XUL_UART_0_DATA_BITS,
> + .flow = 'n',
> + .uartclk = 100000000 / 16, /* PLB speed / 16 */
> + .irq = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .mapbase = XPAR_XUL_UART_0_BASEADDR,
> + .size = (XPAR_XUL_UART_0_HIGHADDR - XPAR_XUL_UART_0_BASEADDR) + 1
> + }
> +
> + /* Add next uart here */
> +};
Don't do this stuff here. Add a table to the platform bus initializer
in virtex.c.
> +
> +static const long ISR_PASS_LIMIT = 255;
> +static struct uart_port xul_uart_ports[XPAR_XUARTLITE_NUM_INSTANCES];
> +
> +#define XUL(port) ((unsigned int)((port)->membase))
> +
> +#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
> +#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
> +#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
> +#define XUL_CONTROL_REG_OFFSET 12 /* control register, write only */
> +
> +#define XUL_CR_ENABLE_INTR 0x10 /* enable interrupt */
> +#define XUL_CR_FIFO_RX_RESET 0x02 /* reset receive FIFO */
> +#define XUL_CR_FIFO_TX_RESET 0x01 /* reset transmit FIFO */
> +
> +#define XUL_SR_PARITY_ERROR 0x80
> +#define XUL_SR_FRAMING_ERROR 0x40
> +#define XUL_SR_OVERRUN_ERROR 0x20
> +#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
> +#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
> +#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
Break these out into an include file, and share them with
arch/ppc/boot/simple/xuartlite_tty.c
<snip>
> +static void
> +xul_uart_release_port(struct uart_port *port)
> +{
> + if (port->flags & UPF_IOREMAP) {
> + iounmap(port->membase);
> + port->membase = NULL;
> + }
> +
> + release_mem_region(port->mapbase, xul_data[port->line].size);
> +}
> +
> +static int
> +xul_uart_request_port(struct uart_port *port)
> +{
> + int mem_region;
> +
> + if (port->flags & UPF_IOREMAP) {
> + port->membase = ioremap(port->mapbase, xul_data[port->line].size);
> + }
> +
> + if (!port->membase) {
> + return -EINVAL;
> + }
> +
> + mem_region = request_mem_region(port->mapbase, xul_data[port->line].size, "xul_uart") != NULL ? 0 : -EBUSY;
> + return 0;
> +}
> +
> +static void
> +xul_uart_config_port(struct uart_port *port, int flags)
> +{
> + if ( (flags & UART_CONFIG_TYPE) &&
> + (xul_uart_request_port(port) == 0) )
> + port->type = PORT_XUL;
> +}
> +
> +static int
> +xul_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + if ( ser->type != PORT_UNKNOWN && ser->type != PORT_XUL ) {
> + printk(KERN_WARNING "xul_uart_verify_port(1)\n");
> + return -EINVAL;
> + }
> +
> + if ( (ser->irq != port->irq) ||
> + (ser->io_type != SERIAL_IO_MEM) ||
> + (ser->baud_base != port->uartclk) ||
> + (ser->iomem_base != (void*)port->mapbase) ||
> + (ser->hub6 != 0 ) ) {
> + printk(KERN_WARNING "xul_uart_verify_port(1)\n");
> + }
> + return -EINVAL;
> +
> + return 0;
> +}
This will always fail w/ -EINVAL. Check your braces.
Also, merge all these tests into a single if; or break them out into
individual if's. No need for the half-and-half approach done here.
<snip>
======================================================================== */
> +/* Interrupt handling */
> +/* ======================================================================== */
<snip>
> +
> +static irqreturn_t
> +xul_uart_int(int irq, void *dev_id, struct pt_regs *regs)
> +{
> + struct uart_port *port = (struct uart_port *) dev_id;
Cast not needed.
> + unsigned long pass = ISR_PASS_LIMIT;
> + unsigned int keepgoing;
> +
> + if ( irq != port->irq ) {
> + printk( KERN_WARNING
> + "xul_uart_int : " \
> + "Received wrong int %d. Waiting for %d\n",
> + irq, port->irq);
> + return IRQ_NONE;
> + }
No need to check (irq != port->irq). All those code blocks have been
removed from mainline.
<snip>
======================================================================== */
> +/* Platform Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +xul_uart_probe(struct platform_device *dev)
> +{
> + /* Probe does nothing */
> + return 0;
> +}
Gah! What's the point of registering with the platform bus, if you
don't have a probe() routine! :) This is where you should pull the
base addresses and number of devices out of the platform_device
structure and dynamically set up your ports.
<snip>
Cheers,
g.
--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-10 20:49 [PATCH] Xilinx UART Lite 2.6.18 driver David Bolcsfoldi
2006-10-10 22:04 ` Grant Likely
@ 2006-10-11 22:06 ` David H. Lynch Jr.
2006-10-12 10:34 ` Peter Korsgaard
2 siblings, 0 replies; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-11 22:06 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 30623 bytes --]
also:
your driver is strictly interrupt driven.
I need polled for the Pico E12 - which my driver an early
version was posted in January, supports.
Somebody else needs DCR support.
David Bolcsfoldi wrote:
> Hi,
>
> here's a set of patches that adds support for Xilinx UART lite
> devices. It has been tested on an ML403-FX using xapp902
> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox userspace.
>
> This is my first patch for the Linux kernel, so please be gentle :-)
>
> David
> ------------------------------------------------------------------------
>
> diff -urN 2.6.18/arch/ppc/boot/simple/Makefile patched/arch/ppc/boot/simple/Makefile
> --- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/boot/simple/Makefile 2006-10-07 10:34:32.000000000 -0700
> @@ -205,6 +205,7 @@
> endif
> boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
> boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
> +boot-$(CONFIG_SERIAL_XUL_CONSOLE) += xuartlite_tty.o
>
> LIBS := $(common)/lib.a $(bootlib)/lib.a
> ifeq ($(CONFIG_PPC_PREP),y)
> diff -urN 2.6.18/arch/ppc/boot/simple/misc.c patched/arch/ppc/boot/simple/misc.c
> --- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/boot/simple/misc.c 2006-10-07 10:27:34.000000000 -0700
> @@ -48,7 +48,8 @@
> #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_VGA_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)) \
> && !defined(CONFIG_GEMINI)
> #define INTERACTIVE_CONSOLE 1
> #endif
> diff -urN 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c patched/arch/ppc/boot/simple/xuartlite_tty.c
> --- 2.6.18/arch/ppc/boot/simple/xuartlite_tty.c 1969-12-31 16:00:00.000000000 -0800
> +++ patched/arch/ppc/boot/simple/xuartlite_tty.c 2006-10-07 10:29:30.000000000 -0700
> @@ -0,0 +1,74 @@
> +/*
> + * Xilinx UART Lite support.
> + * Right now it only works over UART0 and none other.
> + *
> + * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <asm/io.h>
> +#include <platforms/4xx/xparameters/xparameters.h>
> +
> +#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
> +#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
> +#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
> +#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
> +#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
> +
> +static inline int is_xmit_full(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
> +}
> +
> +static inline int is_recv_empty(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
> +}
> +
> +unsigned long serial_init(int chan, void *ignored)
> +{
> + switch (chan) {
> + #ifdef XPAR_XUL_UART_0_BASEADDR
> + case 0:
> + return XPAR_XUL_UART_0_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_1_BASEADDR
> + case 1:
> + return XPAR_XUL_UART_1_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_2_BASEADDR
> + case 2:
> + return XPAR_XUL_UART_2_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_3_BASEADDR
> + case 3:
> + return XPAR_XUL_UART_3_BASEADDR;
> + #endif
> + default:
> + goto out;
> + }
> +
> +out:
> + return -1;
> +}
> +
> +void serial_putc(unsigned long com_port, unsigned char c)
> +{
> + while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
> + out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_TX_FIFO_OFFSET), c);
> +}
> +
> +unsigned char serial_getc(unsigned long com_port)
> +{
> + while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> + return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + XUL_RX_FIFO_OFFSET));
> +}
> +
> +int serial_tstc(unsigned long com_port)
> +{
> + return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> +}
> +
>
> ------------------------------------------------------------------------
>
> diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c patched/arch/ppc/boot/common/misc-common.c
> --- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/boot/common/misc-common.c 2006-10-07 10:33:28.000000000 -0700
> @@ -57,7 +57,8 @@
>
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)
> extern unsigned long com_port;
>
> extern int serial_tstc(unsigned long com_port);
> @@ -80,7 +81,8 @@
> {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)
> if(keyb_present)
> return (CRT_tstc() || serial_tstc(com_port));
> else
> @@ -95,7 +97,8 @@
> while (1) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)
> if (serial_tstc(com_port))
> return (serial_getc(com_port));
> #endif /* serial console */
> @@ -112,7 +115,8 @@
>
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' )
> serial_putc(com_port, '\r');
> @@ -161,7 +165,8 @@
> while ( ( c = *s++ ) != '\0' ) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_XUL_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' ) serial_putc(com_port, '\r');
> #endif /* serial console */
>
> ------------------------------------------------------------------------
>
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/platforms/4xx/virtex.c 2006-10-07 11:21:18.000000000 -0700
> @@ -52,5 +52,10 @@
> .id = 0,
> .dev.platform_data = serial_platform_data,
> },
> +
> + [VIRTEX_XUL_UART] = {
> + .name = "xul_uart",
> + .id = 0,
> + },
> };
>
>
> ------------------------------------------------------------------------
>
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/platforms/4xx/virtex.h 2006-10-07 10:35:31.000000000 -0700
> @@ -27,7 +27,9 @@
> /* Device type enumeration for platform bus definitions */
> #ifndef __ASSEMBLY__
> enum ppc_sys_devices {
> - VIRTEX_UART, NUM_PPC_SYS_DEVS,
> + VIRTEX_UART,
> + VIRTEX_XUL_UART,
> + NUM_PPC_SYS_DEVS,
> };
> #endif
>
>
> ------------------------------------------------------------------------
>
> diff -urN 2.6.18/drivers/serial/Kconfig patched/drivers/serial/Kconfig
> --- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
> +++ patched/drivers/serial/Kconfig 2006-10-07 10:50:20.000000000 -0700
> @@ -959,4 +959,22 @@
> If you have enabled the serial port on the Motorola IMX
> CPU you can make it the console by answering Y to this option.
>
> +config SERIAL_XUL
> + tristate "Xilinx UART Lite serial support"
> + depends on XILINX_ML403
> + select SERIAL_CORE
> + help
> + This driver supports the Xilinx UART Lite serial ports. If you would
> + like to use them, you must answer Y or M to this option. Note that
> + for use as console, it must be included in the kernel and not as a
> + module.
> +
> +config SERIAL_XUL_CONSOLE
> + bool "Console on a Xilinx UART Lite serial port"
> + depends on SERIAL_XUL
> + select SERIAL_CORE_CONSOLE
> + help
> + Select this option if you'd like to use the UART Lite serial port
> + of the Xilinx ML403 board as a console.
> +
> endmenu
> diff -urN 2.6.18/drivers/serial/Makefile patched/drivers/serial/Makefile
> --- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
> +++ patched/drivers/serial/Makefile 2006-10-07 10:51:02.000000000 -0700
> @@ -56,3 +56,4 @@
> obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
> obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
> obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
> +obj-$(CONFIG_SERIAL_XUL) += xuartlite.o
> diff -urN 2.6.18/drivers/serial/xuartlite.c patched/drivers/serial/xuartlite.c
> --- 2.6.18/drivers/serial/xuartlite.c 1969-12-31 16:00:00.000000000 -0800
> +++ patched/drivers/serial/xuartlite.c 2006-10-10 11:08:08.000000000 -0700
> @@ -0,0 +1,723 @@
> +/*
> + * drivers/serial/xuartlite.c
> + *
> + * Driver for Xilinx UART Lite device.
> + *
> + * This driver has only been tested with the Xilinx ML403-FX board using the plb_temac
> + * reference design with on UART port.
> + *
> + * This driver is loosely based off the mpc52xx_uart driver.
> + *
> + * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/config.h>
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/tty.h>
> +#include <linux/serial.h>
> +#include <linux/sysrq.h>
> +#include <linux/console.h>
> +
> +#include <asm/delay.h>
> +#include <asm/io.h>
> +#include <platforms/4xx/xparameters/xparameters.h>
> +
> +#if defined(CONFIG_SERIAL_XUL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/serial_core.h>
> +
> +#define SERIAL_XUL_MAJOR 204
> +#define SERIAL_XUL_MINOR 187
> +
> +/*
> + * Keeps various tidbits about the serial port taken
> + * from xparameters.h
> + * */
> +
> +struct xul_uart_data {
> + int baud;
> + int parity;
> + int bits;
> + int flow;
> + int uartclk;
> + int irq;
> + int mapbase;
> + int size;
> +};
> +
> +static struct xul_uart_data xul_data[XPAR_XUARTLITE_NUM_INSTANCES] = {
> + {
> + .baud = XPAR_XUL_UART_0_BAUDRATE,
> +#if (XPAR_XUL_UART_0_USE_PARITY != 0)
> + .parity = 'y',
> +#else
> + .parity = 'n',
> +#endif /* XPAR_XUL_UART_0_USE_PARITY */
> + .bits = XPAR_XUL_UART_0_DATA_BITS,
> + .flow = 'n',
> + .uartclk = 100000000 / 16, /* PLB speed / 16 */
> + .irq = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .mapbase = XPAR_XUL_UART_0_BASEADDR,
> + .size = (XPAR_XUL_UART_0_HIGHADDR - XPAR_XUL_UART_0_BASEADDR) + 1
> + }
> +
> + /* Add next uart here */
> +};
> +
> +static const long ISR_PASS_LIMIT = 255;
> +static struct uart_port xul_uart_ports[XPAR_XUARTLITE_NUM_INSTANCES];
> +
> +#define XUL(port) ((unsigned int)((port)->membase))
> +
> +#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */
> +#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */
> +#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */
> +#define XUL_CONTROL_REG_OFFSET 12 /* control register, write only */
> +
> +#define XUL_CR_ENABLE_INTR 0x10 /* enable interrupt */
> +#define XUL_CR_FIFO_RX_RESET 0x02 /* reset receive FIFO */
> +#define XUL_CR_FIFO_TX_RESET 0x01 /* reset transmit FIFO */
> +
> +#define XUL_SR_PARITY_ERROR 0x80
> +#define XUL_SR_FRAMING_ERROR 0x40
> +#define XUL_SR_OVERRUN_ERROR 0x20
> +#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */
> +#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
> +#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
> +
> +/* Forward declaration of the interruption handling routine */
> +static irqreturn_t xul_uart_int(int irq,void *dev_id,struct pt_regs *regs);
> +
> +/* Simple macro to test if a port is console or not. This one is taken
> + * for serial_core.c and maybe should be moved to serial_core.h ? */
> +#ifdef CONFIG_SERIAL_CORE_CONSOLE
> +#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
> +#else
> +#define uart_console(port) (0)
> +#endif
> +
> +/* ======================================================================== */
> +/* UART operations */
> +/* ======================================================================== */
> +
> +static int
> +xul_uart_int_tx_chars(struct uart_port *port);
> +
> +static inline int is_xmit_empty(struct uart_port *port)
> +{
> + return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_EMPTY) == XUL_SR_TX_FIFO_EMPTY);
> +}
> +
> +static inline int is_recv_empty(struct uart_port *port)
> +{
> + return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_RX_FIFO_VALID_DATA) != XUL_SR_RX_FIFO_VALID_DATA);
> +}
> +
> +static inline int is_xmit_full(struct uart_port *port)
> +{
> + return ((in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET)) & XUL_SR_TX_FIFO_FULL) == XUL_SR_TX_FIFO_FULL);
> +}
> +
> +static inline void xmit_char(struct uart_port *port, char c)
> +{
> + while(is_xmit_full(port));
> + out_be32((volatile unsigned *) (XUL(port) + XUL_TX_FIFO_OFFSET), c);
> +}
> +
> +static inline char recv_char(struct uart_port *port)
> +{
> + while(is_recv_empty(port));
> + return in_be32((volatile unsigned *) (XUL(port) + XUL_RX_FIFO_OFFSET));
> +}
> +
> +static unsigned int
> +xul_uart_tx_empty(struct uart_port *port)
> +{
> + return ((is_xmit_empty(port)) ? TIOCSER_TEMT : 0);
> +}
> +
> +static void
> +xul_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + /* Not implemented */
> +}
> +
> +static unsigned int
> +xul_uart_get_mctrl(struct uart_port *port)
> +{
> + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
> +}
> +
> +static void
> +xul_uart_stop_tx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> +}
> +
> +static void
> +xul_uart_start_tx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> + xul_uart_int_tx_chars(port);
> +}
> +
> +static void
> +xul_uart_send_xchar(struct uart_port *port, char ch)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + port->x_char = ch;
> +
> + if (ch) {
> + xmit_char(port, ch);
> + }
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void
> +xul_uart_stop_rx(struct uart_port *port)
> +{
> + /* port->lock taken by caller */
> +}
> +
> +static void
> +xul_uart_enable_ms(struct uart_port *port)
> +{
> + /* Not implemented */
> +}
> +
> +static void
> +xul_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> + /* Not implemented */
> +}
> +
> +static int
> +xul_uart_startup(struct uart_port *port)
> +{
> + int ret;
> +
> + /* Request IRQ */
> + ret = request_irq(port->irq, xul_uart_int,
> + SA_INTERRUPT | SA_SAMPLE_RANDOM, "xul_uart", port);
> + if (ret)
> + return ret;
> +
> + /* Reset/activate the port, clear and enable interrupts */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_ENABLE_INTR); /* Enable interrupt */
> +
> + return 0;
> +}
> +
> +static void
> +xul_uart_shutdown(struct uart_port *port)
> +{
> + /* Shut down the port, interrupt and all */
> +
> + /* Disable interrupt bu clearing control register */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
> +
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_TX_RESET); /* Reset TX */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), XUL_CR_FIFO_RX_RESET); /* Reset RX */
> +
> + /* Release interrupt */
> + free_irq(port->irq, port);
> +}
> +
> +static void
> +xul_uart_set_termios(struct uart_port *port, struct termios *new,
> + struct termios *old)
> +{
> + /* Nothing can be set, fixed at IP block generation */
> +}
> +
> +static const char *
> +xul_uart_type(struct uart_port *port)
> +{
> + return port->type == PORT_XUL ? "ttyXUL" : NULL;
> +}
> +
> +static void
> +xul_uart_release_port(struct uart_port *port)
> +{
> + if (port->flags & UPF_IOREMAP) {
> + iounmap(port->membase);
> + port->membase = NULL;
> + }
> +
> + release_mem_region(port->mapbase, xul_data[port->line].size);
> +}
> +
> +static int
> +xul_uart_request_port(struct uart_port *port)
> +{
> + int mem_region;
> +
> + if (port->flags & UPF_IOREMAP) {
> + port->membase = ioremap(port->mapbase, xul_data[port->line].size);
> + }
> +
> + if (!port->membase) {
> + return -EINVAL;
> + }
> +
> + mem_region = request_mem_region(port->mapbase, xul_data[port->line].size, "xul_uart") != NULL ? 0 : -EBUSY;
> + return 0;
> +}
> +
> +static void
> +xul_uart_config_port(struct uart_port *port, int flags)
> +{
> + if ( (flags & UART_CONFIG_TYPE) &&
> + (xul_uart_request_port(port) == 0) )
> + port->type = PORT_XUL;
> +}
> +
> +static int
> +xul_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + if ( ser->type != PORT_UNKNOWN && ser->type != PORT_XUL ) {
> + printk(KERN_WARNING "xul_uart_verify_port(1)\n");
> + return -EINVAL;
> + }
> +
> + if ( (ser->irq != port->irq) ||
> + (ser->io_type != SERIAL_IO_MEM) ||
> + (ser->baud_base != port->uartclk) ||
> + (ser->iomem_base != (void*)port->mapbase) ||
> + (ser->hub6 != 0 ) ) {
> + printk(KERN_WARNING "xul_uart_verify_port(1)\n");
> + }
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +
> +static struct uart_ops xul_uart_ops = {
> + .tx_empty = xul_uart_tx_empty,
> + .set_mctrl = xul_uart_set_mctrl,
> + .get_mctrl = xul_uart_get_mctrl,
> + .stop_tx = xul_uart_stop_tx,
> + .start_tx = xul_uart_start_tx,
> + .send_xchar = xul_uart_send_xchar,
> + .stop_rx = xul_uart_stop_rx,
> + .enable_ms = xul_uart_enable_ms,
> + .break_ctl = xul_uart_break_ctl,
> + .startup = xul_uart_startup,
> + .shutdown = xul_uart_shutdown,
> + .set_termios = xul_uart_set_termios,
> +/* .pm = xul_uart_pm, Not supported yet */
> +/* .set_wake = xul_uart_set_wake, Not supported yet */
> + .type = xul_uart_type,
> + .release_port = xul_uart_release_port,
> + .request_port = xul_uart_request_port,
> + .config_port = xul_uart_config_port,
> + .verify_port = xul_uart_verify_port
> +};
> +
> +
> +/* ======================================================================== */
> +/* Interrupt handling */
> +/* ======================================================================== */
> +
> +static int
> +xul_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
> +{
> + struct tty_struct *tty = port->info->tty;
> + unsigned char ch, flag;
> + unsigned long status;
> +
> + status = in_be32((volatile unsigned *) (XUL(port) + XUL_STATUS_REG_OFFSET));
> +
> + /* While we can read, do so ! */
> + if ((status & XUL_SR_RX_FIFO_VALID_DATA) == XUL_SR_RX_FIFO_VALID_DATA) {
> +
> + /* Get the char */
> + ch = recv_char(port);
> +
> + /* Handle sysreq char */
> +#ifdef SUPPORT_SYSRQ
> + if (uart_handle_sysrq_char(port, ch, regs)) {
> + port->sysrq = 0;
> + continue;
> + }
> +#endif
> + /* Store it */
> +
> + flag = TTY_NORMAL;
> + port->icount.rx++;
> +
> + if (status & XUL_SR_PARITY_ERROR)
> + flag = TTY_PARITY;
> + else if (status & XUL_SR_FRAMING_ERROR)
> + flag = TTY_FRAME;
> +
> + tty_insert_flip_char(tty, ch, flag);
> +
> + if (status & XUL_SR_OVERRUN_ERROR) {
> + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> + }
> + }
> +
> + spin_unlock(&port->lock);
> + tty_flip_buffer_push(tty);
> + spin_lock(&port->lock);
> +
> + return 0;
> +}
> +
> +static int
> +xul_uart_int_tx_chars(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->info->xmit;
> +
> + /* Process out of band chars */
> + if (port->x_char) {
> + xmit_char(port, port->x_char);
> + port->icount.tx++;
> + port->x_char = 0;
> + return 1;
> + }
> +
> + /* Nothing to do ? */
> + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
> + xul_uart_stop_tx(port);
> + return 0;
> + }
> +
> + /* Send chars */
> + while (is_xmit_full(port) == 0) {
> + xmit_char(port, xmit->buf[xmit->tail]);
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> + port->icount.tx++;
> +
> + if (uart_circ_empty(xmit))
> + break;
> + }
> +
> + /* Wake up */
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
> + uart_write_wakeup(port);
> + }
> +
> + /* Maybe we're done after all */
> + if (uart_circ_empty(xmit)) {
> + xul_uart_stop_tx(port);
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +static irqreturn_t
> +xul_uart_int(int irq, void *dev_id, struct pt_regs *regs)
> +{
> + struct uart_port *port = (struct uart_port *) dev_id;
> + unsigned long pass = ISR_PASS_LIMIT;
> + unsigned int keepgoing;
> +
> + if ( irq != port->irq ) {
> + printk( KERN_WARNING
> + "xul_uart_int : " \
> + "Received wrong int %d. Waiting for %d\n",
> + irq, port->irq);
> + return IRQ_NONE;
> + }
> +
> + spin_lock(&port->lock);
> +
> + /* While we have stuff to do, we continue */
> + do {
> + /* If we don't find anything to do, we stop */
> + keepgoing = 0;
> +
> + /* Do we need to receive chars ? */
> + if (is_recv_empty(port) == 0) {
> + keepgoing |= xul_uart_int_rx_chars(port, regs);
> + }
> +
> + /* Do we need to send chars ? */
> + if (is_xmit_empty(port)) {
> + keepgoing |= xul_uart_int_tx_chars(port);
> + }
> +
> + /* Limit number of iteration */
> + if ( !(--pass) )
> + keepgoing = 0;
> +
> + } while (keepgoing);
> +
> + spin_unlock(&port->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +
> +/*
> + * Utility routines
> + */
> +
> +static void __init xul_uart_init_ports(void)
> +{
> + int i;
> + static int once = 1;
> +
> + /* Initialize ports only once */
> + if (!once)
> + return;
> + once = 0;
> +
> + for (i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
> + struct uart_port *xup = &xul_uart_ports[i];
> +
> + xup->line = i;
> + spin_lock_init(&xup->lock);
> + xup->uartclk = xul_data[i].uartclk / 16;
> + xup->fifosize = 16;
> + xup->iotype = UPIO_MEM;
> + xup->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
> + xup->ops = &xul_uart_ops;
> + xup->irq = xul_data[i].irq;
> + xup->mapbase = xul_data[i].mapbase;
> + }
> +}
> +
> +static void __init xul_uart_register_ports(struct uart_driver *driver)
> +{
> + int i, ret;
> +
> + for(i = 0; i < XPAR_XUARTLITE_NUM_INSTANCES; ++i) {
> + struct uart_port *port = &xul_uart_ports[i];
> + /* Add the port to the uart sub-system */
> + ret = uart_add_one_port(driver, port);
> + }
> +}
> +
> +/* ======================================================================== */
> +/* Console ( if applicable ) */
> +/* ======================================================================== */
> +
> +#ifdef CONFIG_SERIAL_XUL_CONSOLE
> +
> +static void
> +xul_console_write(struct console *co, const char *s, unsigned int count)
> +{
> + struct uart_port *port = &xul_uart_ports[co->index];
> + unsigned int i, j;
> +
> + /* Disable interrupts */
> +
> + spin_lock(&port->lock);
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
> + spin_unlock(&port->lock);
> +
> + /* Wait the TX buffer to be empty */
> + j = 5000000; /* Maximum wait */
> + while (!(is_xmit_empty(port)) &&
> + --j)
> + udelay(1);
> +
> + for (i = 0; i < count; i++, s++) {
> + if (*s == '\n')
> + xmit_char(port, '\r');
> +
> + xmit_char(port, *s);
> + }
> +
> + /* Restore interrupt state */
> + out_be32((volatile unsigned *) (XUL(port) + XUL_CONTROL_REG_OFFSET), 0);
> +}
> +
> +static int __init
> +xul_console_setup(struct console *co, char *options)
> +{
> + struct uart_port *port;
> + int baud;
> + int bits;
> + int parity;
> + int flow;
> +
> + if (co->index < 0 || co->index >= XPAR_XUARTLITE_NUM_INSTANCES)
> + return -EINVAL;
> +
> + port = &xul_uart_ports[co->index];
> +
> + /* We ioremap ourself */
> + port->membase = ioremap(port->mapbase, xul_data[co->index].size);
> +
> + if (port->membase == NULL) {
> + return -EINVAL;
> + }
> +
> + port->flags &= ~UPF_IOREMAP;
> +
> + baud = xul_data[co->index].baud;
> + parity = xul_data[co->index].parity;
> + bits = xul_data[co->index].bits;
> + flow = xul_data[co->index].flow;
> +
> + return uart_set_options(port, co, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver xul_uart_driver;
> +
> +static struct console xul_console = {
> + .name = "ttyXUL",
> + .write = xul_console_write,
> + .device = uart_console_device,
> + .setup = xul_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1, /* Specified on the cmdline (e.g. console=ttyXUL0 ) */
> + .data = &xul_uart_driver,
> +};
> +
> +
> +static int __init
> +xul_console_init(void)
> +{
> + xul_uart_init_ports();
> + register_console(&xul_console);
> + return 0;
> +}
> +
> +console_initcall(xul_console_init);
> +
> +#define XUL_CONSOLE &xul_console
> +#else
> +#define XUL_CONSOLE NULL
> +#endif
> +
> +
> +/* ======================================================================== */
> +/* UART Driver */
> +/* ======================================================================== */
> +
> +static struct uart_driver xul_uart_driver = {
> + .owner = THIS_MODULE,
> + .driver_name = "xul_uart",
> + .dev_name = "ttyXUL",
> + .major = SERIAL_XUL_MAJOR,
> + .minor = SERIAL_XUL_MINOR,
> + .nr = XPAR_XUARTLITE_NUM_INSTANCES,
> + .cons = XUL_CONSOLE,
> +};
> +
> +
> +/* ======================================================================== */
> +/* Platform Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +xul_uart_probe(struct platform_device *dev)
> +{
> + /* Probe does nothing */
> + return 0;
> +}
> +
> +static int
> +xul_uart_remove(struct platform_device *dev)
> +{
> + struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
> +
> + platform_set_drvdata(dev, NULL);
> +
> + if (port)
> + uart_remove_one_port(&xul_uart_driver, port);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int
> +xul_uart_suspend(struct platform_device *dev, pm_message_t state)
> +{
> + struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
> +
> + if (port)
> + uart_suspend_port(&xul_uart_driver, port);
> +
> + return 0;
> +}
> +
> +static int
> +xul_uart_resume(struct platform_device *dev)
> +{
> + struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
> +
> + if (port)
> + uart_resume_port(&xul_uart_driver, port);
> +
> + return 0;
> +}
> +#endif
> +
> +static struct platform_driver xul_uart_platform_driver = {
> + .probe = xul_uart_probe,
> + .remove = xul_uart_remove,
> +#ifdef CONFIG_PM
> + .suspend = xul_uart_suspend,
> + .resume = xul_uart_resume,
> +#endif
> + .driver = {
> + .name = "xul_uart"
> + },
> +};
> +
> +
> +/* ======================================================================== */
> +/* Module */
> +/* ======================================================================== */
> +
> +static int __init
> +xul_uart_init(void)
> +{
> + int ret;
> +
> + printk(KERN_INFO "Serial: Xilinx UART Lite driver\n");
> +
> + xul_uart_init_ports();
> +
> + ret = uart_register_driver(&xul_uart_driver);
> +
> + if (ret == 0) {
> + xul_uart_register_ports(&xul_uart_driver);
> +
> + ret = platform_driver_register(&xul_uart_platform_driver);
> +
> + if (ret) {
> + printk(KERN_WARNING "platform_driver_register failed! :%i\n", ret);
> + uart_unregister_driver(&xul_uart_driver);
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void __exit
> +xul_uart_exit(void)
> +{
> + platform_driver_unregister(&xul_uart_platform_driver);
> + uart_unregister_driver(&xul_uart_driver);
> +}
> +
> +
> +module_init(xul_uart_init);
> +module_exit(xul_uart_exit);
> +
> +MODULE_AUTHOR("David Bolcsfoldi <dbolcsfoldi@gmail.com>");
> +MODULE_DESCRIPTION("Xilinx UART Lite");
> +MODULE_LICENSE("GPL");
> +
>
> ------------------------------------------------------------------------
>
> --- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-07 10:41:50.000000000 -0700
> @@ -69,6 +69,7 @@
> .device_list = (enum ppc_sys_devices[])
> {
> VIRTEX_UART,
> + VIRTEX_XUL_UART,
> },
> },
> };
>
> ------------------------------------------------------------------------
>
> --- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
> +++ patched/include/linux/serial_core.h 2006-10-07 10:52:24.000000000 -0700
> @@ -132,6 +132,8 @@
>
> #define PORT_S3C2412 73
>
> +/* Xilinx UART Lite */
> +#define PORT_XUL 74
>
> #ifdef __KERNEL__
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
--
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
[-- Attachment #2: Type: text/html, Size: 30125 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-10 20:49 [PATCH] Xilinx UART Lite 2.6.18 driver David Bolcsfoldi
2006-10-10 22:04 ` Grant Likely
2006-10-11 22:06 ` David H. Lynch Jr.
@ 2006-10-12 10:34 ` Peter Korsgaard
2006-10-12 21:12 ` David Bolcsfoldi
2 siblings, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-12 10:34 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi David,
David> here's a set of patches that adds support for Xilinx UART lite
David> devices. It has been tested on an ML403-FX using xapp902
David> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox
David> userspace.
I guess you didn't know, but there already exists a uartlite driver!
It unfortunately didn't made it into 2.6.19-rc1 because Russell
stopped maintaining serial stuff, but it's in -mm.
It also has an official lanana.org assigned set of device nodes.
I didn't look at your patch yet, but I think it would be more useful
to add any features missing to my driver than writing yet another
driver (I think we're up to 3 now).
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-12 10:34 ` Peter Korsgaard
@ 2006-10-12 21:12 ` David Bolcsfoldi
2006-10-13 5:21 ` David Bolcsfoldi
` (2 more replies)
0 siblings, 3 replies; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-12 21:12 UTC (permalink / raw)
To: linuxppc-embedded
No I did not know that unfortunately, it could have saved me some work.
You are of course right and I'd much prefer to make changes to your driver
instead of writing another one.
I've noticed that in the probe function it tries to get some resources
from the platform_device structure but it looks like that this
operation will always fail unless I add a 'uartlite' platform device
or have I completely misunderstood how platform devices work?
But yes, I will try to add support for the things I need to this
driver instead, most importantly early console support and move the
#defines for register offsets and such into a separate header file per
Grants comment.
Cheers,
David
On 10/12/06, Peter Korsgaard <jacmet@sunsite.dk> wrote:
> >>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
>
> Hi David,
>
> David> here's a set of patches that adds support for Xilinx UART lite
> David> devices. It has been tested on an ML403-FX using xapp902
> David> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox
> David> userspace.
>
> I guess you didn't know, but there already exists a uartlite driver!
> It unfortunately didn't made it into 2.6.19-rc1 because Russell
> stopped maintaining serial stuff, but it's in -mm.
>
> It also has an official lanana.org assigned set of device nodes.
>
> I didn't look at your patch yet, but I think it would be more useful
> to add any features missing to my driver than writing yet another
> driver (I think we're up to 3 now).
>
> --
> Bye, Peter Korsgaard
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-12 21:12 ` David Bolcsfoldi
@ 2006-10-13 5:21 ` David Bolcsfoldi
2006-10-13 7:04 ` David H. Lynch Jr.
2006-10-13 7:11 ` Peter Korsgaard
2006-10-13 6:48 ` David H. Lynch Jr.
2006-10-13 7:08 ` Peter Korsgaard
2 siblings, 2 replies; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-13 5:21 UTC (permalink / raw)
To: linuxppc-embedded
Here's an initial patch based on a modified uartlite (by Peter
Korsgaard), it's by no means ment to be final and any feedback would
be appreciated.
What I have changed:
- Early console support.
Since the platform bus isn't initialized by the time the first printk
comes I've added a call 'early_uart_get_pdev' fashioned after the CPM
serial driver.
- Platform device.
The 'uartlite' is now a platform device although I am not entirely
happy how this is done since there's only one VIRTEX_UARTLITE device
with id of 0 although there might be several more described by the
plafrom_data. Maybe the additional devices can be added to the
platform bus in the probe call or would it be better to add these
devices at compile time to the list of platform_devices in virtex.c?
- readb/writeb to in_be32/out_be32.
For some reason on my board the readb and writeb don't behave
correctly when reading and writing to the uartlite device. I haven't
looked into it but if this is unacceptable I will try to revert to
readb/writeb.
- Embedded boot serial support.
There's now support for embedded boot serial I/O over uartlite device 0.
- uartlite.h
A shared header file between the embedded boot serial driver and the
real one with all the reg offsets and such. I don't know if the
location for this file is ok though.
diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c
patched-uartlite/arch/ppc/boot/common/misc-common.c
--- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04
14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/common/misc-common.c 2006-10-12
12:47:31.000000000 -0700
@@ -57,7 +57,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
diff -urN 2.6.18/arch/ppc/boot/simple/Makefile
patched-uartlite/arch/ppc/boot/simple/Makefile
--- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/simple/Makefile 2006-10-12
12:45:53.000000000 -0700
@@ -205,6 +205,7 @@
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff -urN 2.6.18/arch/ppc/boot/simple/misc.c
patched-uartlite/arch/ppc/boot/simple/misc.c
--- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/boot/simple/misc.c 2006-10-12
12:48:01.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
diff -urN 2.6.18/arch/ppc/boot/simple/uartlite_tty.c
patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c
--- 2.6.18/arch/ppc/boot/simple/uartlite_tty.c 1969-12-31
16:00:00.000000000 -0800
+++ patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c 2006-10-12
22:10:44.000000000 -0700
@@ -0,0 +1,69 @@
+/*
+ * Xilinx UART Lite support.
+ * Right now it only works over UART0 and none other.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <asm/uartlite.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+static inline int is_xmit_full(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_TXFULL) == ULITE_STATUS_TXFULL);
+}
+
+static inline int is_recv_empty(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_RXVALID) != ULITE_STATUS_RXVALID);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
+ default:
+ goto out;
+ }
+
+out:
+ return -1;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
+ out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_TX), c);
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+ return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_RX));
+}
+
+int serial_tstc(unsigned long com_port)
+{
+ return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+}
+
Binary files 2.6.18/arch/ppc/boot/simple/.uartlite_tty.c.swp and
patched-uartlite/arch/ppc/boot/simple/.uartlite_tty.c.swp differ
diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.c
patched-uartlite/arch/ppc/platforms/4xx/virtex.c
--- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/virtex.c 2006-10-12
16:37:23.000000000 -0700
@@ -46,11 +46,71 @@
{ }, /* terminated by empty record */
};
+#define XPAR_UARTLITE(num) { \
+ .mapbase = XPAR_XUL_UART_##num##_BASEADDR, \
+ .irq = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
+ .size = (XPAR_XUL_UART_##num##_HIGHADDR -
XPAR_XUL_UART_##num##_BASEADDR) + 1, \
+ .baud = XPAR_XUL_UART_##num##_BAUDRATE, \
+ .bits = XPAR_XUL_UART_##num##_DATA_BITS, \
+ .parity = XPAR_XUL_UART_##num##_USE_PARITY, \
+ .odd_parity = XPAR_XUL_UART_##num##_ODD_PARITY, \
+}
+
+struct plat_uartlite_port uartlite_platform_data[] = {
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ XPAR_UARTLITE(0),
+#endif
+#ifdef XPAR_XUL_UART_1_BASEADDR
+ XPAR_UARTLITE(1),
+#endif
+#ifdef XPAR_XUL_UART_2_BASEADDR
+ XPAR_UARTLITE(2),
+#endif
+#ifdef XPAR_XUL_UART_3_BASEADDR
+ XPAR_UARTLITE(3),
+#endif
+ { }, /* terminated by empty record */
+};
+
struct platform_device ppc_sys_platform_devices[] = {
[VIRTEX_UART] = {
.name = "serial8250",
.id = 0,
.dev.platform_data = serial_platform_data,
},
+
+ [VIRTEX_UARTLITE] = {
+ .name = "uartlite",
+ .id = 0,
+ .dev.platform_data = uartlite_platform_data,
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ .num_resources = 2,
+ .resource = (struct resource[]) {
+ {
+ .start = XPAR_XUL_UART_0_BASEADDR,
+ .end = XPAR_XUL_UART_0_HIGHADDR,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .end = XPAR_INTC_0_XUL_UART_0_VEC_ID,
+ .flags = IORESOURCE_IRQ,
+ },
+ },
+#endif /* XPAR_XUL_UART_0_BASEADDR */
+ },
};
+/* For early console on the uartlite serial port some way of
+ * getting to the platform_device is needed */
+
+struct platform_device* early_uart_get_pdev(int dev)
+{
+ if (dev < 0 ||
+ dev >= NUM_PPC_SYS_DEVS) {
+ return NULL;
+ }
+
+ return &ppc_sys_platform_devices[dev];
+}
+
diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.h
patched-uartlite/arch/ppc/platforms/4xx/virtex.h
--- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/virtex.h 2006-10-12
16:37:41.000000000 -0700
@@ -27,8 +27,21 @@
/* Device type enumeration for platform bus definitions */
#ifndef __ASSEMBLY__
enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
+ VIRTEX_UART,
+ VIRTEX_UARTLITE,
+ NUM_PPC_SYS_DEVS,
};
+
+struct plat_uartlite_port {
+ unsigned int mapbase;
+ unsigned int irq;
+ unsigned int size;
+ unsigned int baud;
+ unsigned char bits;
+ unsigned char parity;
+ unsigned char odd_parity;
+};
+
#endif
#endif /* __ASM_VIRTEX_H__ */
diff -urN 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c
patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c
--- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04
14:31:15.000000000 -0700
+++ patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-12
13:15:36.000000000 -0700
@@ -65,10 +65,11 @@
.ppc_sys_name = "Xilinx ML403 Reference Design",
.mask = 0x00000000,
.value = 0x00000000,
- .num_devices = 1,
+ .num_devices = 2,
.device_list = (enum ppc_sys_devices[])
{
VIRTEX_UART,
+ VIRTEX_UARTLITE,
},
},
};
diff -urN 2.6.18/drivers/serial/Kconfig patched-uartlite/drivers/serial/Kconfig
--- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
+++ patched-uartlite/drivers/serial/Kconfig 2006-10-12 12:15:32.000000000 -0700
@@ -511,6 +511,25 @@
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 -urN 2.6.18/drivers/serial/Makefile
patched-uartlite/drivers/serial/Makefile
--- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
+++ patched-uartlite/drivers/serial/Makefile 2006-10-12 12:15:32.000000000 -0700
@@ -55,4 +55,5 @@
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 -urN 2.6.18/drivers/serial/uartlite.c
patched-uartlite/drivers/serial/uartlite.c
--- 2.6.18/drivers/serial/uartlite.c 1969-12-31 16:00:00.000000000 -0800
+++ patched-uartlite/drivers/serial/uartlite.c 2006-10-12
22:10:57.000000000 -0700
@@ -0,0 +1,551 @@
+/*
+ * 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>
+#include <asm/uartlite.h>
+
+#define ULITE_MAJOR 204
+#define ULITE_MINOR 187
+#define ULITE_NR_UARTS 4
+
+static struct uart_port ports[ULITE_NR_UARTS];
+
+/* Place-holder for board-specific stuff */
+struct platform_device* __attribute__ ((weak)) __init
+early_uart_get_pdev(int index)
+{
+ return NULL;
+}
+
+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 = in_be32((unsigned volatile *) (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) {
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), port->x_char);
+ port->x_char = 0;
+ port->icount.tx++;
+ return 1;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ return 0;
+
+ out_be32((unsigned volatile *) (port->membase + 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);
+
+ 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;
+
+ spin_lock(&port->lock); /* Lock the port in case of printk */
+
+ do {
+ int stat = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
+ busy = ulite_receive(port, stat);
+ busy |= ulite_transmit(port, stat);
+ } while (busy);
+
+ spin_unlock(&port->lock);
+
+ 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 = in_be32((unsigned volatile *) (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, in_be32((unsigned volatile *) (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;
+
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
+
+ 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)
+{
+ struct plat_uartlite_port *uport;
+ 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 */
+ uport = &((struct plat_uartlite_port *)port->dev->platform_data)[port->line];
+
+ baud = uart_get_baud_rate(port, termios, old, uport->baud, uport->baud);
+ 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;
+ }
+
+ if (port->flags & UPF_IOREMAP) {
+ 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
+};
+
+static inline void ulite_init_port(struct uart_port *port)
+{
+ port->uartclk = 0;
+ port->membase = 0;
+ port->fifosize = 16;
+ port->regshift = 2;
+ port->iobase = 1; /* Mark port in use */
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &ulite_ops;
+ port->type = PORT_UNKNOWN;
+}
+
+#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 (in_be32((unsigned volatile *) (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);
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), ch);
+}
+
+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 = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS))
& ULITE_STATUS_IE;
+
+ //writeb(0, port->membase + ULITE_CONTROL);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL), 0);
+
+ uart_console_write(port, s, count, ulite_console_putchar);
+
+ ulite_console_wait_tx(port);
+
+ /* restore interrupt state */
+ if (ier)
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init ulite_console_setup(struct console *co, char *options)
+{
+ int i;
+ struct uart_port *port;
+ struct platform_device *pdev;
+ struct plat_uartlite_port *uport;
+
+ if (co->index < 0 || co->index >= ULITE_NR_UARTS)
+ return -EINVAL;
+
+ port = &ports[co->index];
+
+ /* not initialized yet? */
+ if (!port->membase) {
+ /* We might be early console */
+ pdev = early_uart_get_pdev(VIRTEX_UARTLITE);
+
+ if (pdev == NULL) {
+ return -ENODEV;
+ }
+
+ uport = pdev->dev.platform_data;
+
+ for (i = 0; i <= co->index; ++i) {
+ /* We need to count the number of ports available */
+ /* List of ports is terminated by a 0 record */
+
+ if (uport[i].baud == 0) {
+ return -ENODEV;
+ }
+ }
+
+ ulite_init_port(port);
+
+ port->irq = uport[co->index].irq;
+ port->mapbase = uport[co->index].mapbase;
+ port->line = co->index;
+ spin_lock_init(&port->lock);
+ port->membase = ioremap(port->mapbase, ULITE_REGION);
+
+ if(port->membase == NULL) {
+ port->iobase = 0;
+ return -EINVAL;
+ }
+
+ /* Clear ioremap since this port has been mapped already */
+ port->flags &= ~UPF_IOREMAP;
+ }
+
+ 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;
+ int ret;
+
+ if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+ return -EINVAL;
+
+ if (ports[pdev->id].membase) {
+ if (ports[pdev->id].flags & UPF_IOREMAP) {
+ return -EBUSY; /* Port is busy */
+ }
+
+ else {
+ /* This port as be remapped so it must have been an early console */
+ port = &ports[pdev->id];
+ goto add_port;
+ }
+ }
+
+ 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];
+
+ ulite_init_port(port);
+
+ port->mapbase = res->start;
+ port->irq = res2->start;
+ port->line = pdev->id;
+
+add_port:
+ port->dev = &pdev->dev;
+
+ ret = uart_add_one_port(&ulite_uart_driver, port);
+
+ if(ret == 0)
+ platform_set_drvdata(pdev, port);
+
+ 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");
Binary files 2.6.18/drivers/serial/.uartlite.c.swp and
patched-uartlite/drivers/serial/.uartlite.c.swp differ
diff -urN 2.6.18/include/asm-ppc/uartlite.h
patched-uartlite/include/asm-ppc/uartlite.h
--- 2.6.18/include/asm-ppc/uartlite.h 1969-12-31 16:00:00.000000000 -0800
+++ patched-uartlite/include/asm-ppc/uartlite.h 2006-10-12
21:53:00.000000000 -0700
@@ -0,0 +1,28 @@
+#ifndef __ASM_UARTLITE_H__
+#define __ASM_UARTLITE_H__
+
+/* 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
+
+#endif /* __ASM_UARTLITE_H__ */
+
diff -urN 2.6.18/include/linux/serial_core.h
patched-uartlite/include/linux/serial_core.h
--- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
+++ patched-uartlite/include/linux/serial_core.h 2006-10-12
12:15:32.000000000 -0700
@@ -132,6 +132,8 @@
#define PORT_S3C2412 73
+/* Xilinx uartlite */
+#define PORT_UARTLITE 74
#ifdef __KERNEL__
diff -urN 2.6.18/MAINTAINERS patched-uartlite/MAINTAINERS
--- 2.6.18/MAINTAINERS 2006-10-04 14:31:14.000000000 -0700
+++ patched-uartlite/MAINTAINERS 2006-10-12 12:15:32.000000000 -0700
@@ -3311,6 +3311,12 @@
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
--
Cheers,
David
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-12 21:12 ` David Bolcsfoldi
2006-10-13 5:21 ` David Bolcsfoldi
@ 2006-10-13 6:48 ` David H. Lynch Jr.
2006-10-13 7:15 ` Peter Korsgaard
2006-10-13 7:08 ` Peter Korsgaard
2 siblings, 1 reply; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-13 6:48 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 3876 bytes --]
David Bolcsfoldi wrote:
> No I did not know that unfortunately, it could have saved me some work.
> You are of course right and I'd much prefer to make changes to your driver
> instead of writing another one.
>
I am sorry you put so much effort in. However, you could have
checked the archives.
I think there are atleast 3 different UartLite drivers posted since
January.
It would be really nice if we could all standardize on one driver.
But I would not sweat this too much.
Peter ignored the fact that my driver was posted here in January,
too and went off and wrote his own
which does not have early serial port - yours and mine do.
and does not have polled support - mine does.
and does not have DCR support - there is another one out there that
has DCR support.
and I can not get to work on my hardware - the only Xilinx V4 based
product that actually defaults to a UartLite
> I've noticed that in the probe function it tries to get some resources
> from the platform_device structure but it looks like that this
> operation will always fail unless I add a 'uartlite' platform device
> or have I completely misunderstood how platform devices work?
>
Peter's driver uses the IORESOURCE requests to pull platform data.
Most other serial platformdevices pull a uart_port object.
My limited understanding of IORESOURCE is that it is not
sufficiently deep to support
the parameters that are needed to support UartLite such as a DCR
flag and a regoffset.
Counting yours that is 4.
> But yes, I will try to add support for the things I need to this
> driver instead, most importantly early console support and move the
> #defines for register offsets and such into a separate header file per
> Grants comments
>
You are welcome to do that. I already patched his driver to work
with my early console support as well as adding the boot-bash stuff
similar to yours. But I gave up actually using it when I could not
get it to work.
Next time I get an opportunity I am going to try to setup an ml403
to atleast verify that Peter's driver is working there.
> Cheers,
> David
>
> On 10/12/06, Peter Korsgaard <jacmet@sunsite.dk> wrote:
>
>>>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
>>>>>>>
>> Hi David,
>>
>> David> here's a set of patches that adds support for Xilinx UART lite
>> David> devices. It has been tested on an ML403-FX using xapp902
>> David> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox
>> David> userspace.
>>
>> I guess you didn't know, but there already exists a uartlite driver!
>> It unfortunately didn't made it into 2.6.19-rc1 because Russell
>> stopped maintaining serial stuff, but it's in -mm.
>>
>> It also has an official lanana.org assigned set of device nodes.
>>
>> I didn't look at your patch yet, but I think it would be more useful
>> to add any features missing to my driver than writing yet another
>> driver (I think we're up to 3 now).
>>
>> --
>> Bye, Peter Korsgaard
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>
>>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
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
[-- Attachment #2: Type: text/html, Size: 5960 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 5:21 ` David Bolcsfoldi
@ 2006-10-13 7:04 ` David H. Lynch Jr.
2006-10-13 7:22 ` Peter Korsgaard
2006-10-13 7:11 ` Peter Korsgaard
1 sibling, 1 reply; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-13 7:04 UTC (permalink / raw)
To: David Bolcsfoldi; +Cc: linuxppc-embedded
David Bolcsfoldi wrote:
> Here's an initial patch based on a modified uartlite (by Peter
> Korsgaard), it's by no means ment to be final and any feedback would
> be appreciated.
>
> What I have changed:
>
> - Early console support.
>
> Since the platform bus isn't initialized by the time the first printk
> comes I've added a call 'early_uart_get_pdev' fashioned after the CPM
> serial driver.
>
If you want to mess with this my recomendation would be to switch to
passing a uart_port
like the 8250 does. You can find 8250 early serial init code in
xilinx_ml403.c
I beleive the init routine is called early_console_init().
Nobody has given me a reason yet why the UartLite should init
different from the 8250,
and absent a reason, I would mimic the 8250. I do not think there is
reason for a different routing name.
The ml403 8250 init code deals with multiple 8250's, I did the same
with UartLite.
I am not sure I did nto follow everything on linux-serial - but I
think Peter was asked to remove support
for additional uarts. I am not sure why.
> - Platform device.
>
> The 'uartlite' is now a platform device although I am not entirely
> happy how this is done since there's only one VIRTEX_UARTLITE device
> with id of 0 although there might be several more described by the
> plafrom_data. Maybe the additional devices can be added to the
> platform bus in the probe call or would it be better to add these
> devices at compile time to the list of platform_devices in virtex.c?
>
> - readb/writeb to in_be32/out_be32.
>
> For some reason on my board the readb and writeb don't behave
> correctly when reading and writing to the uartlite device. I haven't
> looked into it but if this is unacceptable I will try to revert to
> readb/writeb.
>
I would appreciate some further elaboration. I think they were
working for me when I tried Peter's driver.
I even think that is one change I made to my own driver based on
Peter's.
But maybe I am wrong and that has something to do with my inability
to get Peter's driver working on my hardware.
> - Embedded boot serial support.
>
> There's now support for embedded boot serial I/O over uartlite device 0.
>
> - uartlite.h
>
To be consistent with other uarts I think it should be
include/linux/serial_uartlite.h
> A shared header file between the embedded boot serial driver and the
> real one with all the reg offsets and such. I don't know if the
> location for this file is ok though.
>
Finally, I think that this really needs submitted to linux-serial if
you are looking to get it in.
> diff -urN 2.6.18/arch/ppc/boot/common/misc-common.c
> patched-uartlite/arch/ppc/boot/common/misc-common.c
> --- 2.6.18/arch/ppc/boot/common/misc-common.c 2006-10-04
> 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/common/misc-common.c 2006-10-12
> 12:47:31.000000000 -0700
> @@ -57,7 +57,8 @
>
Just a minor nit, but you can make the patches simpler by adding
SERIAL_UARTLITE_CONSOLE into the middle of the list instead of the end.
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> extern unsigned long com_port;
>
> extern int serial_tstc(unsigned long com_port);
> @@ -80,7 +81,8 @@
> {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> if(keyb_present)
> return (CRT_tstc() || serial_tstc(com_port));
> else
> @@ -95,7 +97,8 @@
> while (1) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> if (serial_tstc(com_port))
> return (serial_getc(com_port));
> #endif /* serial console */
> @@ -112,7 +115,8 @@
>
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' )
> serial_putc(com_port, '\r');
> @@ -161,7 +165,8 @@
> while ( ( c = *s++ ) != '\0' ) {
> #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
> serial_putc(com_port, c);
> if ( c == '\n' ) serial_putc(com_port, '\r');
> #endif /* serial console */
> diff -urN 2.6.18/arch/ppc/boot/simple/Makefile
> patched-uartlite/arch/ppc/boot/simple/Makefile
> --- 2.6.18/arch/ppc/boot/simple/Makefile 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/simple/Makefile 2006-10-12
> 12:45:53.000000000 -0700
> @@ -205,6 +205,7 @@
> endif
> boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
> boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
> +boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
>
> LIBS := $(common)/lib.a $(bootlib)/lib.a
> ifeq ($(CONFIG_PPC_PREP),y)
> diff -urN 2.6.18/arch/ppc/boot/simple/misc.c
> patched-uartlite/arch/ppc/boot/simple/misc.c
> --- 2.6.18/arch/ppc/boot/simple/misc.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/boot/simple/misc.c 2006-10-12
> 12:48:01.000000000 -0700
> @@ -48,7 +48,8 @@
> #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_VGA_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
> && !defined(CONFIG_GEMINI)
> #define INTERACTIVE_CONSOLE 1
> #endif
> diff -urN 2.6.18/arch/ppc/boot/simple/uartlite_tty.c
> patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c
> --- 2.6.18/arch/ppc/boot/simple/uartlite_tty.c 1969-12-31
> 16:00:00.000000000 -0800
> +++ patched-uartlite/arch/ppc/boot/simple/uartlite_tty.c 2006-10-12
> 22:10:44.000000000 -0700
> @@ -0,0 +1,69 @@
> +/*
> + * Xilinx UART Lite support.
> + * Right now it only works over UART0 and none other.
> + *
> + * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <asm/io.h>
> +#include <asm/uartlite.h>
> +#include <platforms/4xx/xparameters/xparameters.h>
> +
> +static inline int is_xmit_full(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
> ULITE_STATUS_TXFULL) == ULITE_STATUS_TXFULL);
> +}
> +
> +static inline int is_recv_empty(unsigned int address)
> +{
> + return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
> ULITE_STATUS_RXVALID) != ULITE_STATUS_RXVALID);
> +}
> +
> +unsigned long serial_init(int chan, void *ignored)
> +{
> + switch (chan) {
> + #ifdef XPAR_XUL_UART_0_BASEADDR
> + case 0:
> + return XPAR_XUL_UART_0_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_1_BASEADDR
> + case 1:
> + return XPAR_XUL_UART_1_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_2_BASEADDR
> + case 2:
> + return XPAR_XUL_UART_2_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_3_BASEADDR
> + case 3:
> + return XPAR_XUL_UART_3_BASEADDR;
> + #endif
> + default:
> + goto out;
> + }
> +
> +out:
> + return -1;
> +}
> +
> +void serial_putc(unsigned long com_port, unsigned char c)
> +{
> + while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
> + out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_TX), c);
> +}
> +
> +unsigned char serial_getc(unsigned long com_port)
> +{
> + while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> + return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_RX));
> +}
> +
> +int serial_tstc(unsigned long com_port)
> +{
> + return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
> +}
> +
> Binary files 2.6.18/arch/ppc/boot/simple/.uartlite_tty.c.swp and
> patched-uartlite/arch/ppc/boot/simple/.uartlite_tty.c.swp differ
> diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.c
> patched-uartlite/arch/ppc/platforms/4xx/virtex.c
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.c 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/virtex.c 2006-10-12
> 16:37:23.000000000 -0700
> @@ -46,11 +46,71 @@
> { }, /* terminated by empty record */
> };
>
> +#define XPAR_UARTLITE(num) { \
> + .mapbase = XPAR_XUL_UART_##num##_BASEADDR, \
> + .irq = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
> + .size = (XPAR_XUL_UART_##num##_HIGHADDR -
> XPAR_XUL_UART_##num##_BASEADDR) + 1, \
> + .baud = XPAR_XUL_UART_##num##_BAUDRATE, \
> + .bits = XPAR_XUL_UART_##num##_DATA_BITS, \
> + .parity = XPAR_XUL_UART_##num##_USE_PARITY, \
> + .odd_parity = XPAR_XUL_UART_##num##_ODD_PARITY, \
> +}
> +
> +struct plat_uartlite_port uartlite_platform_data[] = {
> +#ifdef XPAR_XUL_UART_0_BASEADDR
> + XPAR_UARTLITE(0),
> +#endif
> +#ifdef XPAR_XUL_UART_1_BASEADDR
> + XPAR_UARTLITE(1),
> +#endif
> +#ifdef XPAR_XUL_UART_2_BASEADDR
> + XPAR_UARTLITE(2),
> +#endif
> +#ifdef XPAR_XUL_UART_3_BASEADDR
> + XPAR_UARTLITE(3),
> +#endif
> + { }, /* terminated by empty record */
> +};
> +
> struct platform_device ppc_sys_platform_devices[] = {
> [VIRTEX_UART] = {
> .name = "serial8250",
> .id = 0,
> .dev.platform_data = serial_platform_data,
> },
> +
> + [VIRTEX_UARTLITE] = {
> + .name = "uartlite",
> + .id = 0,
> + .dev.platform_data = uartlite_platform_data,
> +#ifdef XPAR_XUL_UART_0_BASEADDR
> + .num_resources = 2,
> + .resource = (struct resource[]) {
> + {
> + .start = XPAR_XUL_UART_0_BASEADDR,
> + .end = XPAR_XUL_UART_0_HIGHADDR,
> + .flags = IORESOURCE_MEM,
> + },
> + {
> + .start = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .end = XPAR_INTC_0_XUL_UART_0_VEC_ID,
> + .flags = IORESOURCE_IRQ,
> + },
> + },
> +#endif /* XPAR_XUL_UART_0_BASEADDR */
> + },
> };
>
> +/* For early console on the uartlite serial port some way of
> + * getting to the platform_device is needed */
> +
> +struct platform_device* early_uart_get_pdev(int dev)
> +{
> + if (dev < 0 ||
> + dev >= NUM_PPC_SYS_DEVS) {
> + return NULL;
> + }
> +
> + return &ppc_sys_platform_devices[dev];
> +}
> +
> diff -urN 2.6.18/arch/ppc/platforms/4xx/virtex.h
> patched-uartlite/arch/ppc/platforms/4xx/virtex.h
> --- 2.6.18/arch/ppc/platforms/4xx/virtex.h 2006-10-04 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/virtex.h 2006-10-12
> 16:37:41.000000000 -0700
> @@ -27,8 +27,21 @@
> /* Device type enumeration for platform bus definitions */
> #ifndef __ASSEMBLY__
> enum ppc_sys_devices {
> - VIRTEX_UART, NUM_PPC_SYS_DEVS,
> + VIRTEX_UART,
> + VIRTEX_UARTLITE,
> + NUM_PPC_SYS_DEVS,
> };
> +
> +struct plat_uartlite_port {
> + unsigned int mapbase;
> + unsigned int irq;
> + unsigned int size;
> + unsigned int baud;
> + unsigned char bits;
> + unsigned char parity;
> + unsigned char odd_parity;
> +};
> +
> #endif
>
> #endif /* __ASM_VIRTEX_H__ */
> diff -urN 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c
> patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c
> --- 2.6.18/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-04
> 14:31:15.000000000 -0700
> +++ patched-uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-12
> 13:15:36.000000000 -0700
> @@ -65,10 +65,11 @@
> .ppc_sys_name = "Xilinx ML403 Reference Design",
> .mask = 0x00000000,
> .value = 0x00000000,
> - .num_devices = 1,
> + .num_devices = 2,
> .device_list = (enum ppc_sys_devices[])
> {
> VIRTEX_UART,
> + VIRTEX_UARTLITE,
> },
> },
> };
> diff -urN 2.6.18/drivers/serial/Kconfig patched-uartlite/drivers/serial/Kconfig
> --- 2.6.18/drivers/serial/Kconfig 2006-10-04 14:31:18.000000000 -0700
> +++ patched-uartlite/drivers/serial/Kconfig 2006-10-12 12:15:32.000000000 -0700
> @@ -511,6 +511,25 @@
> 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 -urN 2.6.18/drivers/serial/Makefile
> patched-uartlite/drivers/serial/Makefile
> --- 2.6.18/drivers/serial/Makefile 2006-10-04 14:31:18.000000000 -0700
> +++ patched-uartlite/drivers/serial/Makefile 2006-10-12 12:15:32.000000000 -0700
> @@ -55,4 +55,5 @@
> 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 -urN 2.6.18/drivers/serial/uartlite.c
> patched-uartlite/drivers/serial/uartlite.c
> --- 2.6.18/drivers/serial/uartlite.c 1969-12-31 16:00:00.000000000 -0800
> +++ patched-uartlite/drivers/serial/uartlite.c 2006-10-12
> 22:10:57.000000000 -0700
> @@ -0,0 +1,551 @@
> +/*
> + * 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>
> +#include <asm/uartlite.h>
> +
> +#define ULITE_MAJOR 204
> +#define ULITE_MINOR 187
> +#define ULITE_NR_UARTS 4
> +
> +static struct uart_port ports[ULITE_NR_UARTS];
> +
> +/* Place-holder for board-specific stuff */
> +struct platform_device* __attribute__ ((weak)) __init
> +early_uart_get_pdev(int index)
> +{
> + return NULL;
> +}
> +
> +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 = in_be32((unsigned volatile *) (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) {
> + out_be32((unsigned volatile *) (port->membase + ULITE_TX), port->x_char);
> + port->x_char = 0;
> + port->icount.tx++;
> + return 1;
> + }
> +
> + if (uart_circ_empty(xmit) || uart_tx_stopped(port))
> + return 0;
> +
> + out_be32((unsigned volatile *) (port->membase + 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);
> +
> + 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;
> +
> + spin_lock(&port->lock); /* Lock the port in case of printk */
> +
> + do {
> + int stat = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
> + busy = ulite_receive(port, stat);
> + busy |= ulite_transmit(port, stat);
> + } while (busy);
> +
> + spin_unlock(&port->lock);
> +
> + 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 = in_be32((unsigned volatile *) (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, in_be32((unsigned volatile *) (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;
> +
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_IE);
> +
> + 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)
> +{
> + struct plat_uartlite_port *uport;
> + 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 */
> + uport = &((struct plat_uartlite_port *)port->dev->platform_data)[port->line];
> +
> + baud = uart_get_baud_rate(port, termios, old, uport->baud, uport->baud);
> + 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;
> + }
> +
> + if (port->flags & UPF_IOREMAP) {
> + 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
> +};
> +
> +static inline void ulite_init_port(struct uart_port *port)
> +{
> + port->uartclk = 0;
> + port->membase = 0;
> + port->fifosize = 16;
> + port->regshift = 2;
> + port->iobase = 1; /* Mark port in use */
> + port->iotype = UPIO_MEM;
> + port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
> + port->ops = &ulite_ops;
> + port->type = PORT_UNKNOWN;
> +}
> +
> +#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 (in_be32((unsigned volatile *) (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);
> + out_be32((unsigned volatile *) (port->membase + ULITE_TX), ch);
> +}
> +
> +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 = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS))
> & ULITE_STATUS_IE;
> +
> + //writeb(0, port->membase + ULITE_CONTROL);
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL), 0);
> +
> + uart_console_write(port, s, count, ulite_console_putchar);
> +
> + ulite_console_wait_tx(port);
> +
> + /* restore interrupt state */
> + if (ier)
> + out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
> ULITE_CONTROL_IE);
> +
> + if (locked)
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int __init ulite_console_setup(struct console *co, char *options)
> +{
> + int i;
> + struct uart_port *port;
> + struct platform_device *pdev;
> + struct plat_uartlite_port *uport;
> +
> + if (co->index < 0 || co->index >= ULITE_NR_UARTS)
> + return -EINVAL;
> +
> + port = &ports[co->index];
> +
> + /* not initialized yet? */
> + if (!port->membase) {
> + /* We might be early console */
> + pdev = early_uart_get_pdev(VIRTEX_UARTLITE);
> +
> + if (pdev == NULL) {
> + return -ENODEV;
> + }
> +
> + uport = pdev->dev.platform_data;
> +
> + for (i = 0; i <= co->index; ++i) {
> + /* We need to count the number of ports available */
> + /* List of ports is terminated by a 0 record */
> +
> + if (uport[i].baud == 0) {
> + return -ENODEV;
> + }
> + }
> +
> + ulite_init_port(port);
> +
> + port->irq = uport[co->index].irq;
> + port->mapbase = uport[co->index].mapbase;
> + port->line = co->index;
> + spin_lock_init(&port->lock);
> + port->membase = ioremap(port->mapbase, ULITE_REGION);
> +
> + if(port->membase == NULL) {
> + port->iobase = 0;
> + return -EINVAL;
> + }
> +
> + /* Clear ioremap since this port has been mapped already */
> + port->flags &= ~UPF_IOREMAP;
> + }
> +
> + 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;
> + int ret;
> +
> + if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
> + return -EINVAL;
> +
> + if (ports[pdev->id].membase) {
> + if (ports[pdev->id].flags & UPF_IOREMAP) {
> + return -EBUSY; /* Port is busy */
> + }
> +
> + else {
> + /* This port as be remapped so it must have been an early console */
> + port = &ports[pdev->id];
> + goto add_port;
> + }
> + }
> +
> + 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];
> +
> + ulite_init_port(port);
> +
> + port->mapbase = res->start;
> + port->irq = res2->start;
> + port->line = pdev->id;
> +
> +add_port:
> + port->dev = &pdev->dev;
> +
> + ret = uart_add_one_port(&ulite_uart_driver, port);
> +
> + if(ret == 0)
> + platform_set_drvdata(pdev, port);
> +
> + 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");
> Binary files 2.6.18/drivers/serial/.uartlite.c.swp and
> patched-uartlite/drivers/serial/.uartlite.c.swp differ
> diff -urN 2.6.18/include/asm-ppc/uartlite.h
> patched-uartlite/include/asm-ppc/uartlite.h
> --- 2.6.18/include/asm-ppc/uartlite.h 1969-12-31 16:00:00.000000000 -0800
> +++ patched-uartlite/include/asm-ppc/uartlite.h 2006-10-12
> 21:53:00.000000000 -0700
> @@ -0,0 +1,28 @@
> +#ifndef __ASM_UARTLITE_H__
> +#define __ASM_UARTLITE_H__
> +
> +/* 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
> +
> +#endif /* __ASM_UARTLITE_H__ */
> +
> diff -urN 2.6.18/include/linux/serial_core.h
> patched-uartlite/include/linux/serial_core.h
> --- 2.6.18/include/linux/serial_core.h 2006-10-04 14:31:19.000000000 -0700
> +++ patched-uartlite/include/linux/serial_core.h 2006-10-12
> 12:15:32.000000000 -0700
> @@ -132,6 +132,8 @@
>
> #define PORT_S3C2412 73
>
> +/* Xilinx uartlite */
> +#define PORT_UARTLITE 74
>
> #ifdef __KERNEL__
>
> diff -urN 2.6.18/MAINTAINERS patched-uartlite/MAINTAINERS
> --- 2.6.18/MAINTAINERS 2006-10-04 14:31:14.000000000 -0700
> +++ patched-uartlite/MAINTAINERS 2006-10-12 12:15:32.000000000 -0700
> @@ -3311,6 +3311,12 @@
> 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
> --
>
> Cheers,
> David
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
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] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-12 21:12 ` David Bolcsfoldi
2006-10-13 5:21 ` David Bolcsfoldi
2006-10-13 6:48 ` David H. Lynch Jr.
@ 2006-10-13 7:08 ` Peter Korsgaard
2 siblings, 0 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-13 7:08 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi,
David> No I did not know that unfortunately, it could have saved me
David> some work. You are of course right and I'd much prefer to make
David> changes to your driver instead of writing another one.
It unfortunately happens all the time - Googling a bit around before
writing code often pays off ;)
David> I've noticed that in the probe function it tries to get some
David> resources from the platform_device structure but it looks like
David> that this operation will always fail unless I add a 'uartlite'
David> platform device or have I completely misunderstood how platform
David> devices work?
Yes, you need a platform device with the info, E.G. something like:
#include <linux/platform_device.h>
static struct resource myuartlite_resources[] = {
[0] = {
.start = 0xa1000003,
.end = 0xa1000012,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 2,
.end = 2,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device my_uartlite = {
.name = "uartlite",
.id = 0,
.num_resources = ARRAY_SIZE(myuartlite_resources),
.resource = myuartlite_resources,
.dev.platform_data = 0,
};
Which you then add to the platform bus (platform_add_devices).
David> But yes, I will try to add support for the things I need to
David> this driver instead, most importantly early console support and
David> move the #defines for register offsets and such into a separate
David> header file per Grants comment.
Great!
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 5:21 ` David Bolcsfoldi
2006-10-13 7:04 ` David H. Lynch Jr.
@ 2006-10-13 7:11 ` Peter Korsgaard
2006-10-15 23:48 ` David Bolcsfoldi
1 sibling, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-13 7:11 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
David> Here's an initial patch based on a modified uartlite (by Peter
David> Korsgaard), it's by no means ment to be final and any feedback
David> would be appreciated.
Could you make it relative to my driver so the changes are easier to
see?
David> - readb/writeb to in_be32/out_be32.
David> For some reason on my board the readb and writeb don't behave
David> correctly when reading and writing to the uartlite device. I
David> haven't looked into it but if this is unacceptable I will try
David> to revert to readb/writeb.
The PPC is big endian - Did you remember to add 3 to your base
address?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 6:48 ` David H. Lynch Jr.
@ 2006-10-13 7:15 ` Peter Korsgaard
2006-10-15 21:02 ` David H. Lynch Jr.
0 siblings, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-13 7:15 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
David> Peter's driver uses the IORESOURCE requests to pull platform
David> data. Most other serial platformdevices pull a uart_port
David> object. My limited understanding of IORESOURCE is that it is
David> not sufficiently deep to support the parameters that are needed
David> to support UartLite such as a DCR flag and a regoffset.
I'm still not convinced that DCR access and variable register offsets
are needed - But it can always be added (through a seperate struct in
platform_data) - Patches are welcome.
The same with interrupt-less support if the changes are not too
intrusive.
David> You are welcome to do that. I already patched his driver to
David> work with my early console support as well as adding the
David> boot-bash stuff similar to yours. But I gave up actually using
David> it when I could not get it to work.
Which is odd as I've gotten positive feedback from others.
David> Next time I get an opportunity I am going to try to setup an
David> ml403 to atleast verify that Peter's driver is working there.
Great.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 7:04 ` David H. Lynch Jr.
@ 2006-10-13 7:22 ` Peter Korsgaard
[not found] ` <45329C42.3030000@dlasys.net>
0 siblings, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-13 7:22 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
David> Nobody has given me a reason yet why the UartLite should
David> init different from the 8250, and absent a reason, I would
David> mimic the 8250. I do not think there is reason for a different
David> routing name. The ml403 8250 init code deals with multiple
David> 8250's, I did the same with UartLite.
8250 is not the only serial driver. I think the reason why 8250 uses
it's own struct is simple that it's a really old driver. Newer drivers
like atmel_serial.c also uses the platform bus.
David> I am not sure I did nto follow everything on linux-serial -
David> but I think Peter was asked to remove support for additional
David> uarts. I am not sure why.
Remove support? I don't remember anything about that.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 7:15 ` Peter Korsgaard
@ 2006-10-15 21:02 ` David H. Lynch Jr.
2006-10-16 19:49 ` Peter Korsgaard
2006-10-16 19:52 ` Peter Korsgaard
0 siblings, 2 replies; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-15 21:02 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 4080 bytes --]
Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>
>
> Hi,
>
> David> Peter's driver uses the IORESOURCE requests to pull platform
> David> data. Most other serial platformdevices pull a uart_port
> David> object. My limited understanding of IORESOURCE is that it is
> David> not sufficiently deep to support the parameters that are needed
> David> to support UartLite such as a DCR flag and a regoffset.
>
> I'm still not convinced that DCR access and variable register offsets
> are needed - But it can always be added (through a seperate struct in
> platform_data) - Patches are welcome.
>
It does not matter whether you or I are convinced. It matters
whether there are people that need it.
Xilinx has a reference design that uses DCR. While I have never
tripped over an actual implimentation that uses
DCR there are others on this list that have.
> The same with interrupt-less support if the changes are not too
> intrusive.
>
>
Right now I can not get your driver to work. I spent alot of time
trying to fix it and got nowhere.
I can not get it to receive at all, and I can not get it to send
after switching from the console driver
without dropping characters. I am very busy with other things right
now and it is going to be a long
time before I have time to look at your driver again.
In the meantime, my own driver works - atleast for me. And it is out
in the real world on production systems.
The most instrusive changes is likely to be fixing whatever is
causing yours to drop characters - the problem is
worse when I patch your driver to be timer driven - but that is
likely because your service routines blindly presume it is
safe to transmit - true on a Tx empty interrupt, but not on a timer
tick.
But what matters is not whether the changes are intrusive, but
whether they produce a better result.
> David> You are welcome to do that. I already patched his driver to
> David> work with my early console support as well as adding the
> David> boot-bash stuff similar to yours. But I gave up actually using
> David> it when I could not get it to work.
>
> Which is odd as I've gotten positive feedback from others.
>
I am glad somebody is using your driver and finding it works. But we
are all better served by fixing the failure cases.
It is not particularly odd at all. The UartLite despite its
simplicity is worse than a normal driver - different
FPGA implimentations can vary. Normal drivers for fixed inflexible
hardware often do not work accross
differing implimentations, why would you expect something like
UartLite to be invariant ?
One of the other reasons for implimenting polling is because a
polled driver tends to work accross
wider hardware variations. You can not make state assumptions in a
poll routine,
and if the poll routine does nto run then the rest of the OS is hosed.
Even today, flakey hardware interrupts are not unheard of.
I would also ask what data rates you and others with Working
UartLites are using ?
The cases I am dealing with run at 57600 and 115200 respectively -
it is not that odd for
driver problems to manifest themselves only or more frequently at
high baud rates.
> David> Next time I get an opportunity I am going to try to setup an
> David> ml403 to atleast verify that Peter's driver is working there.
>
> Great.
>
Without being difficult - don't hold your breath. It is something I
would like to do, but
I do not have infinite time.
--
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
[-- Attachment #2: Type: text/html, Size: 5788 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-13 7:11 ` Peter Korsgaard
@ 2006-10-15 23:48 ` David Bolcsfoldi
2006-10-20 19:41 ` Peter Korsgaard
0 siblings, 1 reply; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-15 23:48 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: linuxppc-embedded
On 10/13/06, Peter Korsgaard <jacmet@sunsite.dk> wrote:
> Could you make it relative to my driver so the changes are easier to
> see?
>
Done and done. Look at the end of this e-mail.
> The PPC is big endian - Did you remember to add 3 to your base
> address?
>
I don't see how reading a single byte would be affected by the
endianess of the platform.
I think it has more to do with the fact that the status and control
registers are both 4 byte wide and when you add 3 to your offset you
read only the LSB. I also suspect that the RX and TX registers are 4
byte wide too, even though this is not stated explicitly in the
documentation I think it would be prudent to access these two as
4-byte wide registers as well.
I guess it is OK to read and write bytes as long as the bitflags don't
change location. But I believe it is stated in the documentation that
the OPB UART Lite device is a big endian device, in my opinion it
would better to honor this and do big endian access of register width.
The patch below is not identical to the one I posted in previously.
This one has some preprocessor hackery in it to have the uartlites as
separate platform devices (VIRTEX_UARTLITE_0 ... VIRTEX_UARTLITE_3) if
they are available. In theory the only thing you'd need to have the
uartlites available would be to edit your xparameters.h with the
correct uartlite info, enable the driver in your config and compile
your kernel.
diff -urN uartlite/arch/ppc/boot/common/misc-common.c
uartlite-mod/arch/ppc/boot/common/misc-common.c
--- uartlite/arch/ppc/boot/common/misc-common.c 2006-10-15
14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/boot/common/misc-common.c 2006-10-15
13:58:51.000000000 -0700
@@ -57,7 +57,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
diff -urN uartlite/arch/ppc/boot/simple/Makefile
uartlite-mod/arch/ppc/boot/simple/Makefile
--- uartlite/arch/ppc/boot/simple/Makefile 2006-10-15 14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/boot/simple/Makefile 2006-10-15
13:58:51.000000000 -0700
@@ -205,6 +205,7 @@
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff -urN uartlite/arch/ppc/boot/simple/misc.c
uartlite-mod/arch/ppc/boot/simple/misc.c
--- uartlite/arch/ppc/boot/simple/misc.c 2006-10-15 14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/boot/simple/misc.c 2006-10-15 13:58:51.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
diff -urN uartlite/arch/ppc/boot/simple/uartlite_tty.c
uartlite-mod/arch/ppc/boot/simple/uartlite_tty.c
--- uartlite/arch/ppc/boot/simple/uartlite_tty.c 1969-12-31
16:00:00.000000000 -0800
+++ uartlite-mod/arch/ppc/boot/simple/uartlite_tty.c 2006-10-15
13:58:51.000000000 -0700
@@ -0,0 +1,69 @@
+/*
+ * Xilinx UART Lite support.
+ * Right now it only works over UART0 and none other.
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <linux/serial_uartlite.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+static inline int is_xmit_full(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_TXFULL) == ULITE_STATUS_TXFULL);
+}
+
+static inline int is_recv_empty(unsigned int address)
+{
+ return ((in_be32((volatile unsigned *) (address + ULITE_STATUS)) &
ULITE_STATUS_RXVALID) != ULITE_STATUS_RXVALID);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
+ default:
+ goto out;
+ }
+
+out:
+ return -1;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ while(is_xmit_full(XPAR_XUL_UART_0_BASEADDR));
+ out_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_TX), c);
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ while(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+ return in_be32((volatile unsigned *) (XPAR_XUL_UART_0_BASEADDR + ULITE_RX));
+}
+
+int serial_tstc(unsigned long com_port)
+{
+ return !(is_recv_empty(XPAR_XUL_UART_0_BASEADDR));
+}
+
Binary files uartlite/arch/ppc/boot/simple/.uartlite_tty.c.swp and
uartlite-mod/arch/ppc/boot/simple/.uartlite_tty.c.swp differ
diff -urN uartlite/arch/ppc/platforms/4xx/virtex.c
uartlite-mod/arch/ppc/platforms/4xx/virtex.c
--- uartlite/arch/ppc/platforms/4xx/virtex.c 2006-10-15 14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/platforms/4xx/virtex.c 2006-10-15
13:58:52.000000000 -0700
@@ -46,11 +46,91 @@
{ }, /* terminated by empty record */
};
+#define XPAR_UARTLITE(num) { \
+ .uartclk = XPAR_PLB_CLOCK_FREQ_HZ / 16, \
+ .baud = XPAR_XUL_UART_##num##_BAUDRATE, \
+ .bits = XPAR_XUL_UART_##num##_DATA_BITS, \
+ .parity = XPAR_XUL_UART_##num##_USE_PARITY, \
+ .odd_parity = XPAR_XUL_UART_##num##_ODD_PARITY, \
+}
+
+#define UARTLITE_PDEV(num) { \
+ .name = "uartlite", \
+ .id = num, \
+ .dev.platform_data = &uartlite_platform_data[num], \
+ .num_resources = 2, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_XUL_UART_##num##_BASEADDR, \
+ .end = XPAR_XUL_UART_##num##_HIGHADDR, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ { \
+ .start = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
+ .end = XPAR_INTC_0_XUL_UART_##num##_VEC_ID, \
+ .flags = IORESOURCE_IRQ, \
+ }, \
+ } \
+}
+
+struct plat_uartlite_data uartlite_platform_data[] = {
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ XPAR_UARTLITE(0),
+#endif
+#ifdef XPAR_XUL_UART_1_BASEADDR
+ XPAR_UARTLITE(1),
+#endif
+#ifdef XPAR_XUL_UART_2_BASEADDR
+ XPAR_UARTLITE(2),
+#endif
+#ifdef XPAR_XUL_UART_3_BASEADDR
+ XPAR_UARTLITE(3),
+#endif
+ { }, /* terminated by empty record */
+};
+
struct platform_device ppc_sys_platform_devices[] = {
[VIRTEX_UART] = {
.name = "serial8250",
.id = 0,
.dev.platform_data = serial_platform_data,
},
+
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ [VIRTEX_UARTLITE_0] = UARTLITE_PDEV(0),
+#else
+ [VIRTEX_UARTLITE_0] = { .id = - 1, },
+#endif /* XPAR_XUL_UART_0_BASEADDR */
+
+#ifdef XPAR_XUL_UART_1_BASEADDR
+ [VIRTEX_UARTLITE_1] = UARTLITE_PDEV(1),
+#else
+ [VIRTEX_UARTLITE_1] = { .id = - 1, },
+#endif /* XPAR_XUL_UART_1_BASEADDR */
+
+#ifdef XPAR_XUL_UART_2_BASEADDR
+ [VIRTEX_UARTLITE_2] = UARTLITE_PDEV(2),
+#else
+ [VIRTEX_UARTLITE_2] = { .id = - 1, },
+#endif /* XPAR_XUL_UART_2_BASEADDR */
+
+#ifdef XPAR_XUL_UART_3_BASEADDR
+ [VIRTEX_UARTLITE_3] = UARTLITE_PDEV(3),
+#else
+ [VIRTEX_UARTLITE_3] = { .id = - 1, },
+#endif /* XPAR_XUL_UART_3_BASEADDR */
};
+/* For early console on the uartlite serial port some way of
+ * getting to the platform_device is needed */
+
+struct platform_device* early_uart_get_pdev(int dev)
+{
+ if (dev < 0 ||
+ dev >= NUM_PPC_SYS_DEVS) {
+ return NULL;
+ }
+
+ return &ppc_sys_platform_devices[dev];
+}
+
diff -urN uartlite/arch/ppc/platforms/4xx/virtex.h
uartlite-mod/arch/ppc/platforms/4xx/virtex.h
--- uartlite/arch/ppc/platforms/4xx/virtex.h 2006-10-15 14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/platforms/4xx/virtex.h 2006-10-15
13:58:52.000000000 -0700
@@ -27,8 +27,22 @@
/* Device type enumeration for platform bus definitions */
#ifndef __ASSEMBLY__
enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
+ VIRTEX_UART,
+ VIRTEX_UARTLITE_0,
+ VIRTEX_UARTLITE_1,
+ VIRTEX_UARTLITE_2,
+ VIRTEX_UARTLITE_3,
+ NUM_PPC_SYS_DEVS,
};
+
+struct plat_uartlite_data {
+ unsigned int uartclk;
+ unsigned int baud;
+ unsigned char bits;
+ unsigned char parity;
+ unsigned char odd_parity;
+};
+
#endif
#endif /* __ASM_VIRTEX_H__ */
diff -urN uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c
uartlite-mod/arch/ppc/platforms/4xx/xilinx_ml403.c
--- uartlite/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-15
14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/platforms/4xx/xilinx_ml403.c 2006-10-15
13:58:52.000000000 -0700
@@ -57,6 +57,10 @@
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
+#ifndef XPAR_XUARTLITE_NUM_INSTANCES
+#define XPAR_XUARTLITE_NUM_INSTANCES 0
+#endif
+
/* Board specifications structures */
struct ppc_sys_spec *cur_ppc_sys_spec;
struct ppc_sys_spec ppc_sys_specs[] = {
@@ -65,10 +69,22 @@
.ppc_sys_name = "Xilinx ML403 Reference Design",
.mask = 0x00000000,
.value = 0x00000000,
- .num_devices = 1,
+ .num_devices = 1 + XPAR_XUARTLITE_NUM_INSTANCES,
.device_list = (enum ppc_sys_devices[])
{
VIRTEX_UART,
+#ifdef XPAR_XUL_UART_0_BASEADDR
+ VIRTEX_UARTLITE_0,
+#endif
+#ifdef XPAR_XUL_UART_1_BASEADDR
+ VIRTEX_UARTLITE_1,
+#endif
+#ifdef XPAR_XUL_UART_2_BASEADDR
+ VIRTEX_UARTLITE_2,
+#endif
+#ifdef XPAR_XUL_UART_3_BASEADDR
+ VIRTEX_UARTLITE_3,
+#endif
},
},
};
Binary files uartlite/arch/ppc/platforms/4xx/xparameters/.xparameters_ml403.h.swp
and uartlite-mod/arch/ppc/platforms/4xx/xparameters/.xparameters_ml403.h.swp
differ
diff -urN uartlite/drivers/serial/uartlite.c
uartlite-mod/drivers/serial/uartlite.c
--- uartlite/drivers/serial/uartlite.c 2006-10-15 14:13:30.000000000 -0700
+++ uartlite-mod/drivers/serial/uartlite.c 2006-10-15 13:58:59.000000000 -0700
@@ -17,37 +17,21 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/io.h>
+#include <linux/serial_uartlite.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];
+/* Place-holder for board-specific stuff */
+struct platform_device* __attribute__ ((weak)) __init
+early_uart_get_pdev(int index)
+{
+ return NULL;
+}
+
static int ulite_receive(struct uart_port *port, int stat)
{
struct tty_struct *tty = port->info->tty;
@@ -61,7 +45,7 @@
/* stats */
if (stat & ULITE_STATUS_RXVALID) {
port->icount.rx++;
- ch = readb(port->membase + ULITE_RX);
+ ch = in_be32((unsigned volatile *) (port->membase + ULITE_RX));
if (stat & ULITE_STATUS_PARITY)
port->icount.parity++;
@@ -106,7 +90,7 @@
return 0;
if (port->x_char) {
- writeb(port->x_char, port->membase + ULITE_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), port->x_char);
port->x_char = 0;
port->icount.tx++;
return 1;
@@ -115,7 +99,7 @@
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return 0;
- writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX),
xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
port->icount.tx++;
@@ -131,12 +115,16 @@
struct uart_port *port = (struct uart_port *)dev_id;
int busy;
+ spin_lock(&port->lock); /* Lock the port in case of printk */
+
do {
- int stat = readb(port->membase + ULITE_STATUS);
+ int stat = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
busy = ulite_receive(port, stat);
busy |= ulite_transmit(port, stat);
} while (busy);
+ spin_unlock(&port->lock);
+
tty_flip_buffer_push(port->info->tty);
return IRQ_HANDLED;
@@ -148,7 +136,7 @@
unsigned int ret;
spin_lock_irqsave(&port->lock, flags);
- ret = readb(port->membase + ULITE_STATUS);
+ ret = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS));
spin_unlock_irqrestore(&port->lock, flags);
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
@@ -171,7 +159,7 @@
static void ulite_start_tx(struct uart_port *port)
{
- ulite_transmit(port, readb(port->membase + ULITE_STATUS));
+ ulite_transmit(port, in_be32((unsigned volatile *) (port->membase +
ULITE_STATUS)));
}
static void ulite_stop_rx(struct uart_port *port)
@@ -200,9 +188,8 @@
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);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
return 0;
}
@@ -216,6 +203,7 @@
static void ulite_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
+ struct plat_uartlite_data *udata;
unsigned long flags;
unsigned int baud;
@@ -240,7 +228,9 @@
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
/* update timeout */
- baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+ udata = port->dev->platform_data;
+
+ baud = uart_get_baud_rate(port, termios, old, udata->baud, udata->baud);
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock_irqrestore(&port->lock, flags);
@@ -265,7 +255,10 @@
return -EBUSY;
}
- port->membase = ioremap(port->mapbase, ULITE_REGION);
+ if (port->flags & UPF_IOREMAP) {
+ 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);
@@ -306,6 +299,35 @@
.verify_port = ulite_verify_port
};
+static inline int ulite_init_port(struct uart_port *port, struct
platform_device *pdev)
+{
+ struct resource *res;
+ struct plat_uartlite_data *udata = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ port->mapbase = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res)
+ return -ENODEV;
+
+ port->irq = res->start;
+ port->uartclk = udata->uartclk;
+ port->membase = 0;
+ port->fifosize = 16;
+ port->regshift = 2;
+ port->iobase = 1; /* Mark port in use */
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &ulite_ops;
+ port->type = PORT_UNKNOWN;
+
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
@@ -313,7 +335,7 @@
/* 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)
+ if (in_be32((unsigned volatile *) (port->membase + ULITE_STATUS)) &
ULITE_STATUS_TXEMPTY)
break;
udelay(1);
}
@@ -322,7 +344,7 @@
static void ulite_console_putchar(struct uart_port *port, int ch)
{
ulite_console_wait_tx(port);
- writeb(ch, port->membase + ULITE_TX);
+ out_be32((unsigned volatile *) (port->membase + ULITE_TX), ch);
}
static void ulite_console_write(struct console *co, const char *s,
@@ -339,16 +361,18 @@
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);
-
+ ier = in_be32((unsigned volatile *) (port->membase + ULITE_STATUS))
& ULITE_STATUS_IE;
+
+ //writeb(0, port->membase + ULITE_CONTROL);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL), 0);
+
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);
+ out_be32((unsigned volatile *) (port->membase + ULITE_CONTROL),
ULITE_CONTROL_IE);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
@@ -356,16 +380,57 @@
static int __init ulite_console_setup(struct console *co, char *options)
{
+ int i, ret;
struct uart_port *port;
-
+ struct platform_device *pdev;
+
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
port = &ports[co->index];
/* not initialized yet? */
- if (!port->membase)
- return -ENODEV;
+ if (!port->membase) {
+ /* We might be early console */
+
+ pdev = NULL;
+
+ /* Loop through the platform devices
+ * until we find one with correct name
+ * and device id */
+
+ for (i = 0; i < NUM_PPC_SYS_DEVS; ++i) {
+ pdev = early_uart_get_pdev(0);
+
+ if (pdev->id != - 1 &&
+ pdev->name != NULL &&
+ (strcmp(pdev->name, "uartlite") == 0) &&
+ pdev->id == co->index) {
+ break;
+ }
+ }
+
+ if (pdev == NULL) {
+ return -ENODEV;
+ }
+
+ ret = ulite_init_port(port, pdev);
+
+ if (ret != 0)
+ return ret;
+
+ port->line = co->index;
+ spin_lock_init(&port->lock);
+ port->membase = ioremap(port->mapbase, ULITE_REGION);
+
+ if(port->membase == NULL) {
+ port->iobase = 0;
+ return -EINVAL;
+ }
+
+ /* Clear ioremap since this port has been mapped already */
+ port->flags &= ~UPF_IOREMAP;
+ }
return 0;
}
@@ -406,41 +471,44 @@
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 >= ULITE_NR_UARTS)
return -EINVAL;
- if (ports[pdev->id].membase)
- return -EBUSY;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
+ if (ports[pdev->id].membase) {
+ if (ports[pdev->id].flags & UPF_IOREMAP) {
+ return -EBUSY; /* Port is busy */
+ }
+
+ else {
+ /* This port as be remapped so it must have been an early console */
+ port = &ports[pdev->id];
+ goto add_port;
+ }
+ }
- 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;
+ ret = ulite_init_port(port, pdev);
- uart_add_one_port(&ulite_uart_driver, port);
- platform_set_drvdata(pdev, port);
+ if (ret != 0)
+ goto out;
+
+ port->line = pdev->id;
+
+add_port:
+ port->dev = &pdev->dev;
+
+ ret = uart_add_one_port(&ulite_uart_driver, port);
- return 0;
+ if(ret == 0)
+ platform_set_drvdata(pdev, port);
+
+out:
+ return ret;
}
static int ulite_remove(struct platform_device *pdev)
Binary files uartlite/drivers/serial/.uartlite.c.swp and
uartlite-mod/drivers/serial/.uartlite.c.swp differ
diff -urN uartlite/include/linux/serial_uartlite.h
uartlite-mod/include/linux/serial_uartlite.h
--- uartlite/include/linux/serial_uartlite.h 1969-12-31 16:00:00.000000000 -0800
+++ uartlite-mod/include/linux/serial_uartlite.h 2006-10-15
14:22:07.000000000 -0700
@@ -0,0 +1,28 @@
+#ifndef __SERIAL_UARTLITE_H__
+#define __SERIAL_UARTLITE_H__
+
+/* 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
+
+#endif /* __SERIAL_UARTLITE_H__ */
+
--
Cheers,
David
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
[not found] ` <45329C42.3030000@dlasys.net>
@ 2006-10-16 19:42 ` Peter Korsgaard
0 siblings, 0 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-16 19:42 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
David> The 8250 is certainly the oldest driver - but it is also
David> by far the most used. It is also the most heavily maintained,
Yes, because there's so many more-or-less compatible variants of the
hardware. Most drivers don't see a lot of development once they are
past the initial development/testing..
David> There are complexities to the 8250 that proved to be difficult
David> and troubling when I based my UartLite driver on it, Those
David> problems were because the 8250driver suports so many 8250
David> variants with so many idiosyncracies.
Exactly. Try to compare it to one of the "modern" drivers like
atmel_serial.c - It's almost 3 times as big.
>> Remove support? I don't remember anything about that.
David> I may have misread something there - I thought your
David> initial driver allowed stting the number of Uarts, and I
David> beleive your current one does not. If I am wrong, then I
David> think support for more Uarts needs to get added to the todo
David> list. That is not something important to me. But it probably
David> will be for others.
There was a discussion about how many device nodes to register with
lanana.org and hence how many devices to support. I went with 4 which
seems to be pretty standard (E.G. virtex.c supports up to 4 8250s). If
more is needed a bigger range can be requested with lanana.org.
Again, let's see a real need before changing anything.
David> Despite the fact hat you apear to run combined 16550/Uartlite
David> implimentations, My expectation is that will be rare. A small
David> savings in FPGA spare is rarely going to justify more complex
David> hardware and software. Multiple port systems are mostly
David> likely to be all one type or another.
Almost all our designs use both.
P.S.: Would it be possible to fix up your quoting?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-15 21:02 ` David H. Lynch Jr.
@ 2006-10-16 19:49 ` Peter Korsgaard
2006-10-16 19:52 ` Peter Korsgaard
1 sibling, 0 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-16 19:49 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
>> I'm still not convinced that DCR access and variable register
>> offsets are needed - But it can always be added (through a
>> seperate struct in platform_data) - Patches are welcome.
David> It does not matter whether you or I are convinced. It
David> matters whether there are people that need it. Xilinx has a
David> reference design that uses DCR. While I have never tripped
David> over an actual implimentation that uses DCR there are others
David> on this list that have.
Those people are welcome to add it then. Benh recently posted some
patches with a dcr abstraction that could probably make it pretty
clean to add.
David> Right now I can not get your driver to work. I spent alot
David> of time trying to fix it and got nowhere. I can not get it to
David> receive at all, and I can not get it to send after switching
David> from the console driver without dropping characters. I am very
David> busy with other things right now and it is going to be a long
David> time before I have time to look at your driver again.
Sorry to hear. We are using it in several designs without problems and
it also worked for Oluf. I'm afraid I won't be able to help you
anymore unless you provide more details.
David> But what matters is not whether the changes are intrusive,
David> but whether they produce a better result.
Sorry, I don't agree. Maintainability is very important.
David> I am glad somebody is using your driver and finding it
David> works. But we are all better served by fixing the failure
David> cases.
Yes, please do or provide enough details for me to reproduce it.
David> It is not particularly odd at all. The UartLite despite
David> its simplicity is worse than a normal driver - different FPGA
David> implimentations can vary. Normal drivers for fixed inflexible
David> hardware often do not work accross differing implimentations,
David> why would you expect something like UartLite to be invariant ?
It's no worse than Xilinx 8250 core. There's only 1 implementation of
the uarlite IP core - Xilinx's.
David> I would also ask what data rates you and others with
David> Working UartLites are using ? The cases I am dealing with run
David> at 57600 and 115200 respectively - it is not that odd for
David> driver problems to manifest themselves only or more frequently
David> at high baud rates.
We're using 115200 for most designs, but one design is using it at
1mbit.
David> Without being difficult - don't hold your breath. It is
David> something I would like to do, but I do not have infinite time.
Ok.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-15 21:02 ` David H. Lynch Jr.
2006-10-16 19:49 ` Peter Korsgaard
@ 2006-10-16 19:52 ` Peter Korsgaard
1 sibling, 0 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-16 19:52 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
Hi,
>> I'm still not convinced that DCR access and variable register
>> offsets are needed - But it can always be added (through a
>> seperate struct in platform_data) - Patches are welcome.
David> It does not matter whether you or I are convinced. It
David> matters whether there are people that need it. Xilinx has a
David> reference design that uses DCR. While I have never tripped
David> over an actual implimentation that uses DCR there are others
David> on this list that have.
Those people are welcome to add it then. Benh recently posted some
patches with a dcr abstraction that could probably make it pretty
clean to add. I don't have a DCR based design to do the implementation
and test, so it's pretty low on my priority list.
David> Right now I can not get your driver to work. I spent alot
David> of time trying to fix it and got nowhere. I can not get it to
David> receive at all, and I can not get it to send after switching
David> from the console driver without dropping characters. I am very
David> busy with other things right now and it is going to be a long
David> time before I have time to look at your driver again.
Sorry to hear. We are using it in several designs without problems and
it also worked for Oluf. I'm afraid I won't be able to help you
anymore unless you provide more details.
David> But what matters is not whether the changes are intrusive,
David> but whether they produce a better result.
Sorry, I don't agree. Maintainability is very important.
David> I am glad somebody is using your driver and finding it
David> works. But we are all better served by fixing the failure
David> cases.
Yes, please do or provide enough details for me to reproduce it.
David> It is not particularly odd at all. The UartLite despite
David> its simplicity is worse than a normal driver - different FPGA
David> implimentations can vary. Normal drivers for fixed inflexible
David> hardware often do not work accross differing implimentations,
David> why would you expect something like UartLite to be invariant ?
It's no worse than Xilinx 8250 core. There's only 1 implementation of
the uarlite IP core - Xilinx's.
David> I would also ask what data rates you and others with
David> Working UartLites are using ? The cases I am dealing with run
David> at 57600 and 115200 respectively - it is not that odd for
David> driver problems to manifest themselves only or more frequently
David> at high baud rates.
We're using 115200 for most designs, but one design is using it at
1mbit.
David> Without being difficult - don't hold your breath. It is
David> something I would like to do, but I do not have infinite time.
Ok.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-15 23:48 ` David Bolcsfoldi
@ 2006-10-20 19:41 ` Peter Korsgaard
2006-10-27 15:03 ` Peter Korsgaard
0 siblings, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-20 19:41 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi - sorry for the slow response, this week has been crazy :/
>> Could you make it relative to my driver so the changes are easier
>> to see?
David> Done and done. Look at the end of this e-mail.
Thanks.
>> The PPC is big endian - Did you remember to add 3 to your base
>> address?
David> I don't see how reading a single byte would be affected by the
David> endianess of the platform. I think it has more to do with the
David> fact that the status and control registers are both 4 byte wide
David> and when you add 3 to your offset you read only the LSB. I also
David> suspect that the RX and TX registers are 4 byte wide too, even
David> though this is not stated explicitly in the documentation I
David> think it would be prudent to access these two as 4-byte wide
David> registers as well.
Well, the end result is the same. I guess the only reason for the
4-byte spacing between the registers is the 32bit width of the OPB
bus. The logical contents of the registers are all 8bit or less, and
sticking to 8bit access makes things easier (no endianness issues, no
issues with alternative implementations with another physical width).
E.G. the driver might be useful for other architectures
(E.G. microblaze) and for other implementations of the uartlite. We
are using another uart with a uartlite compatible interface in a
non-virtex fpga.
The exact same thing is done my 8250.c for the 16550 opb core.
David> I guess it is OK to read and write bytes as long as the
David> bitflags don't change location. But I believe it is stated in
David> the documentation that the OPB UART Lite device is a big endian
David> device, in my opinion it would better to honor this and do big
David> endian access of register width.
The driver has to be updated If the hardware interface changes no
matter what. The documentation clearly states (bottom of page 3) that
you can access the registers using 8, 16 or 32bit accesses.
I'll test and take a closer look at your patch when I have access to
hw again on Monday.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-20 19:41 ` Peter Korsgaard
@ 2006-10-27 15:03 ` Peter Korsgaard
2006-10-28 3:29 ` David H. Lynch Jr.
2006-10-30 19:45 ` David Bolcsfoldi
0 siblings, 2 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-27 15:03 UTC (permalink / raw)
To: dbolcsfoldi, linuxppc-embedded
>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
Peter> I'll test and take a closer look at your patch when I have
Peter> access to hw again on Monday.
Sorry, it got a bit later than promised, but I've now had a closer
look at your patch ..
--- uartlite/arch/ppc/boot/simple/misc.c 2006-10-15 14:09:47.000000000 -0700
+++ uartlite-mod/arch/ppc/boot/simple/misc.c 2006-10-15 13:58:51.000000000 -0700
@@ -48,7 +48,8 @@
#if (defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_VGA_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
&& !defined(CONFIG_GEMINI)
#define INTERACTIVE_CONSOLE 1
#endif
The Xilinx boards use misc-embedded.c not misc.c - Why is this needed?
+unsigned long serial_init(int chan, void *ignored)
+{
+ switch (chan) {
+ #ifdef XPAR_XUL_UART_0_BASEADDR
+ case 0:
+ return XPAR_XUL_UART_0_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_1_BASEADDR
+ case 1:
+ return XPAR_XUL_UART_1_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_2_BASEADDR
+ case 2:
+ return XPAR_XUL_UART_2_BASEADDR;
+ #endif
+ #ifdef XPAR_XUL_UART_3_BASEADDR
+ case 3:
+ return XPAR_XUL_UART_3_BASEADDR;
+ #endif
This doesn't help much as you don't use the com_port argument in the
other functions.
Where did you get the XPAR_XUL_UART_ defines from? Our xparameters.h
seem to contain XPAR_UARTLITE_ defines instead.
@@ -131,12 +115,16 @@
struct uart_port *port = (struct uart_port *)dev_id;
int busy;
+ spin_lock(&port->lock); /* Lock the port in case of printk */
+
In an interrupt handler? Why? The console_write does a spin_lock_irqsave.
static int __init ulite_console_setup(struct console *co, char *options)
{
+ int i, ret;
struct uart_port *port;
-
+ struct platform_device *pdev;
+
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
port = &ports[co->index];
/* not initialized yet? */
- if (!port->membase)
- return -ENODEV;
+ if (!port->membase) {
+ /* We might be early console */
Is this really necessary? The platform probe get's called quite early, E.G.:
Breakpoint 2, ulite_probe (pdev=0xc01c84d0) at drivers/serial/uartlite.c:392
392 {
(gdb) print __log_buf
$1 = "<5>Linux version 2.6.19-rc3 (peko@sleipner) (gcc version 3.4.5) #19 Fri Oct 27 16:39:00 CEST 2006\n<6>Barco ThinLite (V2P) <peter.korsgaard@barco.com>\n<7>Entering add_active_range(0, 0, 15360) 0 entrie"...
You can always use the ppc_md.progress() stuff for really early
debugging if needed. I would prefer to keep this workaround out of
uartlite.c if it isn't needed.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-27 15:03 ` Peter Korsgaard
@ 2006-10-28 3:29 ` David H. Lynch Jr.
2006-10-30 8:23 ` Peter Korsgaard
2006-10-30 19:45 ` David Bolcsfoldi
1 sibling, 1 reply; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-28 3:29 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: linuxppc-embedded
Peter Korsgaard wrote:
>
> static int __init ulite_console_setup(struct console *co, char *options)
> {
> + int i, ret;
> struct uart_port *port;
> -
> + struct platform_device *pdev;
> +
> if (co->index < 0 || co->index >= ULITE_NR_UARTS)
> return -EINVAL;
>
> port = &ports[co->index];
>
> /* not initialized yet? */
> - if (!port->membase)
> - return -ENODEV;
> + if (!port->membase) {
> + /* We might be early console */
>
> Is this really necessary? The platform probe get's called quite early, E.G.:
>
> Breakpoint 2, ulite_probe (pdev=0xc01c84d0) at drivers/serial/uartlite.c:392
There is a substantial time/code difference between the time
ulite_console_setup() is called and the time the platform device is
initiallized.
If you are actually doing board bringup, you want output as soon as
you can get it and you do not want to have to stuff calls to
ppc_md.progress() to do so.
Regardless, I think this is an issue of style and personal preference.
> 392 {
> (gdb) print __log_buf
> $1 = "<5>Linux version 2.6.19-rc3 (peko@sleipner) (gcc version 3.4.5) #19 Fri Oct 27 16:39:00 CEST 2006\n<6>Barco ThinLite (V2P) <peter.korsgaard@barco.com>\n<7>Entering add_active_range(0, 0, 15360) 0 entrie"...
>
> You can always use the ppc_md.progress() stuff for really early
> debugging if needed. I would prefer to keep this workaround out of
> uartlite.c if it isn't needed.
>
>
I will absolutely agree that trying to resolve the the
dissimilarities between the console_setup() call and the platform device
init is ugly.
But I would have changed the platform device init code to use
the uart_port structure in the platform device data as all the other
drivers that have early console support do.
At some point I suspect a cleaner more structured approach to
modularizing the relationship between early serial code and serial
drivers will force this issue one way or another.
But for now, if you are not going to bother making console_settup()
work you might as well not put the rest of the early serial code in at all.
--
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] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-28 3:29 ` David H. Lynch Jr.
@ 2006-10-30 8:23 ` Peter Korsgaard
2006-10-31 17:26 ` David H. Lynch Jr.
0 siblings, 1 reply; 24+ messages in thread
From: Peter Korsgaard @ 2006-10-30 8:23 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
David> There is a substantial time/code difference between the
David> time ulite_console_setup() is called and the time the platform
David> device is initiallized.
Huh?
(gdb) br ulite_probe
Breakpoint 2 at 0xc00f7530: file drivers/serial/uartlite.c, line 397.
(gdb) br ulite_console_setup
Breakpoint 3 at 0xc00f7454: file drivers/serial/uartlite.c, line 342.
(gdb) c
Continuing.
Breakpoint 2, ulite_probe (pdev=0xc00ddb50) at drivers/serial/uartlite.c:397
397 return -EINVAL;
(gdb) c
Continuing.
Breakpoint 3, ulite_console_setup (co=0xc00e2f14, options=0xc00fe00f "115200")
at drivers/serial/uartlite.c:342
342 if (co->index < 0 || co->index >= ULITE_NR_UARTS)
_probe get's called before console_setup, so we have all the
information to output console data right away.
David> But for now, if you are not going to bother making
David> console_settup() work you might as well not put the rest of the
David> early serial code in at all.
Not going to make it work? What doesn't work?
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-27 15:03 ` Peter Korsgaard
2006-10-28 3:29 ` David H. Lynch Jr.
@ 2006-10-30 19:45 ` David Bolcsfoldi
2006-11-06 15:44 ` Peter Korsgaard
1 sibling, 1 reply; 24+ messages in thread
From: David Bolcsfoldi @ 2006-10-30 19:45 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: linuxppc-embedded
On 10/27/06, Peter Korsgaard <jacmet@sunsite.dk> wrote:
> >>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
>
> Peter> I'll test and take a closer look at your patch when I have
> Peter> access to hw again on Monday.
>
> Sorry, it got a bit later than promised, but I've now had a closer
> look at your patch ..
>
> --- uartlite/arch/ppc/boot/simple/misc.c 2006-10-15 14:09:47.000000000 -0700
> +++ uartlite-mod/arch/ppc/boot/simple/misc.c 2006-10-15 13:58:51.000000000 -0700
> @@ -48,7 +48,8 @@
> #if (defined(CONFIG_SERIAL_8250_CONSOLE) \
> || defined(CONFIG_VGA_CONSOLE) \
> || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
> - || defined(CONFIG_SERIAL_MPSC_CONSOLE)) \
> + || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
> + || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)) \
> && !defined(CONFIG_GEMINI)
> #define INTERACTIVE_CONSOLE 1
> #endif
>
> The Xilinx boards use misc-embedded.c not misc.c - Why is this needed?
>
You are right, it's not.
> +unsigned long serial_init(int chan, void *ignored)
> +{
> + switch (chan) {
> + #ifdef XPAR_XUL_UART_0_BASEADDR
> + case 0:
> + return XPAR_XUL_UART_0_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_1_BASEADDR
> + case 1:
> + return XPAR_XUL_UART_1_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_2_BASEADDR
> + case 2:
> + return XPAR_XUL_UART_2_BASEADDR;
> + #endif
> + #ifdef XPAR_XUL_UART_3_BASEADDR
> + case 3:
> + return XPAR_XUL_UART_3_BASEADDR;
> + #endif
>
> This doesn't help much as you don't use the com_port argument in the
> other functions.
>
True, it's utterly useless. I was planning on having an array with
base addresses which would be used to support the com_port argument.
But it didn't make it in this patch although I have version that does
this now.
> Where did you get the XPAR_XUL_UART_ defines from? Our xparameters.h
> seem to contain XPAR_UARTLITE_ defines instead.
>
I think that name is picked up from the name of the device in your
design, the defines get names XPAR_NNN_ and mine are called XUL_UART.
> @@ -131,12 +115,16 @@
> struct uart_port *port = (struct uart_port *)dev_id;
> int busy;
>
> + spin_lock(&port->lock); /* Lock the port in case of printk */
> +
>
> In an interrupt handler? Why? The console_write does a spin_lock_irqsave.
>
Sorry, my mistake. It's not needed.
> static int __init ulite_console_setup(struct console *co, char *options)
> {
> + int i, ret;
> struct uart_port *port;
> -
> + struct platform_device *pdev;
> +
> if (co->index < 0 || co->index >= ULITE_NR_UARTS)
> return -EINVAL;
>
> port = &ports[co->index];
>
> /* not initialized yet? */
> - if (!port->membase)
> - return -ENODEV;
> + if (!port->membase) {
> + /* We might be early console */
>
> Is this really necessary? The platform probe get's called quite early, E.G.:
>
> Breakpoint 2, ulite_probe (pdev=0xc01c84d0) at drivers/serial/uartlite.c:392
> 392 {
> (gdb) print __log_buf
> $1 = "<5>Linux version 2.6.19-rc3 (peko@sleipner) (gcc version 3.4.5) #19 Fri Oct 27 16:39:00 CEST 2006\n<6>Barco ThinLite (V2P) <peter.korsgaard@barco.com>\n<7>Entering add_active_range(0, 0, 15360) 0 entrie"...
>
> You can always use the ppc_md.progress() stuff for really early
> debugging if needed. I would prefer to keep this workaround out of
> uartlite.c if it isn't needed.
>
I am pretty certain probe won't get called until ppc_sys_init has been
called which is fairly far into the booting process and even if it did
the platform_bus hasn't been initialized before the ppc_sys_init is
called, at least not with any of the devices exported by
ppc_sys_devices.
Thanks for the review!
David
> --
> Bye, Peter Korsgaard
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-30 8:23 ` Peter Korsgaard
@ 2006-10-31 17:26 ` David H. Lynch Jr.
0 siblings, 0 replies; 24+ messages in thread
From: David H. Lynch Jr. @ 2006-10-31 17:26 UTC (permalink / raw)
To: Peter Korsgaard, linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 7010 bytes --]
Peter Korsgaard wrote:
>>>>>> "David" == David H Lynch <dhlii@dlasys.net> writes:
>>>>>>
>
> David> There is a substantial time/code difference between the
> David> time ulite_console_setup() is called and the time the platform
> David> device is initiallized.
>
> Huh?
>
> (gdb) br ulite_probe
> Breakpoint 2 at 0xc00f7530: file drivers/serial/uartlite.c, line 397.
> (gdb) br ulite_console_setup
> Breakpoint 3 at 0xc00f7454: file drivers/serial/uartlite.c, line 342.
> (gdb) c
> Continuing.
>
> Breakpoint 2, ulite_probe (pdev=0xc00ddb50) at drivers/serial/uartlite.c:397
> 397 return -EINVAL;
> (gdb) c
> Continuing.
>
> Breakpoint 3, ulite_console_setup (co=0xc00e2f14, options=0xc00fe00f "115200")
> at drivers/serial/uartlite.c:342
> 342 if (co->index < 0 || co->index >= ULITE_NR_UARTS)
>
> _probe get's called before console_setup, so we have all the
> information to output console data right away.
I am not nearly as familiar with your driver and David B. Early
serial patches as I am with my own.
But I can assure you that the early serial init code occurs well
before the call to probe.
If that is not the case then there is no reason for the early serial
code to even exist.
Does David B.'s patch include support for early_serial_init(struct
uart_port *) ?
Look at other BSP's, most have early serial support.
One of the reasons I modeled my driver off the 8250 was because it
had boot to bash support.
If the 8250 did something in a particular way I did the same for the
uartlite - unless I really deeply understood why
I needed not to. I implimented every relevant 8250 feature every
step of the way.
I actually started with the early serial code long before I started
with the driver. It was fairly trivial. It gets you fairly far into the
boot process,
and you can call it directly for debugging.
> David> But for now, if you are not going to bother making
> David> console_settup() work you might as well not put the rest of the
> David> early serial code in at all.
>
> Not going to make it work? What doesn't work?
>
If you impliment early_serial_setup(struct uart_port *) then you
must initialize the driver at the time of that call using a uart_port
struct.
Unless you are going to redefine early_serial_setup() specifically
for the uartlite - maybe that is possible, I don't know, but it sounds
like a bad idea.
I have attached the boot text from a Pico E14 - this one using my
Keyhole port serial driver not the uartlite drive - but since I
patterned them both after the 8250
the sequence is the same.
The serial_init() call initializes the mini_driver in
arch/ppc/boot/simple - in the case of uartlite that would be uartlite_tty.c
keyhole_init() or uartlite_init() is in arch/ppc/syslib - in the
case of uartlite uartlite_dbg.c
that is followed immediately by early_serial_init() - basically
meaning unless you make heavy use of progress() calls - and with
early_serial_init() you can call printk and receive output immediately,
uartlite_dbg.c is probably unneeded but it is trivial and damn
near identical to uartlite_tty.c
early_serial_init() is followed nearly immediately with
keyhole_console_setup() or uartlite_console_setup()
Much late Linux starts initializing the serial drivers and calls probe.
If you do not impliment early_serial_setup, then you will be blind
from that point until the probe call occurs. If anything goes wrong you
will have to try to dump the printk buffer in memory to find out what
went wrong.
I do not know what hardware you are using or how your BSP is
constructed.
The whole early serial text system has little use for a system that
is working perfectly.
But it could be a life saver for somebody doing board bringup.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
.
Loading zImage.elf.
[keyhole] serial_init()
loaded at: 00800000 00ABC13C
board data at: 0FFFFF60 0FFFFF7C
relocated to: 00804030 0080404C
zimage at: 00804E01 00AB9C2E
avail ram: 00ABD000 0FFFFFFF
Linux/PPC load: root=/dev/ram
Uncompressing Linux...done.
Now booting the kernel
id mach(): done
MMU:enter
MMU:hw init
MMU:mapin
MMU:setio
MMU:exit
setup_arch: enter
setup_arch: bootmem
keyhole_init()
keyhole:early_serial_setup()
arch: exit
keyhole_console_setup()
Linux version 2.6.19-rc2 (root@pico.dlasys.net) (gcc version 3.4.1) #2
Tue Oct 31 11:24:48 EST 2006
Pico Virtex-4 port
Port by DLA Systems (info@dlasys.net)
Zone PFN ranges:
DMA 0 -> 65535
Normal 65535 -> 65535
early_node_map[1] active PFN ranges
0: 0 -> 65535
Built 1 zonelists. Total pages: 65024
Kernel command line: root=/dev/ram
Xilinx INTC #0 at 0x41200000 mapped to 0xF5FFD000
PID hash table entries: 1024 (order: 10, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 255488k available (1272k kernel code, 724k data, 2052k init, 0k
highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 8192 bind 4096)
TCP reno registered
io scheduler noop registered (default)
Serial: Xilinx uartlite driver $Revision: 0.10 $ 1 ports
Serial: Pico keyhole driver $Revision: 0.20 $*
keyhole_device_probe()
ttyS0 at MMIO 0x70000000 (irq = -1) is a keyhole
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize
TCP cubic registered
NET: Registered protocol family 17
Freeing unused kernel memory: 2052k init
command='/bin/sh' action='2' terminal='/dev/ttyS0'
command='/etc/init.d/rcS' action='1' terminal='/dev/ttyS0'
command='/sbin/init' action='128' terminal='/dev/ttyS0'
command='/sbin/reboot' action='32' terminal='/dev/ttyS0'
command='/sbin/swapoff -a 2>/dev/null' action='64' terminal='/dev/ttyS0'
command='/bin/umount -a -r' action='64' terminal='/dev/ttyS0'
Starting DHCP client: udhcpc a
BusyBox v1.2.0 (2006.07.21-07:20+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.
/ $
--
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
[-- Attachment #2: Type: text/html, Size: 9287 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
2006-10-30 19:45 ` David Bolcsfoldi
@ 2006-11-06 15:44 ` Peter Korsgaard
0 siblings, 0 replies; 24+ messages in thread
From: Peter Korsgaard @ 2006-11-06 15:44 UTC (permalink / raw)
To: linuxppc-embedded
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi,
>> This doesn't help much as you don't use the com_port argument in
>> the other functions.
David> True, it's utterly useless. I was planning on having an array
David> with base addresses which would be used to support the com_port
David> argument. But it didn't make it in this patch although I have
David> version that does this now.
You don't even need an array - you can use use the base address as the
com_port cookie, E.G.:
--- /dev/null
+++ linux-trunk/arch/ppc/boot/simple/uartlite_tty.c
@@ -0,0 +1,86 @@
+/*
+ * Boot support for Xilinx uartlite
+ *
+ * Copyright (C) 2006 David Bolcsfoldi <dbolcsfoldi@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <asm/io.h>
+#include <linux/serial_uartlite.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+unsigned long serial_init(int chan, void *ignored)
+{
+ unsigned long com_port = 0;
+
+ switch (chan) {
+#ifdef XPAR_UARTLITE_0_BASEADDR
+ case 0:
+ com_port = XPAR_UARTLITE_0_BASEADDR + 3;
+ break;
+#endif
+#ifdef XPAR_UARTLITE_1_BASEADDR
+ case 1:
+ com_port = XPAR_UARTLITE_1_BASEADDR + 3;
+ break;
+#endif
+#ifdef XPAR_UARTLITE_2_BASEADDR
+ case 2:
+ com_port = XPAR_UARTLITE_2_BASEADDR + 3;
+ break;
+#endif
+#ifdef XPAR_UARTLITE_3_BASEADDR
+ case 3:
+ com_port = XPAR_UARTLITE_3_BASEADDR + 3;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (com_port) {
+ void __iomem *base = (void __iomem*)com_port;
+ writeb(0, base + ULITE_CONTROL);
+ writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+ base + ULITE_CONTROL);
+ writeb(0, base + ULITE_CONTROL);
+ }
+
+ return com_port;
+}
+
+
+int serial_tstc(unsigned long com_port)
+{
+ void __iomem *base = (void __iomem*)com_port;
+
+ if (base)
+ return readb(base + ULITE_STATUS) & ULITE_STATUS_RXVALID;
+ else
+ return 0;
+}
+
+void serial_putc(unsigned long com_port, unsigned char c)
+{
+ void __iomem *base = (void __iomem*)com_port;
+
+ if (base) {
+ while (readb(base + ULITE_STATUS) & ULITE_STATUS_TXFULL);
+ writeb(c, base + ULITE_TX);
+ }
+}
+
+unsigned char serial_getc(unsigned long com_port)
+{
+ void __iomem *base = (void __iomem*)com_port;
+
+ if (base) {
+ while (!serial_tstc(com_port));
+ return readb(base + ULITE_RX);
+ }
+ else
+ return 0;
+}
>> Where did you get the XPAR_XUL_UART_ defines from? Our
>> xparameters.h seem to contain XPAR_UARTLITE_ defines instead.
David> I think that name is picked up from the name of the device in your
David> design, the defines get names XPAR_NNN_ and mine are called
David> XUL_UART.
Crap - Ok, then people just have to add linux-compatible defines to
the end of their xparameters.h - E.G
#define XPAR_UARTLITE_0_BASEADDR XPAR_XUL_UART_BASEADDR
>> You can always use the ppc_md.progress() stuff for really early
>> debugging if needed. I would prefer to keep this workaround out of
>> uartlite.c if it isn't needed.
David> I am pretty certain probe won't get called until ppc_sys_init has been
David> called which is fairly far into the booting process and even if
David> it did the platform_bus hasn't been initialized before the
David> ppc_sys_init is called, at least not with any of the devices
David> exported by ppc_sys_devices.
True. For really early stuff you'll need to use ppc_md.progress() (or
some additional hacking)
David> Thanks for the review! David
You're welcome.
--
Bye, Peter Korsgaard
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2006-11-06 15:44 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-10 20:49 [PATCH] Xilinx UART Lite 2.6.18 driver David Bolcsfoldi
2006-10-10 22:04 ` Grant Likely
2006-10-11 22:06 ` David H. Lynch Jr.
2006-10-12 10:34 ` Peter Korsgaard
2006-10-12 21:12 ` David Bolcsfoldi
2006-10-13 5:21 ` David Bolcsfoldi
2006-10-13 7:04 ` David H. Lynch Jr.
2006-10-13 7:22 ` Peter Korsgaard
[not found] ` <45329C42.3030000@dlasys.net>
2006-10-16 19:42 ` Peter Korsgaard
2006-10-13 7:11 ` Peter Korsgaard
2006-10-15 23:48 ` David Bolcsfoldi
2006-10-20 19:41 ` Peter Korsgaard
2006-10-27 15:03 ` Peter Korsgaard
2006-10-28 3:29 ` David H. Lynch Jr.
2006-10-30 8:23 ` Peter Korsgaard
2006-10-31 17:26 ` David H. Lynch Jr.
2006-10-30 19:45 ` David Bolcsfoldi
2006-11-06 15:44 ` Peter Korsgaard
2006-10-13 6:48 ` David H. Lynch Jr.
2006-10-13 7:15 ` Peter Korsgaard
2006-10-15 21:02 ` David H. Lynch Jr.
2006-10-16 19:49 ` Peter Korsgaard
2006-10-16 19:52 ` Peter Korsgaard
2006-10-13 7:08 ` Peter Korsgaard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).