162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker.
462306a36Sopenharmony_ci * Copyright 2020 NXP
562306a36Sopenharmony_ci * Copyright 2020 Puresoftware Ltd.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This isn't a full driver; it just provides an alternate IRQ
862306a36Sopenharmony_ci * handler to deal with an errata and provide ACPI wrapper.
962306a36Sopenharmony_ci * Everything else is just using the bog standard 8250 support.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * We follow code flow of serial8250_default_handle_irq() but add
1262306a36Sopenharmony_ci * a check for a break and insert a dummy read on the Rx for the
1362306a36Sopenharmony_ci * immediately following IRQ event.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * We re-use the already existing "bug handling" lsr_saved_flags
1662306a36Sopenharmony_ci * field to carry the "what we just did" information from the one
1762306a36Sopenharmony_ci * IRQ event to the next one.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/acpi.h>
2162306a36Sopenharmony_ci#include <linux/serial_reg.h>
2262306a36Sopenharmony_ci#include <linux/serial_8250.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "8250.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint fsl8250_handle_irq(struct uart_port *port)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	unsigned long flags;
2962306a36Sopenharmony_ci	u16 lsr, orig_lsr;
3062306a36Sopenharmony_ci	unsigned int iir;
3162306a36Sopenharmony_ci	struct uart_8250_port *up = up_to_u8250p(port);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	spin_lock_irqsave(&up->port.lock, flags);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	iir = port->serial_in(port, UART_IIR);
3662306a36Sopenharmony_ci	if (iir & UART_IIR_NO_INT) {
3762306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->port.lock, flags);
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/*
4262306a36Sopenharmony_ci	 * For a single break the hardware reports LSR.BI for each character
4362306a36Sopenharmony_ci	 * time. This is described in the MPC8313E chip errata as "General17".
4462306a36Sopenharmony_ci	 * A typical break has a duration of 0.3s, with a 115200n8 configuration
4562306a36Sopenharmony_ci	 * that (theoretically) corresponds to ~3500 interrupts in these 0.3s.
4662306a36Sopenharmony_ci	 * In practise it's less (around 500) because of hardware
4762306a36Sopenharmony_ci	 * and software latencies. The workaround recommended by the vendor is
4862306a36Sopenharmony_ci	 * to read the RX register (to clear LSR.DR and thus prevent a FIFO
4962306a36Sopenharmony_ci	 * aging interrupt). To prevent the irq from retriggering LSR must not be
5062306a36Sopenharmony_ci	 * read. (This would clear LSR.BI, hardware would reassert the BI event
5162306a36Sopenharmony_ci	 * immediately and interrupt the CPU again. The hardware clears LSR.BI
5262306a36Sopenharmony_ci	 * when the next valid char is read.)
5362306a36Sopenharmony_ci	 */
5462306a36Sopenharmony_ci	if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
5562306a36Sopenharmony_ci		up->lsr_saved_flags &= ~UART_LSR_BI;
5662306a36Sopenharmony_ci		port->serial_in(port, UART_RX);
5762306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->port.lock, flags);
5862306a36Sopenharmony_ci		return 1;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Process incoming characters first */
6462306a36Sopenharmony_ci	if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
6562306a36Sopenharmony_ci	    (up->ier & (UART_IER_RLSI | UART_IER_RDI))) {
6662306a36Sopenharmony_ci		lsr = serial8250_rx_chars(up, lsr);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Stop processing interrupts on input overrun */
7062306a36Sopenharmony_ci	if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
7162306a36Sopenharmony_ci		unsigned long delay;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		up->ier = port->serial_in(port, UART_IER);
7462306a36Sopenharmony_ci		if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
7562306a36Sopenharmony_ci			port->ops->stop_rx(port);
7662306a36Sopenharmony_ci		} else {
7762306a36Sopenharmony_ci			/* Keep restarting the timer until
7862306a36Sopenharmony_ci			 * the input overrun subsides.
7962306a36Sopenharmony_ci			 */
8062306a36Sopenharmony_ci			cancel_delayed_work(&up->overrun_backoff);
8162306a36Sopenharmony_ci		}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
8462306a36Sopenharmony_ci		schedule_delayed_work(&up->overrun_backoff, delay);
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	serial8250_modem_status(up);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI))
9062306a36Sopenharmony_ci		serial8250_tx_chars(up);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	up->lsr_saved_flags |= orig_lsr & UART_LSR_BI;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	uart_unlock_and_check_sysrq_irqrestore(&up->port, flags);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return 1;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl8250_handle_irq);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#ifdef CONFIG_ACPI
10162306a36Sopenharmony_cistruct fsl8250_data {
10262306a36Sopenharmony_ci	int	line;
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int fsl8250_acpi_probe(struct platform_device *pdev)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct fsl8250_data *data;
10862306a36Sopenharmony_ci	struct uart_8250_port port8250;
10962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
11062306a36Sopenharmony_ci	struct resource *regs;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	int ret, irq;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11562306a36Sopenharmony_ci	if (!regs) {
11662306a36Sopenharmony_ci		dev_err(dev, "no registers defined\n");
11762306a36Sopenharmony_ci		return -EINVAL;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
12162306a36Sopenharmony_ci	if (irq < 0)
12262306a36Sopenharmony_ci		return irq;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	memset(&port8250, 0, sizeof(port8250));
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ret = device_property_read_u32(dev, "clock-frequency",
12762306a36Sopenharmony_ci					&port8250.port.uartclk);
12862306a36Sopenharmony_ci	if (ret)
12962306a36Sopenharmony_ci		return ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	spin_lock_init(&port8250.port.lock);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	port8250.port.mapbase           = regs->start;
13462306a36Sopenharmony_ci	port8250.port.irq               = irq;
13562306a36Sopenharmony_ci	port8250.port.handle_irq        = fsl8250_handle_irq;
13662306a36Sopenharmony_ci	port8250.port.type              = PORT_16550A;
13762306a36Sopenharmony_ci	port8250.port.flags             = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
13862306a36Sopenharmony_ci						| UPF_FIXED_PORT | UPF_IOREMAP
13962306a36Sopenharmony_ci						| UPF_FIXED_TYPE;
14062306a36Sopenharmony_ci	port8250.port.dev               = dev;
14162306a36Sopenharmony_ci	port8250.port.mapsize           = resource_size(regs);
14262306a36Sopenharmony_ci	port8250.port.iotype            = UPIO_MEM;
14362306a36Sopenharmony_ci	port8250.port.irqflags          = IRQF_SHARED;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	port8250.port.membase = devm_ioremap(dev,  port8250.port.mapbase,
14662306a36Sopenharmony_ci							port8250.port.mapsize);
14762306a36Sopenharmony_ci	if (!port8250.port.membase)
14862306a36Sopenharmony_ci		return -ENOMEM;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
15162306a36Sopenharmony_ci	if (!data)
15262306a36Sopenharmony_ci		return -ENOMEM;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	data->line = serial8250_register_8250_port(&port8250);
15562306a36Sopenharmony_ci	if (data->line < 0)
15662306a36Sopenharmony_ci		return data->line;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	platform_set_drvdata(pdev, data);
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int fsl8250_acpi_remove(struct platform_device *pdev)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct fsl8250_data *data = platform_get_drvdata(pdev);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	serial8250_unregister_port(data->line);
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic const struct acpi_device_id fsl_8250_acpi_id[] = {
17162306a36Sopenharmony_ci	{ "NXP0018", 0 },
17262306a36Sopenharmony_ci	{ },
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, fsl_8250_acpi_id);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic struct platform_driver fsl8250_platform_driver = {
17762306a36Sopenharmony_ci	.driver = {
17862306a36Sopenharmony_ci		.name			= "fsl-16550-uart",
17962306a36Sopenharmony_ci		.acpi_match_table	= ACPI_PTR(fsl_8250_acpi_id),
18062306a36Sopenharmony_ci	},
18162306a36Sopenharmony_ci	.probe			= fsl8250_acpi_probe,
18262306a36Sopenharmony_ci	.remove			= fsl8250_acpi_remove,
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cimodule_platform_driver(fsl8250_platform_driver);
18662306a36Sopenharmony_ci#endif
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
18962306a36Sopenharmony_ciMODULE_DESCRIPTION("Handling of Freescale specific 8250 variants");
190