From patchwork Tue Jan 14 20:34:55 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Boyd X-Patchwork-Id: 3487891 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 908F69F2E9 for ; Tue, 14 Jan 2014 20:35:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7F4B720251 for ; Tue, 14 Jan 2014 20:35:40 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5E7892023F for ; Tue, 14 Jan 2014 20:35:39 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W3Ahq-000201-S6; Tue, 14 Jan 2014 20:35:26 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W3Aho-0008Dv-GB; Tue, 14 Jan 2014 20:35:24 +0000 Received: from smtp.codeaurora.org ([198.145.11.231]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W3Ahk-0008DE-O4 for linux-arm-kernel@lists.infradead.org; Tue, 14 Jan 2014 20:35:21 +0000 Received: from smtp.codeaurora.org (localhost [127.0.0.1]) by smtp.codeaurora.org (Postfix) with ESMTP id 64A1F13EF17; Tue, 14 Jan 2014 20:34:59 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 486) id 5756313EFFB; Tue, 14 Jan 2014 20:34:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from sboyd-linux.qualcomm.com (i-global252.qualcomm.com [199.106.103.252]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: sboyd@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 9BFC313EF17; Tue, 14 Jan 2014 20:34:58 +0000 (UTC) From: Stephen Boyd To: Greg Kroah-Hartman Subject: [PATCH] msm_serial: Add support for poll_{get,put}_char() Date: Tue, 14 Jan 2014 12:34:55 -0800 Message-Id: <1389731695-28265-1-git-send-email-sboyd@codeaurora.org> X-Mailer: git-send-email 1.8.5.2.228.g8f9f19c X-Virus-Scanned: ClamAV using ClamSMTP X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140114_153520_933126_29A62592 X-CRM114-Status: GOOD ( 26.72 ) X-Spam-Score: -2.0 (--) Cc: linux-arm-msm@vger.kernel.org, David Brown , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-serial@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Implement the polling functionality for the MSM serial driver. This allows us to use KGDB on this hardware. Cc: David Brown Signed-off-by: Stephen Boyd --- drivers/tty/serial/msm_serial.c | 140 +++++++++++++++++++++++++++++++++++++++- drivers/tty/serial/msm_serial.h | 9 +++ 2 files changed, 146 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b5d779cd3c2b..053b98eb46c8 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -39,6 +39,13 @@ #include "msm_serial.h" +enum { + UARTDM_1P1 = 1, + UARTDM_1P2, + UARTDM_1P3, + UARTDM_1P4, +}; + struct msm_port { struct uart_port uart; char name[16]; @@ -309,6 +316,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port) static void msm_reset(struct uart_port *port) { + struct msm_port *msm_port = UART_TO_MSM(port); + /* reset everything */ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); @@ -316,6 +325,10 @@ static void msm_reset(struct uart_port *port) msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + + /* Disable DM modes */ + if (msm_port->is_uartdm) + msm_write(port, 0, UARTDM_DMEN); } static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -711,6 +724,117 @@ static void msm_power(struct uart_port *port, unsigned int state, } } +#ifdef CONFIG_CONSOLE_POLL +static int msm_poll_init(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Enable single character mode on RX FIFO */ + if (msm_port->is_uartdm >= UARTDM_1P4) + msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); + + return 0; +} + +static int msm_poll_get_char_single(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + + if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + return NO_POLL_CHAR; + else + return msm_read(port, rf_reg) & 0xff; +} + +static int msm_poll_get_char_dm_1p3(struct uart_port *port) +{ + int c; + static u32 slop; + static int count; + unsigned char *sp = (unsigned char *)&slop; + + /* Check if a previous read had more than one char */ + if (count) { + c = sp[sizeof(slop) - count]; + count--; + /* Or if FIFO is empty */ + } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { + /* + * If RX packing buffer has less than a word, force stale to + * push contents into RX FIFO + */ + count = msm_read(port, UARTDM_RXFS); + count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; + if (count) { + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count--; + } else { + c = NO_POLL_CHAR; + } + /* FIFO has a word */ + } else { + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count = sizeof(slop) - 1; + } + + return c; +} + +static int msm_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm == UARTDM_1P3) + c = msm_poll_get_char_dm_1p3(port); + else + c = msm_poll_get_char_single(port); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return c; +} + +static void msm_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm) + reset_dm_count(port, 1); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Write a character */ + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return; +} +#endif + static struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, @@ -729,6 +853,11 @@ static struct uart_ops msm_uart_pops = { .config_port = msm_config_port, .verify_port = msm_verify_port, .pm = msm_power, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = msm_poll_init, + .poll_get_char = msm_poll_get_char, + .poll_put_char = msm_poll_put_char, +#endif }; static struct msm_port msm_uart_ports[] = { @@ -900,7 +1029,10 @@ static struct uart_driver msm_uart_driver = { static atomic_t msm_uart_next_id = ATOMIC_INIT(0); static const struct of_device_id msm_uartdm_table[] = { - { .compatible = "qcom,msm-uartdm" }, + { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, + { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 }, + { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 }, + { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 }, { } }; @@ -909,6 +1041,7 @@ static int __init msm_serial_probe(struct platform_device *pdev) struct msm_port *msm_port; struct resource *resource; struct uart_port *port; + const struct of_device_id *id; int irq; if (pdev->id == -1) @@ -923,8 +1056,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); - if (of_match_device(msm_uartdm_table, &pdev->dev)) - msm_port->is_uartdm = 1; + id = of_match_device(msm_uartdm_table, &pdev->dev); + if (id) + msm_port->is_uartdm = (unsigned long)id->data; else msm_port->is_uartdm = 0; diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 469fda50ac63..1e9b68b6f9eb 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -59,6 +59,7 @@ #define UART_CR_CMD_RESET_RFR (14 << 4) #define UART_CR_CMD_PROTECTION_EN (16 << 4) #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) #define UART_CR_CMD_RESET_TX_READY (3 << 8) #define UART_CR_TX_DISABLE (1 << 3) #define UART_CR_TX_ENABLE (1 << 2) @@ -113,6 +114,14 @@ #define GSBI_PROTOCOL_UART 0x40 #define GSBI_PROTOCOL_IDLE 0x0 +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + #define UARTDM_DMRX 0x34 #define UARTDM_NCF_TX 0x40 #define UARTDM_RX_TOTAL_SNAP 0x38