aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/amba-pl011.c
diff options
context:
space:
mode:
authorAnton Vorontsov <anton.vorontsov@linaro.org>2012-09-24 17:27:54 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-26 16:51:31 -0400
commitb3564c2cf464e11f8cb4f8d9c124e5e0f5418e3f (patch)
tree7bf784c8c903d940be37d0705ec8bf44f1c13962 /drivers/tty/serial/amba-pl011.c
parentc7f3e7087ab0abb52bb1286010f2c104fd38ca5c (diff)
tty/serial/amba-pl011: Implement poll_init callback
The callback is used to initialize the hardware, nothing else should be done, i.e. we should not request interrupts (but we can and do unmask some of them, as they might be useful for NMI entry). As a side-effect, the patch also fixes a division by zero[1] when booting with kgdboc options specified (e.g. kgdboc=ttyAMA0,115200n8). The issue happens because serial core calls set_termios callback, but the driver doesn't know clock frequency, and thus cannot calculate proper baud rate values. [1] WARNING: at drivers/tty/serial/serial_core.c:400 uart_get_baud_rate+0xe8/0x14c() Modules linked in: [<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c0020ae8>] (warn_slowpath_common+0x4c/0x64) [<c0020ae8>] (warn_slowpath_common+0x4c/0x64) from [<c0020b1c>] (warn_slowpath_null+0x1c/0x24) [<c0020b1c>] (warn_slowpath_null+0x1c/0x24) from [<c0185ed8>] (uart_get_baud_rate+0xe8/0x14c) [<c0185ed8>] (uart_get_baud_rate+0xe8/0x14c) from [<c0187078>] (pl011_set_termios+0x48/0x278) [<c0187078>] (pl011_set_termios+0x48/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114) [<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0) [<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8) [<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168) [<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8) [<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4) [<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8) ---[ end trace 7d41c9186f342c40 ]--- Division by zero in kernel. [<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c014546c>] (Ldiv0+0x8/0x10) [<c014546c>] (Ldiv0+0x8/0x10) from [<c0187098>] (pl011_set_termios+0x68/0x278) [<c0187098>] (pl011_set_termios+0x68/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114) [<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0) [<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8) [<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168) [<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8) [<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4) [<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8) Division by zero in kernel. [<c0018e50>] (unwind_backtrace+0x0/0xf0) from [<c014546c>] (Ldiv0+0x8/0x10) [<c014546c>] (Ldiv0+0x8/0x10) from [<c0183a98>] (uart_update_timeout+0x4c/0x5c) [<c0183a98>] (uart_update_timeout+0x4c/0x5c) from [<c01870f8>] (pl011_set_termios+0xc8/0x278) [<c01870f8>] (pl011_set_termios+0xc8/0x278) from [<c01850b0>] (uart_set_options+0xe8/0x114) [<c01850b0>] (uart_set_options+0xe8/0x114) from [<c0185de4>] (uart_poll_init+0xd4/0xe0) [<c0185de4>] (uart_poll_init+0xd4/0xe0) from [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) [<c016da8c>] (tty_find_polling_driver+0x100/0x17c) from [<c0188538>] (configure_kgdboc+0xc8/0x1b8) [<c0188538>] (configure_kgdboc+0xc8/0x1b8) from [<c00088a4>] (do_one_initcall+0x30/0x168) [<c00088a4>] (do_one_initcall+0x30/0x168) from [<c033784c>] (do_basic_setup+0x94/0xc8) [<c033784c>] (do_basic_setup+0x94/0xc8) from [<c03378e0>] (kernel_init+0x60/0xf4) [<c03378e0>] (kernel_init+0x60/0xf4) from [<c00144a0>] (kernel_thread_exit+0x0/0x8) Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org> Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/amba-pl011.c')
-rw-r--r--drivers/tty/serial/amba-pl011.c44
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 925eb8813a45..ea7aa973ab43 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1309,10 +1309,9 @@ static void pl011_put_poll_char(struct uart_port *port,
1309 1309
1310#endif /* CONFIG_CONSOLE_POLL */ 1310#endif /* CONFIG_CONSOLE_POLL */
1311 1311
1312static int pl011_startup(struct uart_port *port) 1312static int pl011_hwinit(struct uart_port *port)
1313{ 1313{
1314 struct uart_amba_port *uap = (struct uart_amba_port *)port; 1314 struct uart_amba_port *uap = (struct uart_amba_port *)port;
1315 unsigned int cr;
1316 int retval; 1315 int retval;
1317 1316
1318 /* Optionaly enable pins to be muxed in and configured */ 1317 /* Optionaly enable pins to be muxed in and configured */
@@ -1337,6 +1336,37 @@ static int pl011_startup(struct uart_port *port)
1337 UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR); 1336 UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
1338 1337
1339 /* 1338 /*
1339 * Save interrupts enable mask, and enable RX interrupts in case if
1340 * the interrupt is used for NMI entry.
1341 */
1342 uap->im = readw(uap->port.membase + UART011_IMSC);
1343 writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
1344
1345 if (uap->port.dev->platform_data) {
1346 struct amba_pl011_data *plat;
1347
1348 plat = uap->port.dev->platform_data;
1349 if (plat->init)
1350 plat->init();
1351 }
1352 return 0;
1353 out:
1354 return retval;
1355}
1356
1357static int pl011_startup(struct uart_port *port)
1358{
1359 struct uart_amba_port *uap = (struct uart_amba_port *)port;
1360 unsigned int cr;
1361 int retval;
1362
1363 retval = pl011_hwinit(port);
1364 if (retval)
1365 goto clk_dis;
1366
1367 writew(uap->im, uap->port.membase + UART011_IMSC);
1368
1369 /*
1340 * Allocate the IRQ 1370 * Allocate the IRQ
1341 */ 1371 */
1342 retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); 1372 retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
@@ -1395,19 +1425,10 @@ static int pl011_startup(struct uart_port *port)
1395 writew(uap->im, uap->port.membase + UART011_IMSC); 1425 writew(uap->im, uap->port.membase + UART011_IMSC);
1396 spin_unlock_irq(&uap->port.lock); 1426 spin_unlock_irq(&uap->port.lock);
1397 1427
1398 if (uap->port.dev->platform_data) {
1399 struct amba_pl011_data *plat;
1400
1401 plat = uap->port.dev->platform_data;
1402 if (plat->init)
1403 plat->init();
1404 }
1405
1406 return 0; 1428 return 0;
1407 1429
1408 clk_dis: 1430 clk_dis:
1409 clk_disable_unprepare(uap->clk); 1431 clk_disable_unprepare(uap->clk);
1410 out:
1411 return retval; 1432 return retval;
1412} 1433}
1413 1434
@@ -1701,6 +1722,7 @@ static struct uart_ops amba_pl011_pops = {
1701 .config_port = pl011_config_port, 1722 .config_port = pl011_config_port,
1702 .verify_port = pl011_verify_port, 1723 .verify_port = pl011_verify_port,
1703#ifdef CONFIG_CONSOLE_POLL 1724#ifdef CONFIG_CONSOLE_POLL
1725 .poll_init = pl011_hwinit,
1704 .poll_get_char = pl011_get_poll_char, 1726 .poll_get_char = pl011_get_poll_char,
1705 .poll_put_char = pl011_put_poll_char, 1727 .poll_put_char = pl011_put_poll_char,
1706#endif 1728#endif