diff options
author | Nava kishore Manne <nava.manne@xilinx.com> | 2016-09-15 05:15:29 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-09-22 05:46:12 -0400 |
commit | 3816b2f886d0918d8a8ae593b2db203ab905a889 (patch) | |
tree | adb9631bf0a8a74e754d90ba058c6d1f45121bc8 /drivers/tty/serial/xilinx_uartps.c | |
parent | 54f19b4a679149130f78413c421a5780e90a9d0a (diff) |
serial: xuartps: Adds RXBS register support for zynqmp
This patch adds RXBS register access support for zynqmp.
To avoid the corner error conditions it will consider only
RXBS[2:0] bits while checking the error conditions
(Parity,Framing and BRAK).
Signed-off-by: Nava kishore Manne <navam@xilinx.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/xilinx_uartps.c')
-rw-r--r-- | drivers/tty/serial/xilinx_uartps.c | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 11a2b36e14bb..bf06d2c6b96e 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c | |||
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); | |||
57 | #define CDNS_UART_IMR 0x10 /* Interrupt Mask */ | 57 | #define CDNS_UART_IMR 0x10 /* Interrupt Mask */ |
58 | #define CDNS_UART_ISR 0x14 /* Interrupt Status */ | 58 | #define CDNS_UART_ISR 0x14 /* Interrupt Status */ |
59 | #define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */ | 59 | #define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */ |
60 | #define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ | 60 | #define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ |
61 | #define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */ | 61 | #define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */ |
62 | #define CDNS_UART_MODEMCR 0x24 /* Modem Control */ | 62 | #define CDNS_UART_MODEMCR 0x24 /* Modem Control */ |
63 | #define CDNS_UART_MODEMSR 0x28 /* Modem Status */ | 63 | #define CDNS_UART_MODEMSR 0x28 /* Modem Status */ |
@@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); | |||
68 | #define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ | 68 | #define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ |
69 | #define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ | 69 | #define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ |
70 | #define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ | 70 | #define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ |
71 | #define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */ | ||
71 | 72 | ||
72 | /* Control Register Bit Definitions */ | 73 | /* Control Register Bit Definitions */ |
73 | #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ | 74 | #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ |
@@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); | |||
79 | #define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ | 80 | #define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ |
80 | #define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ | 81 | #define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ |
81 | #define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ | 82 | #define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ |
83 | #define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */ | ||
84 | #define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */ | ||
85 | #define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */ | ||
82 | 86 | ||
83 | /* | 87 | /* |
84 | * Mode Register: | 88 | * Mode Register: |
@@ -131,8 +135,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); | |||
131 | CDNS_UART_IXR_TOUT) | 135 | CDNS_UART_IXR_TOUT) |
132 | 136 | ||
133 | /* Goes in read_status_mask for break detection as the HW doesn't do it*/ | 137 | /* Goes in read_status_mask for break detection as the HW doesn't do it*/ |
134 | #define CDNS_UART_IXR_BRK 0x80000000 | 138 | #define CDNS_UART_IXR_BRK 0x00002000 |
135 | 139 | ||
140 | #define CDNS_UART_RXBS_SUPPORT BIT(1) | ||
136 | /* | 141 | /* |
137 | * Modem Control register: | 142 | * Modem Control register: |
138 | * The read/write Modem Control register controls the interface with the modem | 143 | * The read/write Modem Control register controls the interface with the modem |
@@ -172,18 +177,29 @@ struct cdns_uart { | |||
172 | struct clk *pclk; | 177 | struct clk *pclk; |
173 | unsigned int baud; | 178 | unsigned int baud; |
174 | struct notifier_block clk_rate_change_nb; | 179 | struct notifier_block clk_rate_change_nb; |
180 | u32 quirks; | ||
181 | }; | ||
182 | struct cdns_platform_data { | ||
183 | u32 quirks; | ||
175 | }; | 184 | }; |
176 | #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ | 185 | #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ |
177 | clk_rate_change_nb); | 186 | clk_rate_change_nb); |
178 | 187 | ||
179 | static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) | 188 | static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) |
180 | { | 189 | { |
190 | struct cdns_uart *cdns_uart = port->private_data; | ||
191 | bool is_rxbs_support; | ||
192 | unsigned int rxbs_status = 0; | ||
193 | unsigned int status_mask; | ||
194 | |||
195 | is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; | ||
196 | |||
181 | /* | 197 | /* |
182 | * There is no hardware break detection, so we interpret framing | 198 | * There is no hardware break detection, so we interpret framing |
183 | * error with all-zeros data as a break sequence. Most of the time, | 199 | * error with all-zeros data as a break sequence. Most of the time, |
184 | * there's another non-zero byte at the end of the sequence. | 200 | * there's another non-zero byte at the end of the sequence. |
185 | */ | 201 | */ |
186 | if (isrstatus & CDNS_UART_IXR_FRAMING) { | 202 | if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) { |
187 | while (!(readl(port->membase + CDNS_UART_SR) & | 203 | while (!(readl(port->membase + CDNS_UART_SR) & |
188 | CDNS_UART_SR_RXEMPTY)) { | 204 | CDNS_UART_SR_RXEMPTY)) { |
189 | if (!readl(port->membase + CDNS_UART_FIFO)) { | 205 | if (!readl(port->membase + CDNS_UART_FIFO)) { |
@@ -200,6 +216,8 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) | |||
200 | 216 | ||
201 | isrstatus &= port->read_status_mask; | 217 | isrstatus &= port->read_status_mask; |
202 | isrstatus &= ~port->ignore_status_mask; | 218 | isrstatus &= ~port->ignore_status_mask; |
219 | status_mask = port->read_status_mask; | ||
220 | status_mask &= ~port->ignore_status_mask; | ||
203 | 221 | ||
204 | if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG))) | 222 | if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG))) |
205 | return; | 223 | return; |
@@ -208,6 +226,9 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) | |||
208 | u32 data; | 226 | u32 data; |
209 | char status = TTY_NORMAL; | 227 | char status = TTY_NORMAL; |
210 | 228 | ||
229 | if (is_rxbs_support) | ||
230 | rxbs_status = readl(port->membase + CDNS_UART_RXBS); | ||
231 | |||
211 | data = readl(port->membase + CDNS_UART_FIFO); | 232 | data = readl(port->membase + CDNS_UART_FIFO); |
212 | 233 | ||
213 | /* Non-NULL byte after BREAK is garbage (99%) */ | 234 | /* Non-NULL byte after BREAK is garbage (99%) */ |
@@ -217,21 +238,41 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) | |||
217 | if (uart_handle_break(port)) | 238 | if (uart_handle_break(port)) |
218 | continue; | 239 | continue; |
219 | } | 240 | } |
241 | if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) { | ||
242 | port->icount.brk++; | ||
243 | status = TTY_BREAK; | ||
244 | if (uart_handle_break(port)) | ||
245 | continue; | ||
246 | } | ||
220 | 247 | ||
221 | if (uart_handle_sysrq_char(port, data)) | 248 | if (uart_handle_sysrq_char(port, data)) |
222 | continue; | 249 | continue; |
223 | 250 | ||
224 | port->icount.rx++; | 251 | port->icount.rx++; |
225 | 252 | ||
226 | if (isrstatus & CDNS_UART_IXR_PARITY) { | 253 | if (is_rxbs_support) { |
227 | port->icount.parity++; | 254 | if ((rxbs_status & CDNS_UART_RXBS_PARITY) |
228 | status = TTY_PARITY; | 255 | && (status_mask & CDNS_UART_IXR_PARITY)) { |
229 | } else if (isrstatus & CDNS_UART_IXR_FRAMING) { | 256 | port->icount.parity++; |
230 | port->icount.frame++; | 257 | status = TTY_PARITY; |
231 | status = TTY_FRAME; | 258 | } |
232 | } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { | 259 | if ((rxbs_status & CDNS_UART_RXBS_FRAMING) |
233 | port->icount.overrun++; | 260 | && (status_mask & CDNS_UART_IXR_PARITY)) { |
261 | port->icount.frame++; | ||
262 | status = TTY_FRAME; | ||
263 | } | ||
264 | } else { | ||
265 | if (isrstatus & CDNS_UART_IXR_PARITY) { | ||
266 | port->icount.parity++; | ||
267 | status = TTY_PARITY; | ||
268 | } | ||
269 | if (isrstatus & CDNS_UART_IXR_FRAMING) { | ||
270 | port->icount.frame++; | ||
271 | status = TTY_FRAME; | ||
272 | } | ||
234 | } | 273 | } |
274 | if (isrstatus & CDNS_UART_IXR_OVERRUN) | ||
275 | port->icount.overrun++; | ||
235 | 276 | ||
236 | uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, | 277 | uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, |
237 | data, status); | 278 | data, status); |
@@ -736,10 +777,14 @@ static void cdns_uart_set_termios(struct uart_port *port, | |||
736 | */ | 777 | */ |
737 | static int cdns_uart_startup(struct uart_port *port) | 778 | static int cdns_uart_startup(struct uart_port *port) |
738 | { | 779 | { |
780 | struct cdns_uart *cdns_uart = port->private_data; | ||
781 | bool is_brk_support; | ||
739 | int ret; | 782 | int ret; |
740 | unsigned long flags; | 783 | unsigned long flags; |
741 | unsigned int status = 0; | 784 | unsigned int status = 0; |
742 | 785 | ||
786 | is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; | ||
787 | |||
743 | spin_lock_irqsave(&port->lock, flags); | 788 | spin_lock_irqsave(&port->lock, flags); |
744 | 789 | ||
745 | /* Disable the TX and RX */ | 790 | /* Disable the TX and RX */ |
@@ -794,7 +839,11 @@ static int cdns_uart_startup(struct uart_port *port) | |||
794 | } | 839 | } |
795 | 840 | ||
796 | /* Set the Interrupt Registers with desired interrupts */ | 841 | /* Set the Interrupt Registers with desired interrupts */ |
797 | writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER); | 842 | if (is_brk_support) |
843 | writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK, | ||
844 | port->membase + CDNS_UART_IER); | ||
845 | else | ||
846 | writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER); | ||
798 | 847 | ||
799 | return 0; | 848 | return 0; |
800 | } | 849 | } |
@@ -1328,6 +1377,18 @@ static int cdns_uart_resume(struct device *device) | |||
1328 | static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, | 1377 | static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, |
1329 | cdns_uart_resume); | 1378 | cdns_uart_resume); |
1330 | 1379 | ||
1380 | static const struct cdns_platform_data zynqmp_uart_def = { | ||
1381 | .quirks = CDNS_UART_RXBS_SUPPORT, }; | ||
1382 | |||
1383 | /* Match table for of_platform binding */ | ||
1384 | static const struct of_device_id cdns_uart_of_match[] = { | ||
1385 | { .compatible = "xlnx,xuartps", }, | ||
1386 | { .compatible = "cdns,uart-r1p8", }, | ||
1387 | { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def }, | ||
1388 | {} | ||
1389 | }; | ||
1390 | MODULE_DEVICE_TABLE(of, cdns_uart_of_match); | ||
1391 | |||
1331 | /** | 1392 | /** |
1332 | * cdns_uart_probe - Platform driver probe | 1393 | * cdns_uart_probe - Platform driver probe |
1333 | * @pdev: Pointer to the platform device structure | 1394 | * @pdev: Pointer to the platform device structure |
@@ -1340,12 +1401,20 @@ static int cdns_uart_probe(struct platform_device *pdev) | |||
1340 | struct uart_port *port; | 1401 | struct uart_port *port; |
1341 | struct resource *res; | 1402 | struct resource *res; |
1342 | struct cdns_uart *cdns_uart_data; | 1403 | struct cdns_uart *cdns_uart_data; |
1404 | const struct of_device_id *match; | ||
1343 | 1405 | ||
1344 | cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), | 1406 | cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), |
1345 | GFP_KERNEL); | 1407 | GFP_KERNEL); |
1346 | if (!cdns_uart_data) | 1408 | if (!cdns_uart_data) |
1347 | return -ENOMEM; | 1409 | return -ENOMEM; |
1348 | 1410 | ||
1411 | match = of_match_node(cdns_uart_of_match, pdev->dev.of_node); | ||
1412 | if (match && match->data) { | ||
1413 | const struct cdns_platform_data *data = match->data; | ||
1414 | |||
1415 | cdns_uart_data->quirks = data->quirks; | ||
1416 | } | ||
1417 | |||
1349 | cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); | 1418 | cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); |
1350 | if (IS_ERR(cdns_uart_data->pclk)) { | 1419 | if (IS_ERR(cdns_uart_data->pclk)) { |
1351 | cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); | 1420 | cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); |
@@ -1471,14 +1540,6 @@ static int cdns_uart_remove(struct platform_device *pdev) | |||
1471 | return rc; | 1540 | return rc; |
1472 | } | 1541 | } |
1473 | 1542 | ||
1474 | /* Match table for of_platform binding */ | ||
1475 | static const struct of_device_id cdns_uart_of_match[] = { | ||
1476 | { .compatible = "xlnx,xuartps", }, | ||
1477 | { .compatible = "cdns,uart-r1p8", }, | ||
1478 | {} | ||
1479 | }; | ||
1480 | MODULE_DEVICE_TABLE(of, cdns_uart_of_match); | ||
1481 | |||
1482 | static struct platform_driver cdns_uart_platform_driver = { | 1543 | static struct platform_driver cdns_uart_platform_driver = { |
1483 | .probe = cdns_uart_probe, | 1544 | .probe = cdns_uart_probe, |
1484 | .remove = cdns_uart_remove, | 1545 | .remove = cdns_uart_remove, |