Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: m-labs/linux-milkymist
base: 328c2ec
...
head fork: m-labs/linux-milkymist
compare: 329e85e
  • 3 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 22, 2011
@mwalle mwalle lm32: update driver for new uart core
Signed-off-by: Michael Walle <michael@walle.cc>
db2002a
@mwalle mwalle milkymist_uart: don't restart tx
Don't start transmission if one is still in progress.

Signed-off-by: Michael Walle <michael@walle.cc>
964d1db
@mwalle mwalle milkymist: new interrupt map
Signed-off-by: Michael Walle <michael@walle.cc>
329e85e
View
24 arch/lm32/boot/dts/milkymist_one.dts
@@ -23,7 +23,7 @@
device_type = "cpu";
compatible = "lattice,mico32";
reg = <0>;
- clock-frequency = <83333333>; /* 83.3333 MHz */
+ clock-frequency = <80000000>; /* 80 MHz */
i-cache-line-size = <16>;
d-cache-line-size = <16>;
i-cache-size = <4096>;
@@ -75,16 +75,16 @@
uart@0 {
device_type = "serial";
compatible = "milkymist,uart";
- clock-frequency = <83333333>;
+ clock-frequency = <80000000>;
reg = <0x0 0x1000>;
- interrupts = <0 1>;
+ interrupts = <0>;
interrupt-parent = <&pic>;
};
sysctl: sysctl@1000 {
compatible = "milkymist,sysctl";
reg = <0x1000 0x1000>;
- interrupts = <2 3 4>;
+ interrupts = <1 2 3>;
#gpio-cells = <2>;
gpio-controller;
num-gpi = <7>;
@@ -122,21 +122,21 @@
ac97@5000 {
compatible = "milkymist,ac97";
reg = <0x5000 0x1000>;
- interrupts = <5 6 7 8>;
+ interrupts = <4 5 6 7>;
interrupt-parent = <&pic>;
};
pfpu@6000 {
compatible = "milkymist,pfpu";
reg = <0x6000 0x1000>;
- interrupts = <9>;
+ interrupts = <8>;
interrupt-parent = <&pic>;
};
tmu@7000 {
compatible = "milkymist,tmu2";
reg = <0x7000 0x1000>;
- interrupts = <10>;
+ interrupts = <9>;
interrupt-parent = <&pic>;
};
@@ -145,7 +145,7 @@
#size-cells = <0>;
compatible = "milkymist,minimac2";
reg = <0x8000 0x1000>;
- interrupts = <11 12>;
+ interrupts = <10 11>;
interrupt-parent = <&pic>;
phy0: ethernet-phy@0 {
@@ -159,14 +159,14 @@
video-capture@a000 {
compatible = "milkymist,bt656cap";
reg = <0xa000 0x1000>;
- interrupts = <13>;
+ interrupts = <12>;
interrupt-parent = <&pic>;
};
midi@b000 {
compatible = "milkymist,midi";
reg = <0xb000 0x1000>;
- interrupts = <14 15>;
+ interrupts = <13>;
interrupt-parent = <&pic>;
};
@@ -178,14 +178,14 @@
ir-receiver@e000 {
compatible = "milkymist,rc5";
reg = <0xe000 0x1000>;
- interrupts = <16>;
+ interrupts = <14>;
interrupt-parent = <&pic>;
};
usb-ctrl@f000 {
compatible = "milkymist,softusb";
reg = <0xf000 0x1000>;
- interrupts = <17>;
+ interrupts = <15>;
interrupt-parent = <&pic>;
};
};
View
36 arch/lm32/include/asm/hw/interrupts.h
@@ -19,24 +19,22 @@
#define __HW_INTERRUPTS_H
#define IRQ_UARTRX (0)
-#define IRQ_UARTTX (1)
-#define IRQ_GPIO (2)
-#define IRQ_TIMER0 (3)
-#define IRQ_TIMER1 (4)
-#define IRQ_AC97CRREQUEST (5)
-#define IRQ_AC97CRREPLY (6)
-#define IRQ_AC97DMAR (7)
-#define IRQ_AC97DMAW (8)
-#define IRQ_PFPU (9)
-#define IRQ_TMU (10)
-#define IRQ_ETHRX (11)
-#define IRQ_ETHTX (12)
-#define IRQ_VIDEOIN (13)
-#define IRQ_MIDIRX (14)
-#define IRQ_MIDITX (15)
-#define IRQ_IR (16)
-#define IRQ_USB (17)
-#define IRQ_PS2KEYBOARD (14)
-#define IRQ_PS2MOUSE (15)
+#define IRQ_GPIO (1)
+#define IRQ_TIMER0 (2)
+#define IRQ_TIMER1 (3)
+#define IRQ_AC97CRREQUEST (4)
+#define IRQ_AC97CRREPLY (5)
+#define IRQ_AC97DMAR (6)
+#define IRQ_AC97DMAW (7)
+#define IRQ_PFPU (8)
+#define IRQ_TMU (9)
+#define IRQ_ETHRX (10)
+#define IRQ_ETHTX (11)
+#define IRQ_VIDEOIN (12)
+#define IRQ_MIDIRX (13)
+#define IRQ_IR (14)
+#define IRQ_USB (15)
+#define IRQ_PS2KEYBOARD (16)
+#define IRQ_PS2MOUSE (17)
#endif /* __HW_INTERRUPTS_H */
View
21 arch/lm32/platforms/milkymist/early_printk.c
@@ -35,20 +35,27 @@
#include <linux/string.h>
#include <asm/irq.h>
#include <linux/io.h>
-#include <asm/hw/milkymist.h>
+
+#define UART_RXTX (void*)0xe0000000
+#define UART_DIVISOR (void*)0xe0000004
+#define UART_STAT (void*)0xe0000008
+#define UART_CTRL (void*)0xe000000c
+#define UART_DEBUG (void*)0xe000000c
+
+#define UART_STAT_THRE (1<<0)
+#define UART_STAT_RX_EVT (1<<1)
+#define UART_STAT_TX_EVT (1<<2)
static void __init early_console_putc(char c)
{
unsigned int timeout = 1000;
- uint32_t pending;
+ uint32_t stat;
- iowrite32be(c, CSR_UART_RXTX);
+ iowrite32be(c, UART_RXTX);
do {
- pending = lm32_irq_pending();
- } while (pending & BIT(IRQ_UARTTX) && --timeout);
-
- lm32_irq_ack(IRQ_UARTTX);
+ stat = ioread32be(UART_STAT);
+ } while (!(stat & UART_STAT_THRE) && --timeout);
}
static void __init early_console_write(struct console *con, const char *s,
View
5 drivers/tty/serial/Kconfig
@@ -1518,6 +1518,11 @@ config SERIAL_MILKYMIST
help
Enable Milkymist UART driver.
+config SERIAL_MILKYMIST_NR_UARTS
+ int "Maximum number of milkymist serial ports"
+ depends on SERIAL_MILKYMIST
+ default "1"
+
config SERIAL_MILKYMIST_CONSOLE
bool "Enable Milkymist UART driver as system console"
depends on SERIAL_MILKYMIST
View
642 drivers/tty/serial/milkymist_uart.c
@@ -1,6 +1,10 @@
/*
- * (C) Copyright 2009 Sebastien Bourdeauducq, Takeshi Matsuya
- * (C) Copyright 2007 Theobroma Systems <www.theobroma-systems.com>
+ * Copyright (C) 2011 Michael Walle <michael@walle.cc>
+ * Copyright (C) 2009 Sebastien Bourdeauducq, Takeshi Matsuya
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
+ *
+ * based on uartlite.c
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -32,468 +36,490 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/serial_core.h>
-#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/setup.h>
-#include <asm/hw/milkymist.h>
-
-#define MILKYMISTUART_DRIVERNAME "milkymist_uart"
-#define MILKYMISTUART_DEVICENAME "ttyS"
-#define MILKYMISTUART_MAJOR TTY_MAJOR
-#define MILKYMISTUART_MINOR 64
-
-static volatile int tx_cts;
-static bool milkymist_uart_irqs_enabled;
-
-/* these two will be initialized by milkymistuart_init */
-static struct uart_port milkymistuart_ports[1];
-
-static struct uart_port* __devinit milkymistuart_init_port(void);
-
-static unsigned int milkymistuart_tx_empty(struct uart_port *port);
-static void milkymistuart_set_mctrl(struct uart_port *port, unsigned int mctrl);
-static unsigned int milkymistuart_get_mctrl(struct uart_port *port);
-static void milkymistuart_start_tx(struct uart_port *port);
-static void milkymistuart_stop_tx(struct uart_port *port);
-static void milkymistuart_stop_rx(struct uart_port *port);
-static void milkymistuart_enable_ms(struct uart_port *port);
-static void milkymistuart_break_ctl(struct uart_port *port, int break_state);
-static int milkymistuart_startup(struct uart_port *port);
-static void milkymistuart_shutdown(struct uart_port *port);
-static void milkymistuart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old);
-static const char *milkymistuart_type(struct uart_port *port);
-static void milkymistuart_release_port(struct uart_port *port);
-static int milkymistuart_request_port(struct uart_port *port);
-static void milkymistuart_config_port(struct uart_port *port, int flags);
-static int milkymistuart_verify_port(struct uart_port *port, struct serial_struct *ser);
-
-static inline void milkymistuart_set_baud_rate(struct uart_port *port, unsigned long baud);
-static irqreturn_t milkymistuart_irq_rx(int irq, void* portarg);
-static irqreturn_t milkymistuart_irq_tx(int irq, void* portarg);
-
-static struct uart_ops milkymistuart_pops = {
- .tx_empty = milkymistuart_tx_empty,
- .set_mctrl = milkymistuart_set_mctrl,
- .get_mctrl = milkymistuart_get_mctrl,
- .stop_tx = milkymistuart_stop_tx,
- .start_tx = milkymistuart_start_tx,
- .stop_rx = milkymistuart_stop_rx,
- .enable_ms = milkymistuart_enable_ms,
- .break_ctl = milkymistuart_break_ctl,
- .startup = milkymistuart_startup,
- .shutdown = milkymistuart_shutdown,
- .set_termios = milkymistuart_set_termios,
- .type = milkymistuart_type,
- .release_port = milkymistuart_release_port,
- .request_port = milkymistuart_request_port,
- .config_port = milkymistuart_config_port,
- .verify_port = milkymistuart_verify_port
-};
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
-static inline void milkymistuart_set_baud_rate(struct uart_port *port, unsigned long baud)
-{
- // TODO: use the board configuration option to get the frequency
- iowrite32be((unsigned long)CONFIG_CPU_CLOCK/baud/16, CSR_UART_DIVISOR);
-}
+#define MILKYMIST_UART_MAJOR TTY_MAJOR
+#define MILKYMIST_UART_MINOR 64
+
+#define MILKYMIST_NR_UARTS CONFIG_SERIAL_MILKYMIST_NR_UARTS
+
+#define UART_RXTX 0x00
+#define UART_DIV 0x04
+#define UART_STAT 0x08
+#define UART_CTRL 0x0c
+#define UART_DEBUG 0x10
+
+#define UART_STAT_THRE 0x01
+#define UART_STAT_RX_EVT 0x02
+#define UART_STAT_TX_EVT 0x04
+
+#define UART_CTRL_RX_INT 0x01
+#define UART_CTRL_TX_INT 0x02
+#define UART_CTRL_THRU 0x04
+
+#define UART_DEBUG_BREAK 0x01
-static void milkymistuart_tx_next_char(struct uart_port* port)
+static struct uart_port milkymist_uart_ports[MILKYMIST_NR_UARTS];
+
+static void milkymist_uart_tx_char(struct uart_port *port)
{
- struct circ_buf *xmit = &(port->state->xmit);
+ struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) {
- /* send xon/xoff character */
- tx_cts = 0;
- iowrite32be(port->x_char, CSR_UART_RXTX);
+ iowrite32be(port->x_char, port->membase + UART_RXTX);
port->x_char = 0;
port->icount.tx++;
return;
}
- /* stop transmitting if buffer empty */
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- tx_cts = 1;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
- }
- /* send next character */
- tx_cts = 0;
- iowrite32be(xmit->buf[xmit->tail], CSR_UART_RXTX);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ iowrite32be(xmit->buf[xmit->tail], port->membase + UART_RXTX);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
port->icount.tx++;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
-#if 0
-while(!(lm32_irq_pending() & (1 << IRQ_UARTTX)));
-#endif
}
-static void milkymistuart_rx_next_char(struct uart_port* port)
+static void milkymist_uart_rx_char(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
unsigned char ch;
- ch = ioread32be(CSR_UART_RXTX) & 0xFF;
+ ch = ioread32be(port->membase + UART_RXTX) & 0xff;
port->icount.rx++;
if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
- tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
ignore_char:
tty_flip_buffer_push(tty);
}
-static irqreturn_t milkymistuart_irq_rx(int irq, void* portarg)
+static irqreturn_t milkymist_uart_isr(int irq, void *data)
{
- struct uart_port* port = (struct uart_port*)portarg;
+ struct uart_port *port = data;
+ u8 stat;
+
+ spin_lock(&port->lock);
+
+ /* read and ack events */
+ stat = ioread32be(port->membase + UART_STAT) & 0xff;
+ iowrite32be(stat, port->membase + UART_STAT);
+
+ if (stat & UART_STAT_RX_EVT)
+ milkymist_uart_rx_char(port);
+ if (stat & UART_STAT_TX_EVT)
+ milkymist_uart_tx_char(port);
+
+ spin_unlock(&port->lock);
- milkymistuart_rx_next_char(port);
-
return IRQ_HANDLED;
}
-static irqreturn_t milkymistuart_irq_tx(int irq, void* portarg)
+static void milkymist_uart_start_tx(struct uart_port *port)
{
- struct uart_port* port = (struct uart_port*)portarg;
+ u8 stat;
+ stat = ioread32be(port->membase + UART_STAT) & 0xff;
- milkymistuart_tx_next_char(port);
+ /* transmission is still in progress */
+ if (!(stat & UART_STAT_THRE))
+ return;
- return IRQ_HANDLED;
+ milkymist_uart_tx_char(port);
}
-static unsigned int milkymistuart_tx_empty(struct uart_port *port)
+static unsigned int milkymist_uart_tx_empty(struct uart_port *port)
{
+ /* XXX return tx_pending */
return TIOCSER_TEMT;
}
-static void milkymistuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+static void milkymist_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* no modem control */
}
-static unsigned int milkymistuart_get_mctrl(struct uart_port *port)
+static unsigned int milkymist_uart_get_mctrl(struct uart_port *port)
{
return 0;
}
-static void milkymistuart_start_tx(struct uart_port *port)
+static void milkymist_uart_stop_tx(struct uart_port *port)
{
- if (tx_cts) {
- struct circ_buf *xmit = &(port->state->xmit);
-
- if (port->x_char) {
- /* send xon/xoff character */
- tx_cts = 0;
- iowrite32be(port->x_char, CSR_UART_RXTX);
- port->x_char = 0;
- port->icount.tx++;
- return;
- }
-
- /* stop transmitting if buffer empty */
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- return;
-
- /* send next character */
- tx_cts = 0;
- iowrite32be(xmit->buf[xmit->tail], CSR_UART_RXTX);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
- }
- return;
+static void milkymist_uart_stop_rx(struct uart_port *port)
+{
}
-static void milkymistuart_stop_tx(struct uart_port *port)
+static void milkymist_uart_enable_ms(struct uart_port *port)
{
- return;
}
+static void milkymist_uart_break_ctl(struct uart_port *port, int break_state)
+{
+}
-static void milkymistuart_stop_rx(struct uart_port *port)
+static int milkymist_uart_startup(struct uart_port *port)
{
- return;
+ int ret;
+
+ ret = request_irq(port->irq, milkymist_uart_isr,
+ IRQF_DISABLED, "milkymist_uart", port);
+
+ /* ack events */
+ iowrite32be(UART_STAT_TX_EVT | UART_STAT_RX_EVT,
+ port->membase + UART_STAT);
+
+ iowrite32be(UART_CTRL_RX_INT | UART_CTRL_TX_INT,
+ port->membase + UART_CTRL);
+
+ if (ret) {
+ pr_err("milkymist_uart: unable to attach interrupt\n");
+ return ret;
+ }
+
+ return 0;
}
-static void milkymistuart_enable_ms(struct uart_port *port)
+static void milkymist_uart_shutdown(struct uart_port *port)
{
+ iowrite32be(0, port->membase + UART_CTRL);
+ free_irq(port->irq, port);
}
-static void milkymistuart_break_ctl(struct uart_port *port, int break_state)
+static const char *milkymist_uart_type(struct uart_port *port)
{
+ return (port->type == PORT_MILKYMIST_UART) ? "Milkymist UART" : NULL;
}
-static int milkymistuart_startup(struct uart_port *port)
+static int milkymist_uart_request_port(struct uart_port *port)
{
- if( request_irq(IRQ_UARTRX, milkymistuart_irq_rx,
- IRQF_DISABLED, "milkymist_uart RX", port) ) {
- printk(KERN_NOTICE "Unable to attach Milkymist UART RX interrupt\n");
+ if (!request_mem_region(port->mapbase, 16, "milkymist_uart")) {
+ dev_err(port->dev, "memory region busy\n");
return -EBUSY;
}
- if( request_irq(IRQ_UARTTX, milkymistuart_irq_tx,
- IRQF_DISABLED, "milkymist_uart TX", port) ) {
- printk(KERN_NOTICE "Unable to attach Milkymist UART TX interrupt\n");
+
+ port->membase = ioremap(port->mapbase, 16);
+ if (!port->membase) {
+ dev_err(port->dev, "unable to map registers\n");
+ release_mem_region(port->mapbase, 16);
return -EBUSY;
}
- milkymist_uart_irqs_enabled = true;
-
return 0;
}
-static void milkymistuart_shutdown(struct uart_port *port)
+static void milkymist_uart_release_port(struct uart_port *port)
{
- milkymist_uart_irqs_enabled = false;
+ release_mem_region(port->mapbase, 16);
+ iounmap(port->membase);
+ port->membase = NULL;
+}
+
+static void milkymist_uart_config_port(struct uart_port *port, int flags)
+{
+ if (!milkymist_uart_request_port(port))
+ port->type = PORT_MILKYMIST_UART;
+}
- free_irq(IRQ_UARTRX, port);
- free_irq(IRQ_UARTTX, port);
+static int milkymist_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MILKYMIST_UART))
+ return -EINVAL;
+ return 0;
}
-static void milkymistuart_set_termios(
- struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+static void milkymist_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
{
- unsigned long baud;
unsigned long flags;
+ unsigned int baud;
+ unsigned int quot;
- /* >> 4 means / 16 */
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk >> 4);
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
- /* deactivate irqs */
spin_lock_irqsave(&port->lock, flags);
-
- milkymistuart_set_baud_rate(port, baud);
-
uart_update_timeout(port, termios->c_cflag, baud);
-
- /* restore irqs */
+ iowrite32be(quot, port->membase + UART_DIV);
spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *milkymistuart_type(struct uart_port *port)
-{
- /* check, to be on the safe side */
- if( port->type == PORT_UARTLITE )
- return "milkymist_uart";
- else
- return "error";
-}
-static void milkymistuart_release_port(struct uart_port *port)
-{
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
}
-static int milkymistuart_request_port(struct uart_port *port)
-{
- return 0;
-}
+static struct uart_ops milkymist_uart_ops = {
+ .tx_empty = milkymist_uart_tx_empty,
+ .set_mctrl = milkymist_uart_set_mctrl,
+ .get_mctrl = milkymist_uart_get_mctrl,
+ .stop_tx = milkymist_uart_stop_tx,
+ .start_tx = milkymist_uart_start_tx,
+ .stop_rx = milkymist_uart_stop_rx,
+ .enable_ms = milkymist_uart_enable_ms,
+ .break_ctl = milkymist_uart_break_ctl,
+ .startup = milkymist_uart_startup,
+ .shutdown = milkymist_uart_shutdown,
+ .set_termios = milkymist_uart_set_termios,
+ .type = milkymist_uart_type,
+ .release_port = milkymist_uart_release_port,
+ .request_port = milkymist_uart_request_port,
+ .config_port = milkymist_uart_config_port,
+ .verify_port = milkymist_uart_verify_port,
+#if 0
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = milkymist_uart_get_poll_char,
+ .poll_put_char = milkymist_uart_put_poll_char,
+#endif
+#endif
+};
-/* we will only configure the port type here */
-static void milkymistuart_config_port(struct uart_port *port, int flags)
+#ifdef CONFIG_SERIAL_MILKYMIST_CONSOLE
+static void milkymist_uart_console_wait_tx(struct uart_port *port)
{
- if( flags & UART_CONFIG_TYPE ) {
- port->type = PORT_UARTLITE;
+ int i;
+ u8 stat;
+
+ for (i = 0; i < 100000; i++) {
+ stat = ioread32be(port->membase + UART_STAT) & 0xff;
+ if (stat & UART_STAT_THRE)
+ break;
+ cpu_relax();
}
}
-/* we do not allow the user to configure via this method */
-static int milkymistuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+static void milkymist_uart_console_putchar(struct uart_port *port, int ch)
{
- return -EINVAL;
+ milkymist_uart_console_wait_tx(port);
+ iowrite32be(ch, port->membase + UART_RXTX);
}
-#ifdef CONFIG_SERIAL_MILKYMIST_CONSOLE
-static void milkymist_console_putchar(struct uart_port *port, int ch)
+static void milkymist_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
{
- if (milkymist_uart_irqs_enabled)
- disable_irq(IRQ_UARTTX);
- iowrite32be(ch, CSR_UART_RXTX);
- while(!(lm32_irq_pending() & (1 << IRQ_UARTTX)));
- lm32_irq_ack(IRQ_UARTTX);
- if (milkymist_uart_irqs_enabled)
- enable_irq(IRQ_UARTTX);
-}
+ struct uart_port *port = &milkymist_uart_ports[co->index];
+ u32 ctrl;
+ unsigned long flags;
+ int locked = 1;
-/*
- * Interrupts are disabled on entering
- */
-static void milkymist_console_write(struct console *co, const char *s, u_int count)
-{
- struct uart_port *port = &milkymistuart_ports[co->index];
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* wait until current transmission is finished */
+ milkymist_uart_console_wait_tx(port);
+
+ /* save ctrl and stat */
+ ctrl = ioread32be(port->membase + UART_CTRL);
+
+ /* disable irqs */
+ iowrite32be(ctrl & ~(UART_CTRL_RX_INT | UART_CTRL_TX_INT),
+ port->membase + UART_CTRL);
- uart_console_write(port, s, count, milkymist_console_putchar);
+ uart_console_write(port, s, count, milkymist_uart_console_putchar);
+ milkymist_uart_console_wait_tx(port);
+
+ /* ack write event */
+ iowrite32be(UART_STAT_TX_EVT, port->membase + UART_STAT);
+
+ /* restore control register */
+ iowrite32be(ctrl, port->membase + UART_CTRL);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
}
-static int __init milkymist_console_setup(struct console *co, char *options)
+static int __devinit milkymist_uart_console_setup(struct console *co,
+ char *options)
{
- struct uart_port *port = &milkymistuart_ports[co->index];
-
+ struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
+ if (co->index < 0 || co->index >= MILKYMIST_NR_UARTS)
+ return -EINVAL;
+
+ port = &milkymist_uart_ports[co->index];
+
+ if (!port->mapbase) {
+ pr_debug("console on ttyS%i not present\n", co->index);
+ return -ENODEV;
+ }
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
-static struct uart_driver milkymistuart_driver;
+static struct uart_driver milkymist_uart_driver;
-static struct console milkymist_console = {
- .name = MILKYMISTUART_DEVICENAME,
- .write = milkymist_console_write,
- .device = uart_console_device,
- .setup = milkymist_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &milkymistuart_driver,
+static struct console milkymist_uart_console = {
+ .name = "ttyS",
+ .write = milkymist_uart_console_write,
+ .device = uart_console_device,
+ .setup = milkymist_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &milkymist_uart_driver,
};
-/*
- * Early console initialization
- */
-static int __init milkymist_early_console_init(void)
+static int __init milkymist_uart_console_init(void)
{
- add_preferred_console(MILKYMISTUART_DEVICENAME, 0, NULL);
- milkymistuart_init_port();
- register_console(&milkymist_console);
- pr_info("milkymist_uart: registered real console\n");
+ register_console(&milkymist_uart_console);
return 0;
}
-console_initcall(milkymist_early_console_init);
+console_initcall(milkymist_uart_console_init);
+#endif
-/*
- * Late console initialization
- */
-static int __init milkymist_late_console_init(void)
+static struct uart_driver milkymist_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "milkymist_uart",
+ .dev_name = "ttyS",
+ .major = MILKYMIST_UART_MAJOR,
+ .minor = MILKYMIST_UART_MINOR,
+ .nr = MILKYMIST_NR_UARTS,
+#ifdef CONFIG_SERIAL_MILKYMIST_CONSOLE
+ .cons = &milkymist_uart_console,
+#endif
+};
+
+static int __devinit milkymist_uart_probe(struct platform_device *op)
{
- if( !(milkymist_console.flags & CON_ENABLED) ) {
- register_console(&milkymist_console);
- pr_info("milkymist_uart: registered real console\n");
+ struct uart_port *port;
+ struct device_node *np = op->dev.of_node;
+ int ret;
+ struct resource res;
+ const unsigned int *pid, *clk;
+ int id;
+ int irq;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&op->dev, "invalid address\n");
+ return ret;
}
- return 0;
-}
-core_initcall(milkymist_late_console_init);
-#define MILKYMIST_CONSOLE_DEVICE &milkymist_console
-#else
-#define MILKYMIST_CONSOLE_DEVICE NULL
-#endif
+ irq = irq_of_parse_and_map(np, 0);
-static struct uart_driver milkymistuart_driver = {
- .owner = THIS_MODULE,
- .driver_name = MILKYMISTUART_DRIVERNAME,
- .dev_name = MILKYMISTUART_DEVICENAME,
- .major = MILKYMISTUART_MAJOR,
- .minor = MILKYMISTUART_MINOR,
- .nr = 0, /* will be filled by init */
- .cons = MILKYMIST_CONSOLE_DEVICE
-};
+ clk = of_get_property(np, "clock-frequency", NULL);
+ if (!clk) {
+ dev_warn(&op->dev, "no clock-frequency property set\n");
+ return -ENODEV;
+ }
-static struct uart_port* __devinit milkymistuart_init_port(void)
-{
- struct uart_port* port;
+ pid = of_get_property(np, "port-number", NULL);
+
+ if (pid)
+ id = *pid;
+ else {
+ /* find free id */
+ for (id = 0; id < MILKYMIST_NR_UARTS; id++)
+ if (milkymist_uart_ports[id].mapbase == 0)
+ break;
+ }
+
+ if (id < 0 || id >= MILKYMIST_NR_UARTS) {
+ dev_err(&op->dev, "milkymist_uart%i too large\n", id);
+ return -EINVAL;
+ }
+
+ if (milkymist_uart_ports[id].mapbase
+ && milkymist_uart_ports[id].mapbase != res.start) {
+ dev_err(&op->dev, "milkymist_uart%i already in use\n", id);
+ return -EBUSY;
+ }
+
+ ret = uart_register_driver(&milkymist_uart_driver);
+ if (ret) {
+ dev_err(&op->dev, "uart_register_driver() failed; err=%i\n", ret);
+ return ret;
+ }
+
+ port = &milkymist_uart_ports[id];
+
+ spin_lock_init(&port->lock);
+ port->line = id;
+ port->regshift = 2;
+ port->iotype = UPIO_MEM;
+ port->mapbase = res.start;
+ port->membase = NULL;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->irq = irq;
+
+ port->ops = &milkymist_uart_ops;
+ port->type = PORT_UNKNOWN;
+ port->uartclk = *clk;
- port = &milkymistuart_ports[0];
- port->type = PORT_UARTLITE;
- port->iobase = 0x0;
- port->membase = (void __iomem*)CSR_UART_RXTX;
- port->irq = IRQ_UARTRX;
- port->uartclk = CONFIG_CPU_CLOCK;
- port->flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; // TODO perhaps this is not completely correct
- port->iotype = UPIO_PORT; // TODO perhaps this is not completely correct
- port->regshift = 0;
- port->ops = &milkymistuart_pops;
- port->line = 0;
- port->private_data = NULL;
- return port;
-}
+ port->dev = &op->dev;
-static int __devinit milkymistuart_serial_probe(struct platform_device *pdev)
-{
- struct uart_port *port;
- int ret;
+ dev_set_drvdata(&op->dev, port);
- port = milkymistuart_init_port();
+ ret = uart_add_one_port(&milkymist_uart_driver, port);
+ if (ret) {
+ dev_err(&op->dev, "uart_add_one_port() failed; err=%i\n", ret);
+ port->mapbase = 0;
+ return ret;
+ }
- ret = uart_add_one_port(&milkymistuart_driver, port);
- if (!ret) {
- pr_info("milkymist_uart: added port %d with irq %d-%d at 0x%lx\n",
- port->line, IRQ_UARTRX, IRQ_UARTTX, (unsigned long)port->membase);
- device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
- } else
- printk(KERN_ERR "milkymist_uart: could not add port %d: %d\n", port->line, ret);
+ //device_init_wakeup(&op->dev, 1);
- return ret;
+ return 0;
}
-static int __devexit milkymistuart_serial_remove(struct platform_device *pdev)
+static int __devexit milkymist_uart_remove(struct platform_device *dev)
{
- struct uart_port *port = platform_get_drvdata(pdev);
- int ret = 0;
-
- device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
+ struct uart_port *port = dev_get_drvdata(&dev->dev);
- if (port) {
- ret = uart_remove_one_port(&milkymistuart_driver, port);
- kfree(port);
- }
+ uart_remove_one_port(&milkymist_uart_driver, port);
+ dev_set_drvdata(&dev->dev, NULL);
+ port->mapbase = 0;
- return ret;
+ return 0;
}
-static const struct of_device_id milkymistuart_of_ids[] = {
+static const struct of_device_id milkymist_uart_match[] = {
{ .compatible = "milkymist,uart", },
- {}
+ {},
};
+MODULE_DEVICE_TABLE(of, milkymist_uart_match);
-static struct platform_driver milkymistuart_serial_driver = {
- .probe = milkymistuart_serial_probe,
- .remove = __devexit_p(milkymistuart_serial_remove),
- .driver = {
- .name = "milkymist_uart",
- .owner = THIS_MODULE,
- .of_match_table = milkymistuart_of_ids,
+static struct platform_driver milkymist_uart_of_driver = {
+ .driver = {
+ .name = "milkymist_uart",
+ .owner = THIS_MODULE,
+ .of_match_table = milkymist_uart_match,
},
+ .probe = milkymist_uart_probe,
+ .remove = __devexit_p(milkymist_uart_remove),
};
-static int __init milkymistuart_init(void)
+static int __init milkymist_uart_init(void)
{
- int ret;
-
- pr_info("milkymist_uart: Milkymist UART driver\n");
-
- /* configure from hardware setup structures */
- milkymistuart_driver.nr = 1;
- tx_cts = 1;
- ret = uart_register_driver(&milkymistuart_driver);
- if( ret < 0 )
- return ret;
-
- ret = platform_driver_register(&milkymistuart_serial_driver);
- if( ret < 0 )
- uart_unregister_driver(&milkymistuart_driver);
-
- return ret;
+ return platform_driver_register(&milkymist_uart_of_driver);
}
-static void __exit milkymistuart_exit(void)
+static void __exit milkymist_uart_exit(void)
{
- platform_driver_unregister(&milkymistuart_serial_driver);
- uart_unregister_driver(&milkymistuart_driver);
+ platform_driver_unregister(&milkymist_uart_of_driver);
}
-module_init(milkymistuart_init);
-module_exit(milkymistuart_exit);
+module_init(milkymist_uart_init);
+module_exit(milkymist_uart_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Milkymist UART driver");
MODULE_AUTHOR("Milkymist Project");
+MODULE_DESCRIPTION("Milkymist UART driver");
+MODULE_LICENSE("GPL");
View
3  include/linux/serial_core.h
@@ -206,6 +206,9 @@
/* Xilinx PSS UART */
#define PORT_XUARTPS 98
+/* Milkymist UART */
+#define PORT_MILKYMIST_UART 99
+
#ifdef __KERNEL__
#include <linux/compiler.h>

No commit comments for this range

Something went wrong with that request. Please try again.