ENGR00117720-2 MX28: Add Debug Uart Driver Support

Add D-UART driver support for MX28

Signed-off-by: Fred Fan <r01011@freescale.com>
Signed-off-by: Robby Cai <R63905@freescale.com>
This commit is contained in:
Robby Cai
2010-01-20 20:39:15 +08:00
committed by Matt Sealey
parent 53d075b2f4
commit fea0ec16c7
4 changed files with 1098 additions and 0 deletions

View File

@@ -359,6 +359,30 @@ config SERIAL_STMP_APP
help
Driver for Sigmatel 36XX/37XX internal application serial port
config SERIAL_MXS_DUART
tristate "i.MXS debug serial port support"
depends on ARCH_MXS
select SERIAL_CORE
help
Driver for Freescale i.MXS internal debug serial port
config SERIAL_MXS_DUART_CONSOLE
bool "Support for console on i.MXS debug serial port"
depends on SERIAL_MXS_DUART=y
select SERIAL_CORE_CONSOLE
---help---
Say Y here if you wish to use the i.MXS debug serial port 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).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyAM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_AMBA_PL011
tristate "ARM AMBA PL011 serial port support"
depends on ARM_AMBA

View File

@@ -77,6 +77,7 @@ obj-$(CONFIG_SERIAL_MXC) += mxc_uart.o
obj-$(CONFIG_SERIAL_MXC_CONSOLE) += mxc_uart_early.o
obj-$(CONFIG_SERIAL_STMP_DBG) += stmp-dbg.o
obj-$(CONFIG_SERIAL_STMP_APP) += stmp-app.o
obj-$(CONFIG_SERIAL_MXS_DUART) += mxs-duart.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o

772
drivers/serial/mxs-duart.c Normal file
View File

@@ -0,0 +1,772 @@
/*
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#if defined(CONFIG_SERIAL_MXS_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <mach/hardware.h>
#include <mach/device.h>
#include "regs-duart.h"
/* treated as variable unless submitted to open-source */
#define PORT_DUART 100
#define SERIAL_DUART_MAJOR 204
#define SERIAL_DUART_MINOR 16
#define SERIAL_RX_LIMIT 256
#define ISR_PASS_LIMIT 256
#define DUART_DEVID "DebugUART"
static int force_cd = 1;
static struct uart_driver duart_drv;
/*
* We wrap our port structure around the generic uart_port.
*/
struct duart_port {
struct uart_port port;
struct clk *clk;
unsigned int im; /* interrupt mask */
unsigned int old_status;
int suspended;
};
static void duart_stop_tx(struct uart_port *port)
{
struct duart_port *dp = container_of(port, struct duart_port, port);
dp->im &= ~BM_UARTDBGIMSC_TXIM;
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
}
static void duart_start_tx(struct uart_port *port)
{
struct duart_port *dp = container_of(port, struct duart_port, port);
dp->im |= BM_UARTDBGIMSC_TXIM;
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
}
static void duart_stop_rx(struct uart_port *port)
{
struct duart_port *dp = container_of(port, struct duart_port, port);
dp->im &= ~(BM_UARTDBGIMSC_OEIM | BM_UARTDBGIMSC_BEIM |
BM_UARTDBGIMSC_PEIM | BM_UARTDBGIMSC_FEIM |
BM_UARTDBGIMSC_RTIM | BM_UARTDBGIMSC_RXIM);
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
}
static void duart_enable_ms(struct uart_port *port)
{
struct duart_port *dp = container_of(port, struct duart_port, port);
dp->im |= BM_UARTDBGIMSC_RIMIM | BM_UARTDBGIMSC_CTSMIM |
BM_UARTDBGIMSC_DCDMIM | BM_UARTDBGIMSC_DSRMIM;
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
}
static void duart_rx_chars(struct duart_port *dp)
{
struct tty_struct *tty = dp->port.info->port.tty;
unsigned int status, ch, flag, rsr, max_count = SERIAL_RX_LIMIT;
status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
while ((status & BM_UARTDBGFR_RXFE) == 0 && max_count--) {
ch = __raw_readl(dp->port.membase + HW_UARTDBGDR);
flag = TTY_NORMAL;
dp->port.icount.rx++;
/*
* Note that the error handling code is
* out of the main execution path
*/
rsr = __raw_readl(dp->port.membase + HW_UARTDBGRSR_ECR);
if (unlikely(rsr & (BM_UARTDBGRSR_ECR_OE |
BM_UARTDBGRSR_ECR_BE |
BM_UARTDBGRSR_ECR_PE |
BM_UARTDBGRSR_ECR_FE))) {
if (rsr & BM_UARTDBGRSR_ECR_BE) {
rsr &= ~(BM_UARTDBGRSR_ECR_FE |
BM_UARTDBGRSR_ECR_PE);
dp->port.icount.brk++;
if (uart_handle_break(&dp->port))
goto ignore_char;
} else if (rsr & BM_UARTDBGRSR_ECR_PE)
dp->port.icount.parity++;
else if (rsr & BM_UARTDBGRSR_ECR_FE)
dp->port.icount.frame++;
if (rsr & BM_UARTDBGRSR_ECR_OE)
dp->port.icount.overrun++;
rsr &= dp->port.read_status_mask;
if (rsr & BM_UARTDBGRSR_ECR_BE)
flag = TTY_BREAK;
else if (rsr & BM_UARTDBGRSR_ECR_PE)
flag = TTY_PARITY;
else if (rsr & BM_UARTDBGRSR_ECR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&dp->port, ch))
goto ignore_char;
uart_insert_char(&dp->port, rsr, BM_UARTDBGRSR_ECR_OE, ch,
flag);
ignore_char:
status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
}
tty_flip_buffer_push(tty);
return;
}
static void duart_tx_chars(struct duart_port *dp)
{
int count;
struct circ_buf *xmit = &dp->port.info->xmit;
if (dp->port.x_char) {
__raw_writel(dp->port.x_char, dp->port.membase + HW_UARTDBGDR);
dp->port.icount.tx++;
dp->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&dp->port)) {
duart_stop_tx(&dp->port);
return;
}
count = dp->port.fifosize >> 1;
do {
__raw_writel(xmit->buf[xmit->tail],
dp->port.membase + HW_UARTDBGDR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
dp->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&dp->port);
if (uart_circ_empty(xmit))
duart_stop_tx(&dp->port);
}
static void duart_modem_status(struct duart_port *dp)
{
unsigned int status, delta;
status = __raw_readl(dp->port.membase + HW_UARTDBGFR) &
(BM_UARTDBGFR_DCD | BM_UARTDBGFR_DSR | BM_UARTDBGFR_CTS);
delta = status ^ dp->old_status;
dp->old_status = status;
if (!delta)
return;
if (delta & BM_UARTDBGFR_DCD)
uart_handle_dcd_change(&dp->port, status & BM_UARTDBGFR_DCD);
if (delta & BM_UARTDBGFR_DSR)
dp->port.icount.dsr++;
if (delta & BM_UARTDBGFR_CTS)
uart_handle_cts_change(&dp->port, status & BM_UARTDBGFR_CTS);
wake_up_interruptible(&dp->port.info->delta_msr_wait);
}
static irqreturn_t duart_int(int irq, void *dev_id)
{
int handled = 0;
struct duart_port *dp = dev_id;
unsigned int status, pass_counter = ISR_PASS_LIMIT;
spin_lock(&dp->port.lock);
status = __raw_readl(dp->port.membase + HW_UARTDBGMIS);
while (status) {
handled = 1;
__raw_writel(status & ~(BM_UARTDBGMIS_TXMIS |
BM_UARTDBGMIS_RTMIS |
BM_UARTDBGMIS_RXMIS),
dp->port.membase + HW_UARTDBGICR);
if (status & (BM_UARTDBGMIS_RTMIS | BM_UARTDBGMIS_RXMIS))
duart_rx_chars(dp);
if (status & (BM_UARTDBGMIS_DSRMMIS |
BM_UARTDBGMIS_DCDMMIS |
BM_UARTDBGMIS_CTSMMIS | BM_UARTDBGMIS_RIMMIS))
duart_modem_status(dp);
if (status & BM_UARTDBGMIS_TXMIS)
duart_tx_chars(dp);
if (pass_counter-- == 0)
break;
status = __raw_readl(dp->port.membase + HW_UARTDBGMIS);
};
spin_unlock(&dp->port.lock);
return IRQ_RETVAL(handled);
}
static unsigned int duart_tx_empty(struct uart_port *port)
{
struct duart_port *dp = (struct duart_port *)port;
unsigned int status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
return status & (BM_UARTDBGFR_BUSY | BM_UARTDBGFR_TXFF) ?
0 : TIOCSER_TEMT;
}
static unsigned int duart_get_mctrl(struct uart_port *port)
{
unsigned int result = 0;
struct duart_port *dp = (struct duart_port *)port;
unsigned int status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
#define TEST_AND_SET_BIT(uartbit, tiocmbit) do { \
if (status & uartbit) \
result |= tiocmbit; \
} while (0)
TEST_AND_SET_BIT(BM_UARTDBGFR_DCD, TIOCM_CAR);
TEST_AND_SET_BIT(BM_UARTDBGFR_DSR, TIOCM_DSR);
TEST_AND_SET_BIT(BM_UARTDBGFR_CTS, TIOCM_CTS);
TEST_AND_SET_BIT(BM_UARTDBGFR_RI, TIOCM_RNG);
#undef TEST_AND_SET_BIT
if (force_cd)
result |= TIOCM_CAR;
return result;
}
static void duart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned int cr;
struct duart_port *dp = (struct duart_port *)port;
cr = __raw_readl(dp->port.membase + HW_UARTDBGCR);
#define TEST_AND_SET_BIT(tiocmbit, uartbit) do { \
if (mctrl & tiocmbit) \
cr |= uartbit; \
else \
cr &= ~uartbit; \
} while (0)
TEST_AND_SET_BIT(TIOCM_RTS, BM_UARTDBGCR_RTS);
TEST_AND_SET_BIT(TIOCM_DTR, BM_UARTDBGCR_DTR);
TEST_AND_SET_BIT(TIOCM_OUT1, BM_UARTDBGCR_OUT1);
TEST_AND_SET_BIT(TIOCM_OUT2, BM_UARTDBGCR_OUT2);
TEST_AND_SET_BIT(TIOCM_LOOP, BM_UARTDBGCR_LBE);
#undef TEST_AND_SET_BIT
__raw_writel(cr, dp->port.membase + HW_UARTDBGCR);
}
static void duart_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int lcr_h;
struct duart_port *dp = (struct duart_port *)port;
spin_lock_irqsave(&dp->port.lock, flags);
lcr_h = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
if (break_state == -1)
lcr_h |= BM_UARTDBGLCR_H_BRK;
else
lcr_h &= ~BM_UARTDBGLCR_H_BRK;
__raw_writel(lcr_h, dp->port.membase + HW_UARTDBGLCR_H);
spin_unlock_irqrestore(&dp->port.lock, flags);
}
static int duart_startup(struct uart_port *port)
{
u32 cr, lcr;
int retval;
struct duart_port *dp = (struct duart_port *)port;
/*
* Allocate the IRQ
*/
retval = request_irq(dp->port.irq, duart_int, 0, DUART_DEVID, dp);
if (retval)
return retval;
/* wake up the UART */
__raw_writel(0, dp->port.membase + HW_UARTDBGDR);
__raw_writel(BF_UARTDBGIFLS_TXIFLSEL(BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF)
|
BF_UARTDBGIFLS_RXIFLSEL(BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF),
dp->port.membase + HW_UARTDBGIFLS);
/*
* Provoke TX FIFO interrupt into asserting.
*/
cr = BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_RXE | BM_UARTDBGCR_TXE;
__raw_writel(cr, dp->port.membase + HW_UARTDBGCR);
lcr = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
lcr |= BM_UARTDBGLCR_H_FEN;
__raw_writel(lcr, dp->port.membase + HW_UARTDBGLCR_H);
/*
* initialise the old status of the modem signals
*/
dp->old_status = __raw_readl(dp->port.membase + HW_UARTDBGFR) &
(BM_UARTDBGFR_DCD | BM_UARTDBGFR_DSR | BM_UARTDBGFR_CTS);
/*
* Finally, enable interrupts
*/
dp->im = BM_UARTDBGIMSC_RXIM | BM_UARTDBGIMSC_RTIM;
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
return 0;
}
static void duart_shutdown(struct uart_port *port)
{
unsigned long flags;
unsigned int val;
struct duart_port *dp = (struct duart_port *)port;
/*
* disable all interrupts
*/
spin_lock_irqsave(&dp->port.lock, flags);
dp->im = 0;
__raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
__raw_writel(0xffff, dp->port.membase + HW_UARTDBGICR);
spin_unlock_irqrestore(&dp->port.lock, flags);
free_irq(dp->port.irq, dp);
/*
* disable the port
*/
__raw_writel(BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_TXE,
dp->port.membase + HW_UARTDBGCR);
/*
* disable break condition and fifos
*/
val = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
val &= ~(BM_UARTDBGLCR_H_BRK | BM_UARTDBGLCR_H_FEN);
__raw_writel(val, dp->port.membase + HW_UARTDBGLCR_H);
}
static void
duart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
quot = (port->uartclk << 2) / baud;
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr_h = BF_UARTDBGLCR_H_WLEN(0);
break;
case CS6:
lcr_h = BF_UARTDBGLCR_H_WLEN(1);
break;
case CS7:
lcr_h = BF_UARTDBGLCR_H_WLEN(2);
break;
default: /* CS8 */
lcr_h = BF_UARTDBGLCR_H_WLEN(3);
break;
}
if (termios->c_cflag & CSTOPB)
lcr_h |= BM_UARTDBGLCR_H_STP2;
if (termios->c_cflag & PARENB) {
lcr_h |= BM_UARTDBGLCR_H_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= BM_UARTDBGLCR_H_EPS;
}
lcr_h |= BM_UARTDBGLCR_H_FEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = BM_UARTDBGRSR_ECR_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= BM_UARTDBGRSR_ECR_FE |
BM_UARTDBGRSR_ECR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= BM_UARTDBGRSR_ECR_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= BM_UARTDBGRSR_ECR_FE |
BM_UARTDBGRSR_ECR_PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= BM_UARTDBGRSR_ECR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= BM_UARTDBGRSR_ECR_OE;
}
if (UART_ENABLE_MS(port, termios->c_cflag))
duart_enable_ms(port);
/* first, disable everything */
old_cr = __raw_readl(port->membase + HW_UARTDBGCR);
__raw_writel(0, port->membase + HW_UARTDBGCR);
/* Set baud rate */
__raw_writel(quot & 0x3f, port->membase + HW_UARTDBGFBRD);
__raw_writel(quot >> 6, port->membase + HW_UARTDBGIBRD);
/*
* ----------v----------v----------v----------v-----
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* ----------^----------^----------^----------^-----
*/
__raw_writel(lcr_h, port->membase + HW_UARTDBGLCR_H);
__raw_writel(old_cr, port->membase + HW_UARTDBGCR);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *duart_type(struct uart_port *port)
{
return port->type == PORT_DUART ? DUART_DEVID : NULL;
}
/*
* Release the memory region(s) being used by 'port'
*/
static void duart_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, PAGE_SIZE);
}
/*
* Request the memory region(s) being used by 'port'
*/
static int duart_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, PAGE_SIZE, DUART_DEVID)
!= NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void duart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_DUART;
duart_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int duart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_DUART)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops duart_pops = {
.tx_empty = duart_tx_empty,
.set_mctrl = duart_set_mctrl,
.get_mctrl = duart_get_mctrl,
.stop_tx = duart_stop_tx,
.start_tx = duart_start_tx,
.stop_rx = duart_stop_rx,
.enable_ms = duart_enable_ms,
.break_ctl = duart_break_ctl,
.startup = duart_startup,
.shutdown = duart_shutdown,
.set_termios = duart_set_termios,
.type = duart_type,
.release_port = duart_release_port,
.request_port = duart_request_port,
.config_port = duart_config_port,
.verify_port = duart_verify_port,
};
static struct duart_port duart_port = {
.port = {
.iotype = SERIAL_IO_MEM,
#ifdef CONFIG_MXS_EARLY_CONSOLE
.membase = MXS_DEBUG_CONSOLE_VIRT,
.mapbase = MXS_DEBUG_CONSOLE_PHYS,
#endif
.fifosize = 16,
.ops = &duart_pops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 0,
},
};
#ifdef CONFIG_SERIAL_MXS_DUART_CONSOLE
static void
duart_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &duart_port.port;
unsigned int status, old_cr;
int i;
/*
* First save the CR then disable the interrupts
*/
old_cr = __raw_readl(port->membase + HW_UARTDBGCR);
__raw_writel(BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_TXE,
port->membase + HW_UARTDBGCR);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = __raw_readl(port->membase + HW_UARTDBGFR);
} while (status & BM_UARTDBGFR_TXFF);
__raw_writel(s[i], port->membase + HW_UARTDBGDR);
if (s[i] == '\n') {
do {
status = __raw_readl(port->membase +
HW_UARTDBGFR);
} while (status & BM_UARTDBGFR_TXFF);
__raw_writel('\r', port->membase + HW_UARTDBGDR);
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
do {
status = __raw_readl(port->membase + HW_UARTDBGFR);
} while (status & BM_UARTDBGFR_BUSY);
__raw_writel(old_cr, port->membase + HW_UARTDBGCR);
}
static void __init
duart_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
if (__raw_readl(port->membase + HW_UARTDBGCR) & BM_UARTDBGCR_UARTEN) {
unsigned int lcr_h, quot;
lcr_h = __raw_readl(port->membase + HW_UARTDBGLCR_H);
*parity = 'n';
if (lcr_h & BM_UARTDBGLCR_H_PEN) {
if (lcr_h & BM_UARTDBGLCR_H_EPS)
*parity = 'e';
else
*parity = 'o';
}
if ((lcr_h & BM_UARTDBGLCR_H_WLEN) == BF_UARTDBGLCR_H_WLEN(2))
*bits = 7;
else
*bits = 8;
quot = (__raw_readl(port->membase + HW_UARTDBGFBRD) & 0x3F) |
__raw_readl(port->membase + HW_UARTDBGIBRD) << 6;
if (quot == 0)
quot = 1;
*baud = (port->uartclk << 2) / quot;
}
}
static int __init duart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index)
return -EINVAL;
port = &duart_port.port;
if (duart_port.clk == NULL || IS_ERR(duart_port.clk)) {
duart_port.clk = clk_get(NULL, "uart");
if (duart_port.clk == NULL || IS_ERR(duart_port.clk))
return -ENODEV;
duart_port.port.uartclk = clk_get_rate(duart_port.clk);
}
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
duart_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct console duart_console = {
.name = "ttyAM",
.write = duart_console_write,
.device = uart_console_device,
.setup = duart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &duart_drv,
};
#ifdef CONFIG_MXS_EARLY_CONSOLE
static int __init duart_console_init(void)
{
register_console(&duart_console);
return 0;
}
console_initcall(duart_console_init);
#endif
#endif
static struct uart_driver duart_drv = {
.owner = THIS_MODULE,
.driver_name = "ttyAM",
.dev_name = "ttyAM",
.major = SERIAL_DUART_MAJOR,
.minor = SERIAL_DUART_MINOR,
.nr = 1,
#ifdef CONFIG_SERIAL_MXS_DUART_CONSOLE
.cons = &duart_console,
#endif
};
static int __devinit duart_probe(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOMEM;
/*
* Will use mapbase and membase here if !CONFIG_MXS_EARLY_CONSOLE,
* or use the overridden values later if CONFIG_MXS_EARLY_CONSOLE
*/
duart_port.port.mapbase = res->start;
duart_port.port.membase =
(unsigned char __iomem *)IO_ADDRESS(res->start);
duart_port.port.irq = platform_get_irq(pdev, 0);
if (duart_port.port.irq < 0)
return -EINVAL;
device_init_wakeup(&pdev->dev, 1);
duart_port.clk = clk_get(NULL, "uart");
if (duart_port.clk == NULL || IS_ERR(duart_port.clk))
return -ENODEV;
duart_port.suspended = 0;
duart_port.port.dev = &pdev->dev;
duart_port.port.uartclk = clk_get_rate(duart_port.clk);
uart_add_one_port(&duart_drv, &duart_port.port);
return 0;
}
static int __devexit duart_remove(struct platform_device *pdev)
{
clk_put(duart_port.clk);
uart_remove_one_port(&duart_drv, &duart_port.port);
return 0;
}
static struct platform_driver duart_driver = {
.probe = duart_probe,
.remove = __devexit_p(duart_remove),
.driver = {
.name = "mxs-duart",
.owner = THIS_MODULE,
},
};
static int __init duart_init(void)
{
int ret;
ret = uart_register_driver(&duart_drv);
if (ret)
return ret;
ret = platform_driver_register(&duart_driver);
if (ret)
uart_unregister_driver(&duart_drv);
return ret;
}
static void __exit duart_exit(void)
{
platform_driver_unregister(&duart_driver);
uart_unregister_driver(&duart_drv);
}
module_init(duart_init);
module_exit(duart_exit);
module_param(force_cd, int, 0644);
MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd/Freescale Inc");
MODULE_DESCRIPTION("i.MXS debug uart");
MODULE_LICENSE("GPL");

301
drivers/serial/regs-duart.h Normal file
View File

@@ -0,0 +1,301 @@
/*
* Freescale UARTDBG Register Definitions
*
* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This file is created by xml file. Don't Edit it.
*
* Xml Revision: 1.21
* Template revision: 26195
*/
#ifndef __ARCH_ARM___UARTDBG_H
#define __ARCH_ARM___UARTDBG_H
#define HW_UARTDBGDR (0x00000000)
#define BP_UARTDBGDR_UNAVAILABLE 16
#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGDR_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
#define BP_UARTDBGDR_RESERVED 12
#define BM_UARTDBGDR_RESERVED 0x0000F000
#define BF_UARTDBGDR_RESERVED(v) \
(((v) << 12) & BM_UARTDBGDR_RESERVED)
#define BM_UARTDBGDR_OE 0x00000800
#define BM_UARTDBGDR_BE 0x00000400
#define BM_UARTDBGDR_PE 0x00000200
#define BM_UARTDBGDR_FE 0x00000100
#define BP_UARTDBGDR_DATA 0
#define BM_UARTDBGDR_DATA 0x000000FF
#define BF_UARTDBGDR_DATA(v) \
(((v) << 0) & BM_UARTDBGDR_DATA)
#define HW_UARTDBGRSR_ECR (0x00000004)
#define BP_UARTDBGRSR_ECR_UNAVAILABLE 8
#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
(((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
#define BP_UARTDBGRSR_ECR_EC 4
#define BM_UARTDBGRSR_ECR_EC 0x000000F0
#define BF_UARTDBGRSR_ECR_EC(v) \
(((v) << 4) & BM_UARTDBGRSR_ECR_EC)
#define BM_UARTDBGRSR_ECR_OE 0x00000008
#define BM_UARTDBGRSR_ECR_BE 0x00000004
#define BM_UARTDBGRSR_ECR_PE 0x00000002
#define BM_UARTDBGRSR_ECR_FE 0x00000001
#define HW_UARTDBGFR (0x00000018)
#define BP_UARTDBGFR_UNAVAILABLE 16
#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGFR_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
#define BP_UARTDBGFR_RESERVED 9
#define BM_UARTDBGFR_RESERVED 0x0000FE00
#define BF_UARTDBGFR_RESERVED(v) \
(((v) << 9) & BM_UARTDBGFR_RESERVED)
#define BM_UARTDBGFR_RI 0x00000100
#define BM_UARTDBGFR_TXFE 0x00000080
#define BM_UARTDBGFR_RXFF 0x00000040
#define BM_UARTDBGFR_TXFF 0x00000020
#define BM_UARTDBGFR_RXFE 0x00000010
#define BM_UARTDBGFR_BUSY 0x00000008
#define BM_UARTDBGFR_DCD 0x00000004
#define BM_UARTDBGFR_DSR 0x00000002
#define BM_UARTDBGFR_CTS 0x00000001
#define HW_UARTDBGILPR (0x00000020)
#define BP_UARTDBGILPR_UNAVAILABLE 8
#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
#define BF_UARTDBGILPR_UNAVAILABLE(v) \
(((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
#define BP_UARTDBGILPR_ILPDVSR 0
#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
#define BF_UARTDBGILPR_ILPDVSR(v) \
(((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
#define HW_UARTDBGIBRD (0x00000024)
#define BP_UARTDBGIBRD_UNAVAILABLE 16
#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
#define BP_UARTDBGIBRD_BAUD_DIVINT 0
#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
#define BF_UARTDBGIBRD_BAUD_DIVINT(v) \
(((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
#define HW_UARTDBGFBRD (0x00000028)
#define BP_UARTDBGFBRD_UNAVAILABLE 8
#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
(((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
#define BP_UARTDBGFBRD_RESERVED 6
#define BM_UARTDBGFBRD_RESERVED 0x000000C0
#define BF_UARTDBGFBRD_RESERVED(v) \
(((v) << 6) & BM_UARTDBGFBRD_RESERVED)
#define BP_UARTDBGFBRD_BAUD_DIVFRAC 0
#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v) \
(((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
#define HW_UARTDBGLCR_H (0x0000002c)
#define BP_UARTDBGLCR_H_UNAVAILABLE 16
#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
#define BP_UARTDBGLCR_H_RESERVED 8
#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
#define BF_UARTDBGLCR_H_RESERVED(v) \
(((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
#define BM_UARTDBGLCR_H_SPS 0x00000080
#define BP_UARTDBGLCR_H_WLEN 5
#define BM_UARTDBGLCR_H_WLEN 0x00000060
#define BF_UARTDBGLCR_H_WLEN(v) \
(((v) << 5) & BM_UARTDBGLCR_H_WLEN)
#define BM_UARTDBGLCR_H_FEN 0x00000010
#define BM_UARTDBGLCR_H_STP2 0x00000008
#define BM_UARTDBGLCR_H_EPS 0x00000004
#define BM_UARTDBGLCR_H_PEN 0x00000002
#define BM_UARTDBGLCR_H_BRK 0x00000001
#define HW_UARTDBGCR (0x00000030)
#define BP_UARTDBGCR_UNAVAILABLE 16
#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGCR_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
#define BM_UARTDBGCR_CTSEN 0x00008000
#define BM_UARTDBGCR_RTSEN 0x00004000
#define BM_UARTDBGCR_OUT2 0x00002000
#define BM_UARTDBGCR_OUT1 0x00001000
#define BM_UARTDBGCR_RTS 0x00000800
#define BM_UARTDBGCR_DTR 0x00000400
#define BM_UARTDBGCR_RXE 0x00000200
#define BM_UARTDBGCR_TXE 0x00000100
#define BM_UARTDBGCR_LBE 0x00000080
#define BP_UARTDBGCR_RESERVED 3
#define BM_UARTDBGCR_RESERVED 0x00000078
#define BF_UARTDBGCR_RESERVED(v) \
(((v) << 3) & BM_UARTDBGCR_RESERVED)
#define BM_UARTDBGCR_SIRLP 0x00000004
#define BM_UARTDBGCR_SIREN 0x00000002
#define BM_UARTDBGCR_UARTEN 0x00000001
#define HW_UARTDBGIFLS (0x00000034)
#define BP_UARTDBGIFLS_UNAVAILABLE 16
#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
#define BP_UARTDBGIFLS_RESERVED 6
#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
#define BF_UARTDBGIFLS_RESERVED(v) \
(((v) << 6) & BM_UARTDBGIFLS_RESERVED)
#define BP_UARTDBGIFLS_RXIFLSEL 3
#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
#define BF_UARTDBGIFLS_RXIFLSEL(v) \
(((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
#define BV_UARTDBGIFLS_RXIFLSEL__ONE_EIGHT 0x0
#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER 0x1
#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF 0x2
#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS 0x4
#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5 0x5
#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6 0x6
#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7 0x7
#define BP_UARTDBGIFLS_TXIFLSEL 0
#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
#define BF_UARTDBGIFLS_TXIFLSEL(v) \
(((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
#define BV_UARTDBGIFLS_TXIFLSEL__ONE_EIGHT 0x0
#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER 0x1
#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF 0x2
#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS 0x4
#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5 0x5
#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6 0x6
#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7 0x7
#define HW_UARTDBGIMSC (0x00000038)
#define BP_UARTDBGIMSC_UNAVAILABLE 16
#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
#define BP_UARTDBGIMSC_RESERVED 11
#define BM_UARTDBGIMSC_RESERVED 0x0000F800
#define BF_UARTDBGIMSC_RESERVED(v) \
(((v) << 11) & BM_UARTDBGIMSC_RESERVED)
#define BM_UARTDBGIMSC_OEIM 0x00000400
#define BM_UARTDBGIMSC_BEIM 0x00000200
#define BM_UARTDBGIMSC_PEIM 0x00000100
#define BM_UARTDBGIMSC_FEIM 0x00000080
#define BM_UARTDBGIMSC_RTIM 0x00000040
#define BM_UARTDBGIMSC_TXIM 0x00000020
#define BM_UARTDBGIMSC_RXIM 0x00000010
#define BM_UARTDBGIMSC_DSRMIM 0x00000008
#define BM_UARTDBGIMSC_DCDMIM 0x00000004
#define BM_UARTDBGIMSC_CTSMIM 0x00000002
#define BM_UARTDBGIMSC_RIMIM 0x00000001
#define HW_UARTDBGRIS (0x0000003c)
#define BP_UARTDBGRIS_UNAVAILABLE 16
#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGRIS_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
#define BP_UARTDBGRIS_RESERVED 11
#define BM_UARTDBGRIS_RESERVED 0x0000F800
#define BF_UARTDBGRIS_RESERVED(v) \
(((v) << 11) & BM_UARTDBGRIS_RESERVED)
#define BM_UARTDBGRIS_OERIS 0x00000400
#define BM_UARTDBGRIS_BERIS 0x00000200
#define BM_UARTDBGRIS_PERIS 0x00000100
#define BM_UARTDBGRIS_FERIS 0x00000080
#define BM_UARTDBGRIS_RTRIS 0x00000040
#define BM_UARTDBGRIS_TXRIS 0x00000020
#define BM_UARTDBGRIS_RXRIS 0x00000010
#define BM_UARTDBGRIS_DSRRMIS 0x00000008
#define BM_UARTDBGRIS_DCDRMIS 0x00000004
#define BM_UARTDBGRIS_CTSRMIS 0x00000002
#define BM_UARTDBGRIS_RIRMIS 0x00000001
#define HW_UARTDBGMIS (0x00000040)
#define BP_UARTDBGMIS_UNAVAILABLE 16
#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGMIS_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
#define BP_UARTDBGMIS_RESERVED 11
#define BM_UARTDBGMIS_RESERVED 0x0000F800
#define BF_UARTDBGMIS_RESERVED(v) \
(((v) << 11) & BM_UARTDBGMIS_RESERVED)
#define BM_UARTDBGMIS_OEMIS 0x00000400
#define BM_UARTDBGMIS_BEMIS 0x00000200
#define BM_UARTDBGMIS_PEMIS 0x00000100
#define BM_UARTDBGMIS_FEMIS 0x00000080
#define BM_UARTDBGMIS_RTMIS 0x00000040
#define BM_UARTDBGMIS_TXMIS 0x00000020
#define BM_UARTDBGMIS_RXMIS 0x00000010
#define BM_UARTDBGMIS_DSRMMIS 0x00000008
#define BM_UARTDBGMIS_DCDMMIS 0x00000004
#define BM_UARTDBGMIS_CTSMMIS 0x00000002
#define BM_UARTDBGMIS_RIMMIS 0x00000001
#define HW_UARTDBGICR (0x00000044)
#define BP_UARTDBGICR_UNAVAILABLE 16
#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGICR_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
#define BP_UARTDBGICR_RESERVED 11
#define BM_UARTDBGICR_RESERVED 0x0000F800
#define BF_UARTDBGICR_RESERVED(v) \
(((v) << 11) & BM_UARTDBGICR_RESERVED)
#define BM_UARTDBGICR_OEIC 0x00000400
#define BM_UARTDBGICR_BEIC 0x00000200
#define BM_UARTDBGICR_PEIC 0x00000100
#define BM_UARTDBGICR_FEIC 0x00000080
#define BM_UARTDBGICR_RTIC 0x00000040
#define BM_UARTDBGICR_TXIC 0x00000020
#define BM_UARTDBGICR_RXIC 0x00000010
#define BM_UARTDBGICR_DSRMIC 0x00000008
#define BM_UARTDBGICR_DCDMIC 0x00000004
#define BM_UARTDBGICR_CTSMIC 0x00000002
#define BM_UARTDBGICR_RIMIC 0x00000001
#define HW_UARTDBGDMACR (0x00000048)
#define BP_UARTDBGDMACR_UNAVAILABLE 16
#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
(((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
#define BP_UARTDBGDMACR_RESERVED 3
#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
#define BF_UARTDBGDMACR_RESERVED(v) \
(((v) << 3) & BM_UARTDBGDMACR_RESERVED)
#define BM_UARTDBGDMACR_DMAONERR 0x00000004
#define BM_UARTDBGDMACR_TXDMAE 0x00000002
#define BM_UARTDBGDMACR_RXDMAE 0x00000001
#endif /* __ARCH_ARM___UARTDBG_H */