aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/xilinx_uartps.c
diff options
context:
space:
mode:
authorNava kishore Manne <nava.manne@xilinx.com>2016-09-15 05:15:29 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-09-22 05:46:12 -0400
commit3816b2f886d0918d8a8ae593b2db203ab905a889 (patch)
treeadb9631bf0a8a74e754d90ba058c6d1f45121bc8 /drivers/tty/serial/xilinx_uartps.c
parent54f19b4a679149130f78413c421a5780e90a9d0a (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.c101
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};
182struct 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
179static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) 188static 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 */
737static int cdns_uart_startup(struct uart_port *port) 778static 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)
1328static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, 1377static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
1329 cdns_uart_resume); 1378 cdns_uart_resume);
1330 1379
1380static const struct cdns_platform_data zynqmp_uart_def = {
1381 .quirks = CDNS_UART_RXBS_SUPPORT, };
1382
1383/* Match table for of_platform binding */
1384static 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};
1390MODULE_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 */
1475static const struct of_device_id cdns_uart_of_match[] = {
1476 { .compatible = "xlnx,xuartps", },
1477 { .compatible = "cdns,uart-r1p8", },
1478 {}
1479};
1480MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
1481
1482static struct platform_driver cdns_uart_platform_driver = { 1543static 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,