aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/pch_uart.c
diff options
context:
space:
mode:
authorAlexander Stein <alexander.stein@systec-electronic.com>2011-11-15 18:04:07 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-15 18:50:31 -0500
commite30f867d402d6dcc2d03d8dd5da3863f7c83572a (patch)
treeb2f6486b5beb598878533bc17dfce275086ede51 /drivers/tty/serial/pch_uart.c
parentb82e324b3c46a554595c12b45465d1943a57326c (diff)
drivers/tty/serial/pch_uart.c: add console support
Add console support to pch_uart. To enable append e.g. console=ttyPCH0,115200 to your kernel command line. This is not expected work on CM-iTC boards due to their having a different clock. Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/tty/serial/pch_uart.c')
-rw-r--r--drivers/tty/serial/pch_uart.c160
1 files changed, 159 insertions, 1 deletions
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 21febef926a..b950d059a78 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -25,6 +25,9 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/dmi.h> 27#include <linux/dmi.h>
28#include <linux/console.h>
29#include <linux/nmi.h>
30#include <linux/delay.h>
28 31
29#include <linux/dmaengine.h> 32#include <linux/dmaengine.h>
30#include <linux/pch_dma.h> 33#include <linux/pch_dma.h>
@@ -198,6 +201,10 @@ enum {
198 201
199#define PCI_VENDOR_ID_ROHM 0x10DB 202#define PCI_VENDOR_ID_ROHM 0x10DB
200 203
204#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
205
206#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
207
201struct pch_uart_buffer { 208struct pch_uart_buffer {
202 unsigned char *buf; 209 unsigned char *buf;
203 int size; 210 int size;
@@ -272,6 +279,9 @@ static struct pch_uart_driver_data drv_dat[] = {
272 [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, 279 [pch_ml7223_uart1] = {PCH_UART_2LINE, 1},
273}; 280};
274 281
282#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
283static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
284#endif
275static unsigned int default_baud = 9600; 285static unsigned int default_baud = 9600;
276static const int trigger_level_256[4] = { 1, 64, 128, 224 }; 286static const int trigger_level_256[4] = { 1, 64, 128, 224 };
277static const int trigger_level_64[4] = { 1, 16, 32, 56 }; 287static const int trigger_level_64[4] = { 1, 16, 32, 56 };
@@ -1380,6 +1390,143 @@ static struct uart_ops pch_uart_ops = {
1380 .verify_port = pch_uart_verify_port 1390 .verify_port = pch_uart_verify_port
1381}; 1391};
1382 1392
1393#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
1394
1395/*
1396 * Wait for transmitter & holding register to empty
1397 */
1398static void wait_for_xmitr(struct eg20t_port *up, int bits)
1399{
1400 unsigned int status, tmout = 10000;
1401
1402 /* Wait up to 10ms for the character(s) to be sent. */
1403 for (;;) {
1404 status = ioread8(up->membase + UART_LSR);
1405
1406 if ((status & bits) == bits)
1407 break;
1408 if (--tmout == 0)
1409 break;
1410 udelay(1);
1411 }
1412
1413 /* Wait up to 1s for flow control if necessary */
1414 if (up->port.flags & UPF_CONS_FLOW) {
1415 unsigned int tmout;
1416 for (tmout = 1000000; tmout; tmout--) {
1417 unsigned int msr = ioread8(up->membase + UART_MSR);
1418 if (msr & UART_MSR_CTS)
1419 break;
1420 udelay(1);
1421 touch_nmi_watchdog();
1422 }
1423 }
1424}
1425
1426static void pch_console_putchar(struct uart_port *port, int ch)
1427{
1428 struct eg20t_port *priv =
1429 container_of(port, struct eg20t_port, port);
1430
1431 wait_for_xmitr(priv, UART_LSR_THRE);
1432 iowrite8(ch, priv->membase + PCH_UART_THR);
1433}
1434
1435/*
1436 * Print a string to the serial port trying not to disturb
1437 * any possible real use of the port...
1438 *
1439 * The console_lock must be held when we get here.
1440 */
1441static void
1442pch_console_write(struct console *co, const char *s, unsigned int count)
1443{
1444 struct eg20t_port *priv;
1445
1446 unsigned long flags;
1447 u8 ier;
1448 int locked = 1;
1449
1450 priv = pch_uart_ports[co->index];
1451
1452 touch_nmi_watchdog();
1453
1454 local_irq_save(flags);
1455 if (priv->port.sysrq) {
1456 /* serial8250_handle_port() already took the lock */
1457 locked = 0;
1458 } else if (oops_in_progress) {
1459 locked = spin_trylock(&priv->port.lock);
1460 } else
1461 spin_lock(&priv->port.lock);
1462
1463 /*
1464 * First save the IER then disable the interrupts
1465 */
1466 ier = ioread8(priv->membase + UART_IER);
1467
1468 pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
1469
1470 uart_console_write(&priv->port, s, count, pch_console_putchar);
1471
1472 /*
1473 * Finally, wait for transmitter to become empty
1474 * and restore the IER
1475 */
1476 wait_for_xmitr(priv, BOTH_EMPTY);
1477 iowrite8(ier, priv->membase + UART_IER);
1478
1479 if (locked)
1480 spin_unlock(&priv->port.lock);
1481 local_irq_restore(flags);
1482}
1483
1484static int __init pch_console_setup(struct console *co, char *options)
1485{
1486 struct uart_port *port;
1487 int baud = 9600;
1488 int bits = 8;
1489 int parity = 'n';
1490 int flow = 'n';
1491
1492 /*
1493 * Check whether an invalid uart number has been specified, and
1494 * if so, search for the first available port that does have
1495 * console support.
1496 */
1497 if (co->index >= PCH_UART_NR)
1498 co->index = 0;
1499 port = &pch_uart_ports[co->index]->port;
1500
1501 if (!port || (!port->iobase && !port->membase))
1502 return -ENODEV;
1503
1504 /* setup uartclock */
1505 port->uartclk = DEFAULT_BAUD_RATE;
1506
1507 if (options)
1508 uart_parse_options(options, &baud, &parity, &bits, &flow);
1509
1510 return uart_set_options(port, co, baud, parity, bits, flow);
1511}
1512
1513static struct uart_driver pch_uart_driver;
1514
1515static struct console pch_console = {
1516 .name = PCH_UART_DRIVER_DEVICE,
1517 .write = pch_console_write,
1518 .device = uart_console_device,
1519 .setup = pch_console_setup,
1520 .flags = CON_PRINTBUFFER | CON_ANYTIME,
1521 .index = -1,
1522 .data = &pch_uart_driver,
1523};
1524
1525#define PCH_CONSOLE (&pch_console)
1526#else
1527#define PCH_CONSOLE NULL
1528#endif
1529
1383static struct uart_driver pch_uart_driver = { 1530static struct uart_driver pch_uart_driver = {
1384 .owner = THIS_MODULE, 1531 .owner = THIS_MODULE,
1385 .driver_name = KBUILD_MODNAME, 1532 .driver_name = KBUILD_MODNAME,
@@ -1387,6 +1534,7 @@ static struct uart_driver pch_uart_driver = {
1387 .major = 0, 1534 .major = 0,
1388 .minor = 0, 1535 .minor = 0,
1389 .nr = PCH_UART_NR, 1536 .nr = PCH_UART_NR,
1537 .cons = PCH_CONSOLE,
1390}; 1538};
1391 1539
1392static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, 1540static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
@@ -1413,7 +1561,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
1413 if (!rxbuf) 1561 if (!rxbuf)
1414 goto init_port_free_txbuf; 1562 goto init_port_free_txbuf;
1415 1563
1416 base_baud = 1843200; /* 1.8432MHz */ 1564 base_baud = DEFAULT_BAUD_RATE;
1417 1565
1418 /* quirk for CM-iTC board */ 1566 /* quirk for CM-iTC board */
1419 board_name = dmi_get_system_info(DMI_BOARD_NAME); 1567 board_name = dmi_get_system_info(DMI_BOARD_NAME);
@@ -1463,6 +1611,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
1463 pci_set_drvdata(pdev, priv); 1611 pci_set_drvdata(pdev, priv);
1464 pch_uart_hal_request(pdev, fifosize, base_baud); 1612 pch_uart_hal_request(pdev, fifosize, base_baud);
1465 1613
1614#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
1615 pch_uart_ports[board->line_no] = priv;
1616#endif
1466 ret = uart_add_one_port(&pch_uart_driver, &priv->port); 1617 ret = uart_add_one_port(&pch_uart_driver, &priv->port);
1467 if (ret < 0) 1618 if (ret < 0)
1468 goto init_port_hal_free; 1619 goto init_port_hal_free;
@@ -1470,6 +1621,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
1470 return priv; 1621 return priv;
1471 1622
1472init_port_hal_free: 1623init_port_hal_free:
1624#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
1625 pch_uart_ports[board->line_no] = NULL;
1626#endif
1473 free_page((unsigned long)rxbuf); 1627 free_page((unsigned long)rxbuf);
1474init_port_free_txbuf: 1628init_port_free_txbuf:
1475 kfree(priv); 1629 kfree(priv);
@@ -1492,6 +1646,10 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
1492 priv = (struct eg20t_port *)pci_get_drvdata(pdev); 1646 priv = (struct eg20t_port *)pci_get_drvdata(pdev);
1493 1647
1494 pci_disable_msi(pdev); 1648 pci_disable_msi(pdev);
1649
1650#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
1651 pch_uart_ports[priv->port.line] = NULL;
1652#endif
1495 pch_uart_exit_port(priv); 1653 pch_uart_exit_port(priv);
1496 pci_disable_device(pdev); 1654 pci_disable_device(pdev);
1497 kfree(priv); 1655 kfree(priv);