You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.5 KiB
239 lines
6.5 KiB
From 48ab619dd6e308c57dac3e5d022a3099806bf79e Mon Sep 17 00:00:00 2001
|
|
From: Stephen Boyd <sboyd@codeaurora.org>
|
|
Date: Tue, 14 Jan 2014 12:34:55 -0800
|
|
Subject: [PATCH 086/182] msm_serial: Add support for poll_{get,put}_char()
|
|
|
|
Implement the polling functionality for the MSM serial driver.
|
|
This allows us to use KGDB on this hardware.
|
|
|
|
Cc: David Brown <davidb@codeaurora.org>
|
|
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
drivers/tty/serial/msm_serial.c | 140 ++++++++++++++++++++++++++++++++++++++-
|
|
drivers/tty/serial/msm_serial.h | 9 +++
|
|
2 files changed, 146 insertions(+), 3 deletions(-)
|
|
|
|
--- 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
|
|
|
|
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 *
|
|
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 *
|
|
}
|
|
}
|
|
|
|
+#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_drive
|
|
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(struc
|
|
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(struc
|
|
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;
|
|
|
|
--- 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
|
|
|