None of the driver make the difference between STDOUT and STDERR. So we just need to check if putc or getc are filled in the console_device save 32 bytes on versatilepb Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
198 lines
6.4 KiB
C
198 lines
6.4 KiB
C
/*
|
|
* (c) 2009 Sascha Hauer <s.hauer@pengutronix.de>
|
|
* 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <driver.h>
|
|
#include <init.h>
|
|
#include <malloc.h>
|
|
|
|
#include <mach/clock.h>
|
|
#include <asm/io.h>
|
|
|
|
#define RBR 0x00 /* Receive Buffer Register (read only) */
|
|
#define THR 0x00 /* Transmit Holding Register (write only) */
|
|
#define IER 0x04 /* Interrupt Enable Register (read/write) */
|
|
#define IIR 0x08 /* Interrupt ID Register (read only) */
|
|
#define FCR 0x08 /* FIFO Control Register (write only) */
|
|
#define LCR 0x0c /* Line Control Register (read/write) */
|
|
#define MCR 0x10 /* Modem Control Register (read/write) */
|
|
#define LSR 0x14 /* Line Status Register (read only) */
|
|
#define MSR 0x18 /* Modem Status Register (read only) */
|
|
#define SPR 0x1c /* Scratch Pad Register (read/write) */
|
|
#define ISR 0x20 /* Infrared Selection Register (read/write) */
|
|
#define DLL 0x00 /* Divisor Latch Low Register (DLAB = 1) (read/write) */
|
|
#define DLH 0x04 /* Divisor Latch High Register (DLAB = 1) (read/write) */
|
|
|
|
#define IER_DMAE (1 << 7) /* DMA Requests Enable */
|
|
#define IER_UUE (1 << 6) /* UART Unit Enable */
|
|
#define IER_NRZE (1 << 5) /* NRZ coding Enable */
|
|
#define IER_RTIOE (1 << 4) /* Receiver Time Out Interrupt Enable */
|
|
#define IER_MIE (1 << 3) /* Modem Interrupt Enable */
|
|
#define IER_RLSE (1 << 2) /* Receiver Line Status Interrupt Enable */
|
|
#define IER_TIE (1 << 1) /* Transmit Data request Interrupt Enable */
|
|
#define IER_RAVIE (1 << 0) /* Receiver Data Available Interrupt Enable */
|
|
|
|
#define IIR_FIFOES1 (1 << 7) /* FIFO Mode Enable Status */
|
|
#define IIR_FIFOES0 (1 << 6) /* FIFO Mode Enable Status */
|
|
#define IIR_TOD (1 << 3) /* Time Out Detected */
|
|
#define IIR_IID2 (1 << 2) /* Interrupt Source Encoded */
|
|
#define IIR_IID1 (1 << 1) /* Interrupt Source Encoded */
|
|
#define IIR_IP (1 << 0) /* Interrupt Pending (active low) */
|
|
|
|
#define FCR_ITL2 (1 << 7) /* Interrupt Trigger Level */
|
|
#define FCR_ITL1 (1 << 6) /* Interrupt Trigger Level */
|
|
#define FCR_RESETTF (1 << 2) /* Reset Transmitter FIFO */
|
|
#define FCR_RESETRF (1 << 1) /* Reset Receiver FIFO */
|
|
#define FCR_TRFIFOE (1 << 0) /* Transmit and Receive FIFO Enable */
|
|
#define FCR_ITL_1 (0)
|
|
#define FCR_ITL_8 (FCR_ITL1)
|
|
#define FCR_ITL_16 (FCR_ITL2)
|
|
#define FCR_ITL_32 (FCR_ITL2 | F CR_ITL1)
|
|
|
|
#define LCR_DLAB (1 << 7) /* Divisor Latch Access Bit */
|
|
#define LCR_SB (1 << 6) /* Set Break */
|
|
#define LCR_STKYP (1 << 5) /* Sticky Parity */
|
|
#define LCR_EPS (1 << 4) /* Even Parity Select */
|
|
#define LCR_PEN (1 << 3) /* Parity Enable */
|
|
#define LCR_STB (1 << 2) /* Stop Bit */
|
|
#define LCR_WLS1 (1 << 1) /* Word Length Select */
|
|
#define LCR_WLS0 (1 << 0) /* Word Length Select */
|
|
#define LCR_WLEN8 (LCR_WLS1 | LCR_WLS0)
|
|
/* Wordlength: 8 bits */
|
|
|
|
#define LSR_FIFOE (1 << 7) /* FIFO Error Status */
|
|
#define LSR_TEMT (1 << 6) /* Transmitter Empty */
|
|
#define LSR_TDRQ (1 << 5) /* Transmit Data Request */
|
|
#define LSR_BI (1 << 4) /* Break Interrupt */
|
|
#define LSR_FE (1 << 3) /* Framing Error */
|
|
#define LSR_PE (1 << 2) /* Parity Error */
|
|
#define LSR_OE (1 << 1) /* Overrun Error */
|
|
#define LSR_DR (1 << 0) /* Data Ready */
|
|
|
|
#define MCR_LOOP (1 << 4) /* */
|
|
#define MCR_OUT2 (1 << 3) /* force MSR_DCD in loopback mode */
|
|
#define MCR_OUT1 (1 << 2) /* force MSR_RI in loopback mode */
|
|
#define MCR_RTS (1 << 1) /* Request to Send */
|
|
#define MCR_DTR (1 << 0) /* Data Terminal Ready */
|
|
|
|
#define MSR_DCD (1 << 7) /* Data Carrier Detect */
|
|
#define MSR_RI (1 << 6) /* Ring Indicator */
|
|
#define MSR_DSR (1 << 5) /* Data Set Ready */
|
|
#define MSR_CTS (1 << 4) /* Clear To Send */
|
|
#define MSR_DDCD (1 << 3) /* Delta Data Carrier Detect */
|
|
#define MSR_TERI (1 << 2) /* Trailing Edge Ring Indicator */
|
|
#define MSR_DDSR (1 << 1) /* Delta Data Set Ready */
|
|
#define MSR_DCTS (1 << 0) /* Delta Clear To Send */
|
|
|
|
struct pxa_serial_priv {
|
|
void __iomem *regs;
|
|
struct console_device cdev;
|
|
};
|
|
|
|
static void __iomem *to_regs(struct console_device *cdev)
|
|
{
|
|
struct pxa_serial_priv *priv =
|
|
container_of(cdev, struct pxa_serial_priv, cdev);
|
|
return priv->regs;
|
|
}
|
|
|
|
static void pxa_serial_putc(struct console_device *cdev, char c)
|
|
{
|
|
while (!(readl(to_regs(cdev) + LSR) & LSR_TEMT));
|
|
|
|
writel(c, to_regs(cdev) + THR);
|
|
}
|
|
|
|
static int pxa_serial_tstc(struct console_device *cdev)
|
|
{
|
|
return readl(to_regs(cdev) + LSR) & LSR_DR;
|
|
}
|
|
|
|
static int pxa_serial_getc(struct console_device *cdev)
|
|
{
|
|
while (!(readl(to_regs(cdev) + LSR) & LSR_DR));
|
|
|
|
return readl(to_regs(cdev) + RBR) & 0xff;
|
|
}
|
|
|
|
static void pxa_serial_flush(struct console_device *cdev)
|
|
{
|
|
}
|
|
|
|
static int pxa_serial_setbaudrate(struct console_device *cdev, int baudrate)
|
|
{
|
|
unsigned char cval = LCR_WLEN8; /* 8N1 */
|
|
unsigned int quot;
|
|
|
|
/* enable uart */
|
|
writel(IER_UUE, to_regs(cdev) + IER);
|
|
|
|
/* write divisor */
|
|
quot = (pxa_get_uartclk() + (8 * baudrate)) / (16 * baudrate);
|
|
|
|
writel(cval | LCR_DLAB, to_regs(cdev) + LCR); /* set DLAB */
|
|
writel(quot & 0xff, to_regs(cdev) + DLL);
|
|
/*
|
|
* work around Errata #75 according to Intel(R) PXA27x
|
|
* Processor Family Specification Update (Nov 2005)
|
|
*/
|
|
readl(to_regs(cdev) + DLL);
|
|
writel(quot >> 8, to_regs(cdev) + DLH);
|
|
writel(cval, to_regs(cdev) + LCR); /* reset DLAB */
|
|
|
|
/* enable fifos */
|
|
writel(FCR_TRFIFOE, to_regs(cdev) + FCR);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pxa_serial_probe(struct device_d *dev)
|
|
{
|
|
struct console_device *cdev;
|
|
struct pxa_serial_priv *priv;
|
|
|
|
priv = xzalloc(sizeof(*priv));
|
|
cdev = &priv->cdev;
|
|
priv->regs = dev_request_mem_region(dev, 0);
|
|
|
|
dev->priv = priv;
|
|
cdev->dev = dev;
|
|
cdev->tstc = pxa_serial_tstc;
|
|
cdev->putc = pxa_serial_putc;
|
|
cdev->getc = pxa_serial_getc;
|
|
cdev->flush = pxa_serial_flush;
|
|
cdev->setbrg = pxa_serial_setbaudrate;
|
|
|
|
console_register(cdev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void pxa_serial_remove(struct device_d *dev)
|
|
{
|
|
struct pxa_serial_priv *priv = dev->priv;
|
|
|
|
console_unregister(&priv->cdev);
|
|
free(priv);
|
|
}
|
|
|
|
static struct driver_d pxa_serial_driver = {
|
|
.name = "pxa_serial",
|
|
.probe = pxa_serial_probe,
|
|
.remove = pxa_serial_remove,
|
|
};
|
|
console_platform_driver(pxa_serial_driver);
|