aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/8250
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c50
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c94
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c73
-rw-r--r--drivers/tty/serial/8250/8250_dw.c121
-rw-r--r--drivers/tty/serial/8250/8250_exar.c52
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c20
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c20
-rw-r--r--drivers/tty/serial/8250/8250_of.c143
-rw-r--r--drivers/tty/serial/8250/8250_omap.c29
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c175
-rw-r--r--drivers/tty/serial/8250/8250_port.c50
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c22
-rw-r--r--drivers/tty/serial/8250/8250_tegra.c26
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c17
-rw-r--r--drivers/tty/serial/8250/Kconfig1
15 files changed, 439 insertions, 454 deletions
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index 8c2aaf7af7b75c..53d8eee9b1c810 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -419,8 +419,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
struct aspeed_vuart *vuart;
struct device_node *np;
struct resource *res;
- u32 clk, prop, sirq[2];
int rc, sirq_polarity;
+ u32 prop, sirq[2];
struct clk *vclk;
np = pdev->dev.of_node;
@@ -447,53 +447,35 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.status = UPSTAT_SYNC_FIFO;
port.port.dev = &pdev->dev;
port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
+ port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE |
+ UPF_NO_THRE_TEST;
port.bugs |= UART_BUG_TXRACE;
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
if (rc < 0)
return rc;
- if (of_property_read_u32(np, "clock-frequency", &clk)) {
+ rc = uart_read_port_properties(&port.port);
+ if (rc)
+ goto err_sysfs_remove;
+
+ /* Get clk rate through clk driver if present */
+ if (!port.port.uartclk) {
vclk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(vclk)) {
rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n");
goto err_sysfs_remove;
}
- clk = clk_get_rate(vclk);
+ port.port.uartclk = clk_get_rate(vclk);
}
/* If current-speed was set, then try not to change it. */
if (of_property_read_u32(np, "current-speed", &prop) == 0)
- port.port.custom_divisor = clk / (16 * prop);
-
- /* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0)
- port.port.mapbase += prop;
-
- /* Check for registers offset within the devices address range */
- if (of_property_read_u32(np, "reg-shift", &prop) == 0)
- port.port.regshift = prop;
+ port.port.custom_divisor = port.port.uartclk / (16 * prop);
- /* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
- port.port.fifosize = prop;
-
- /* Check for a fixed line number */
- rc = of_alias_get_id(np, "serial");
- if (rc >= 0)
- port.port.line = rc;
-
- port.port.irq = irq_of_parse_and_map(np, 0);
port.port.handle_irq = aspeed_vuart_handle_irq;
- port.port.iotype = UPIO_MEM;
port.port.type = PORT_ASPEED_VUART;
- port.port.uartclk = clk;
- port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
- | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
-
- if (of_property_read_bool(np, "no-loopback-test"))
- port.port.flags |= UPF_SKIP_TEST;
if (port.port.fifosize)
port.capabilities = UART_CAP_FIFO;
@@ -503,7 +485,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = serial8250_register_8250_port(&port);
if (rc < 0)
- goto err_clk_disable;
+ goto err_sysfs_remove;
vuart->line = rc;
vuart->port = serial8250_get_port(vuart->line);
@@ -529,7 +511,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = aspeed_vuart_set_lpc_address(vuart, prop);
if (rc < 0) {
dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n");
- goto err_clk_disable;
+ goto err_sysfs_remove;
}
rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2);
@@ -541,14 +523,14 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = aspeed_vuart_set_sirq(vuart, sirq[0]);
if (rc < 0) {
dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n");
- goto err_clk_disable;
+ goto err_sysfs_remove;
}
sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]);
if (sirq_polarity < 0) {
rc = dev_err_probe(dev, sirq_polarity,
"invalid sirq polarity in aspeed,lpc-interrupts property\n");
- goto err_clk_disable;
+ goto err_sysfs_remove;
}
aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity);
@@ -559,8 +541,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
return 0;
-err_clk_disable:
- irq_dispose_mapping(port.port.irq);
err_sysfs_remove:
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
return rc;
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index beac6b340acef7..121a5ce8605089 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -45,10 +45,6 @@ struct bcm2835aux_data {
u32 cntl;
};
-struct bcm2835_aux_serial_driver_data {
- resource_size_t offset;
-};
-
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
{
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
@@ -85,10 +81,9 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
static int bcm2835aux_serial_probe(struct platform_device *pdev)
{
- const struct bcm2835_aux_serial_driver_data *bcm_data;
+ const struct software_node *bcm2835_swnode;
struct uart_8250_port up = { };
struct bcm2835aux_data *data;
- resource_size_t offset = 0;
struct resource *res;
unsigned int uartclk;
int ret;
@@ -101,12 +96,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
/* initialize data */
up.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
up.port.dev = &pdev->dev;
- up.port.regshift = 2;
up.port.type = PORT_16550;
- up.port.iotype = UPIO_MEM;
- up.port.fifosize = 8;
- up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
- UPF_SKIP_TEST | UPF_IOREMAP;
+ up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
up.port.rs485_config = serial8250_em485_config;
up.port.rs485_supported = serial8250_em485_supported;
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
@@ -122,12 +113,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
if (IS_ERR(data->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n");
- /* get the interrupt */
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
- up.port.irq = ret;
-
/* map the main registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -135,52 +120,40 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
return -EINVAL;
}
- bcm_data = device_get_match_data(&pdev->dev);
-
- /* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
- * describe the miniuart with a base address that encompasses the auxiliary
- * registers shared between the miniuart and spi.
- *
- * This is due to historical reasons, see discussion here :
- * https://edk2.groups.io/g/devel/topic/87501357#84349
- *
- * We need to add the offset between the miniuart and auxiliary
- * registers to get the real miniuart base address.
- */
- if (bcm_data)
- offset = bcm_data->offset;
+ up.port.mapbase = res->start;
+ up.port.mapsize = resource_size(res);
+
+ bcm2835_swnode = device_get_match_data(&pdev->dev);
+ if (bcm2835_swnode) {
+ ret = device_add_software_node(&pdev->dev, bcm2835_swnode);
+ if (ret)
+ return ret;
+ }
- up.port.mapbase = res->start + offset;
- up.port.mapsize = resource_size(res) - offset;
+ ret = uart_read_port_properties(&up.port);
+ if (ret)
+ goto rm_swnode;
- /* Check for a fixed line number */
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
- if (ret >= 0)
- up.port.line = ret;
+ up.port.regshift = 2;
+ up.port.fifosize = 8;
/* enable the clock as a last step */
ret = clk_prepare_enable(data->clk);
if (ret) {
- dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
- ret);
- return ret;
+ dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n");
+ goto rm_swnode;
}
uartclk = clk_get_rate(data->clk);
- if (!uartclk) {
- ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
- goto dis_clk;
- }
- }
+ if (uartclk)
+ up.port.uartclk = uartclk;
/* the HW-clock divider for bcm2835aux is 8,
* but 8250 expects a divider of 16,
* so we have to multiply the actual clock by 2
* to get identical baudrates.
*/
- up.port.uartclk = uartclk * 2;
+ up.port.uartclk *= 2;
/* register the port */
ret = serial8250_register_8250_port(&up);
@@ -194,6 +167,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
dis_clk:
clk_disable_unprepare(data->clk);
+rm_swnode:
+ device_remove_software_node(&pdev->dev);
return ret;
}
@@ -203,10 +178,27 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line);
clk_disable_unprepare(data->clk);
+ device_remove_software_node(&pdev->dev);
}
-static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = {
- .offset = 0x40,
+/*
+ * Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
+ * describe the miniuart with a base address that encompasses the auxiliary
+ * registers shared between the miniuart and spi.
+ *
+ * This is due to historical reasons, see discussion here:
+ * https://edk2.groups.io/g/devel/topic/87501357#84349
+ *
+ * We need to add the offset between the miniuart and auxiliary registers
+ * to get the real miniuart base address.
+ */
+static const struct property_entry bcm2835_acpi_properties[] = {
+ PROPERTY_ENTRY_U32("reg-offset", 0x40),
+ { }
+};
+
+static const struct software_node bcm2835_acpi_node = {
+ .properties = bcm2835_acpi_properties,
};
static const struct of_device_id bcm2835aux_serial_match[] = {
@@ -216,7 +208,7 @@ static const struct of_device_id bcm2835aux_serial_match[] = {
MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
- { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data },
+ { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_node },
{ }
};
MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index 504c4c02085776..5daa38d9c64e01 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/units.h>
#include "8250.h"
@@ -187,21 +188,19 @@
#define TX_BUF_SIZE 4096
#define RX_BUF_SIZE 4096
#define RX_BUFS_COUNT 2
-#define KHZ 1000
-#define MHZ(x) ((x) * KHZ * KHZ)
static const u32 brcmstb_rate_table[] = {
- MHZ(81),
- MHZ(108),
- MHZ(64), /* Actually 64285715 for some chips */
- MHZ(48),
+ 81 * HZ_PER_MHZ,
+ 108 * HZ_PER_MHZ,
+ 64 * HZ_PER_MHZ, /* Actually 64285715 for some chips */
+ 48 * HZ_PER_MHZ,
};
static const u32 brcmstb_rate_table_7278[] = {
- MHZ(81),
- MHZ(108),
+ 81 * HZ_PER_MHZ,
+ 108 * HZ_PER_MHZ,
0,
- MHZ(48),
+ 48 * HZ_PER_MHZ,
};
struct brcmuart_priv {
@@ -936,17 +935,14 @@ static void brcmuart_init_debugfs(struct brcmuart_priv *priv,
static int brcmuart_probe(struct platform_device *pdev)
{
struct resource *regs;
- struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id = NULL;
struct uart_8250_port *new_port;
struct device *dev = &pdev->dev;
struct brcmuart_priv *priv;
struct clk *baud_mux_clk;
struct uart_8250_port up;
- int irq;
void __iomem *membase = NULL;
resource_size_t mapbase = 0;
- u32 clk_rate = 0;
int ret;
int x;
int dma_irq;
@@ -954,15 +950,12 @@ static int brcmuart_probe(struct platform_device *pdev)
"uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb"
};
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
- of_id = of_match_node(brcmuart_dt_ids, np);
+ of_id = of_match_node(brcmuart_dt_ids, dev->of_node);
if (!of_id || !of_id->data)
priv->rate_table = brcmstb_rate_table;
else
@@ -1012,7 +1005,23 @@ static int brcmuart_probe(struct platform_device *pdev)
}
}
- of_property_read_u32(np, "clock-frequency", &clk_rate);
+ dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
+
+ memset(&up, 0, sizeof(up));
+ up.port.type = PORT_BCM7271;
+ up.port.dev = dev;
+ up.port.mapbase = mapbase;
+ up.port.membase = membase;
+ up.port.handle_irq = brcmuart_handle_irq;
+ up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ up.port.private_data = priv;
+
+ ret = uart_read_port_properties(&up.port);
+ if (ret)
+ goto release_dma;
+
+ up.port.regshift = 2;
+ up.port.iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
/* See if a Baud clock has been specified */
baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud");
@@ -1024,39 +1033,11 @@ static int brcmuart_probe(struct platform_device *pdev)
priv->baud_mux_clk = baud_mux_clk;
init_real_clk_rates(dev, priv);
- clk_rate = priv->default_mux_rate;
+ up.port.uartclk = priv->default_mux_rate;
} else {
dev_dbg(dev, "BAUD MUX clock not specified\n");
}
- if (clk_rate == 0) {
- ret = dev_err_probe(dev, -EINVAL, "clock-frequency or clk not defined\n");
- goto release_dma;
- }
-
- dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
-
- memset(&up, 0, sizeof(up));
- up.port.type = PORT_BCM7271;
- up.port.uartclk = clk_rate;
- up.port.dev = dev;
- up.port.mapbase = mapbase;
- up.port.membase = membase;
- up.port.irq = irq;
- up.port.handle_irq = brcmuart_handle_irq;
- up.port.regshift = 2;
- up.port.iotype = of_device_is_big_endian(np) ?
- UPIO_MEM32BE : UPIO_MEM32;
- up.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
- | UPF_FIXED_PORT | UPF_FIXED_TYPE;
- up.port.dev = dev;
- up.port.private_data = priv;
-
- /* Check for a fixed line number */
- ret = of_alias_get_id(np, "serial");
- if (ret >= 0)
- up.port.line = ret;
-
/* setup HR timer */
hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
priv->hrt.function = brcmuart_hrtimer_func;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index c1d43f040c43ab..a3acbf0f5da1be 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -9,7 +9,6 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
-#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -17,7 +16,6 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
-#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -56,6 +54,7 @@
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
+#define DW_UART_QUIRK_APMC0D08 BIT(4)
static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
{
@@ -445,44 +444,29 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
- struct device_node *np = p->dev->of_node;
+ unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
- if (np) {
- unsigned int quirks = data->pdata->quirks;
- int id;
-
- /* get index of serial line, if found in DT aliases */
- id = of_alias_get_id(np, "serial");
- if (id >= 0)
- p->line = id;
#ifdef CONFIG_64BIT
- if (quirks & DW_UART_QUIRK_OCTEON) {
- p->serial_in = dw8250_serial_inq;
- p->serial_out = dw8250_serial_outq;
- p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
- p->type = PORT_OCTEON;
- data->skip_autocfg = true;
- }
+ if (quirks & DW_UART_QUIRK_OCTEON) {
+ p->serial_in = dw8250_serial_inq;
+ p->serial_out = dw8250_serial_outq;
+ p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+ p->type = PORT_OCTEON;
+ data->skip_autocfg = true;
+ }
#endif
- if (of_device_is_big_endian(np)) {
- p->iotype = UPIO_MEM32BE;
- p->serial_in = dw8250_serial_in32be;
- p->serial_out = dw8250_serial_out32be;
- }
-
- if (quirks & DW_UART_QUIRK_ARMADA_38X)
- p->serial_out = dw8250_serial_out38x;
- if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
- p->set_termios = dw8250_do_set_termios;
- if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
- data->data.dma.txconf.device_fc = 1;
- data->data.dma.rxconf.device_fc = 1;
- data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
- data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
- }
-
- } else if (acpi_dev_present("APMC0D08", NULL, -1)) {
+ if (quirks & DW_UART_QUIRK_ARMADA_38X)
+ p->serial_out = dw8250_serial_out38x;
+ if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
+ p->set_termios = dw8250_do_set_termios;
+ if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
+ data->data.dma.txconf.device_fc = 1;
+ data->data.dma.rxconf.device_fc = 1;
+ data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
+ data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
+ }
+ if (quirks & DW_UART_QUIRK_APMC0D08) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
p->serial_in = dw8250_serial_in32;
@@ -510,39 +494,21 @@ static int dw8250_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dw8250_data *data;
struct resource *regs;
- int irq;
int err;
- u32 val;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
- irq = platform_get_irq_optional(pdev, 0);
- /* no interrupt -> fall back to polling */
- if (irq == -ENXIO)
- irq = 0;
- if (irq < 0)
- return irq;
-
spin_lock_init(&p->lock);
- p->mapbase = regs->start;
- p->irq = irq;
p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm;
p->type = PORT_8250;
- p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+ p->flags = UPF_FIXED_PORT;
p->dev = dev;
- p->iotype = UPIO_MEM;
- p->serial_in = dw8250_serial_in;
- p->serial_out = dw8250_serial_out;
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
- p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
- if (!p->membase)
- return -ENOMEM;
-
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -554,15 +520,35 @@ static int dw8250_probe(struct platform_device *pdev)
data->uart_16550_compatible = device_property_read_bool(dev,
"snps,uart-16550-compatible");
- err = device_property_read_u32(dev, "reg-shift", &val);
- if (!err)
- p->regshift = val;
+ p->mapbase = regs->start;
+ p->mapsize = resource_size(regs);
- err = device_property_read_u32(dev, "reg-io-width", &val);
- if (!err && val == 4) {
- p->iotype = UPIO_MEM32;
+ p->membase = devm_ioremap(dev, p->mapbase, p->mapsize);
+ if (!p->membase)
+ return -ENOMEM;
+
+ err = uart_read_port_properties(p);
+ /* no interrupt -> fall back to polling */
+ if (err == -ENXIO)
+ err = 0;
+ if (err)
+ return err;
+
+ switch (p->iotype) {
+ case UPIO_MEM:
+ p->serial_in = dw8250_serial_in;
+ p->serial_out = dw8250_serial_out;
+ break;
+ case UPIO_MEM32:
p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32;
+ break;
+ case UPIO_MEM32BE:
+ p->serial_in = dw8250_serial_in32be;
+ p->serial_out = dw8250_serial_out32be;
+ break;
+ default:
+ return -ENODEV;
}
if (device_property_read_bool(dev, "dcd-override")) {
@@ -589,15 +575,13 @@ static int dw8250_probe(struct platform_device *pdev)
data->msr_mask_off |= UART_MSR_TERI;
}
- /* Always ask for fixed clock rate from a property. */
- device_property_read_u32(dev, "clock-frequency", &p->uartclk);
-
/* If there is separate baudclk, get the rate from it. */
data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
if (data->clk == NULL)
data->clk = devm_clk_get_optional_enabled(dev, NULL);
if (IS_ERR(data->clk))
- return PTR_ERR(data->clk);
+ return dev_err_probe(dev, PTR_ERR(data->clk),
+ "failed to get baudclk\n");
INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
@@ -762,13 +746,18 @@ static const struct of_device_id dw8250_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
+static const struct dw8250_platform_data dw8250_apmc0d08 = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_APMC0D08,
+};
+
static const struct acpi_device_id dw8250_acpi_match[] = {
{ "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
- { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+ { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
{ "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
{ "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 23366f868ae3a8..0440df7de1ed74 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -6,23 +6,29 @@
*
* Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved.
*/
-#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/dmi.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/kernel.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/property.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
#include <asm/byteorder.h>
#include "8250.h"
+#include "8250_pcilib.h"
#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052
#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d
@@ -229,13 +235,12 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port)
{
const struct exar8250_board *board = priv->board;
- unsigned int bar = 0;
unsigned char status;
+ int err;
- port->port.iotype = UPIO_MEM;
- port->port.mapbase = pci_resource_start(pcidev, bar) + offset;
- port->port.membase = priv->virt + offset;
- port->port.regshift = board->reg_shift;
+ err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
+ if (err)
+ return err;
/*
* XR17V35x UARTs have an extra divisor register, DLD that gets enabled
@@ -375,7 +380,7 @@ static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev,
return NULL;
pdev->dev.parent = &pcidev->dev;
- ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev));
+ device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev));
if (device_add_software_node(&pdev->dev, node) < 0 ||
platform_device_add(pdev) < 0) {
@@ -713,14 +718,14 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
uart.port.irq = pci_irq_vector(pcidev, 0);
uart.port.dev = &pcidev->dev;
+ /* Clear interrupts */
+ exar_misc_clear(priv);
+
rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler,
IRQF_SHARED, "exar_uart", priv);
if (rc)
return rc;
- /* Clear interrupts */
- exar_misc_clear(priv);
-
for (i = 0; i < nr_ports && i < maxnr; i++) {
rc = board->setup(priv, pcidev, &uart, i);
if (rc) {
@@ -753,28 +758,24 @@ static void exar_pci_remove(struct pci_dev *pcidev)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
+ /* Ensure that every init quirk is properly torn down */
if (priv->board->exit)
priv->board->exit(pcidev);
}
-static int __maybe_unused exar_suspend(struct device *dev)
+static int exar_suspend(struct device *dev)
{
- struct pci_dev *pcidev = to_pci_dev(dev);
- struct exar8250 *priv = pci_get_drvdata(pcidev);
+ struct exar8250 *priv = dev_get_drvdata(dev);
unsigned int i;
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
- /* Ensure that every init quirk is properly torn down */
- if (priv->board->exit)
- priv->board->exit(pcidev);
-
return 0;
}
-static int __maybe_unused exar_resume(struct device *dev)
+static int exar_resume(struct device *dev)
{
struct exar8250 *priv = dev_get_drvdata(dev);
unsigned int i;
@@ -788,7 +789,7 @@ static int __maybe_unused exar_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
static const struct exar8250_board pbn_fastcom335_2 = {
.num_ports = 2,
@@ -938,12 +939,13 @@ static struct pci_driver exar_pci_driver = {
.probe = exar_pci_probe,
.remove = exar_pci_remove,
.driver = {
- .pm = &exar_pci_pm,
+ .pm = pm_sleep_ptr(&exar_pci_pm),
},
.id_table = exar_pci_tbl,
};
module_pci_driver(exar_pci_driver);
+MODULE_IMPORT_NS(SERIAL_8250_PCI);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Exar Serial Driver");
MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index a12f737924c0b7..a2783e38a2e316 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -234,7 +234,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
struct ingenic_uart_data *data;
const struct ingenic_uart_config *cdata;
struct resource *regs;
- int irq, err, line;
+ int err;
cdata = of_device_get_match_data(&pdev->dev);
if (!cdata) {
@@ -242,10 +242,6 @@ static int ingenic_uart_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(&pdev->dev, "no registers defined\n");
@@ -259,21 +255,19 @@ static int ingenic_uart_probe(struct platform_device *pdev)
spin_lock_init(&uart.port.lock);
uart.port.type = PORT_16550A;
uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
- uart.port.iotype = UPIO_MEM;
uart.port.mapbase = regs->start;
- uart.port.regshift = 2;
uart.port.serial_out = ingenic_uart_serial_out;
uart.port.serial_in = ingenic_uart_serial_in;
- uart.port.irq = irq;
uart.port.dev = &pdev->dev;
- uart.port.fifosize = cdata->fifosize;
uart.tx_loadsz = cdata->tx_loadsz;
uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
- /* Check for a fixed line number */
- line = of_alias_get_id(pdev->dev.of_node, "serial");
- if (line >= 0)
- uart.port.line = line;
+ err = uart_read_port_properties(&uart.port);
+ if (err)
+ return err;
+
+ uart.port.regshift = 2;
+ uart.port.fifosize = cdata->fifosize;
uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
resource_size(regs));
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 8d728a6a599141..7984ee05af1dad 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -92,11 +92,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
struct lpc18xx_uart_data *data;
struct uart_8250_port uart;
struct resource *res;
- int irq, ret;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -139,19 +135,12 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
goto dis_clk_reg;
}
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
- if (ret >= 0)
- uart.port.line = ret;
-
data->dma.rx_param = data;
data->dma.tx_param = data;
spin_lock_init(&uart.port.lock);
uart.port.dev = &pdev->dev;
- uart.port.irq = irq;
- uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = res->start;
- uart.port.regshift = 2;
uart.port.type = PORT_16550A;
uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
uart.port.uartclk = clk_get_rate(data->clk_uart);
@@ -160,6 +149,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
uart.port.rs485_supported = lpc18xx_rs485_supported;
uart.port.serial_out = lpc18xx_uart_serial_out;
+ ret = uart_read_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = 2;
+
uart.dma = &data->dma;
uart.dma->rxconf.src_maxburst = 1;
uart.dma->txconf.dst_maxburst = 1;
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 34f17a9785e79e..5d1dd992d8fba0 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -4,7 +4,10 @@
*
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/
+
+#include <linux/bits.h>
#include <linux/console.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/serial_core.h>
@@ -25,6 +28,36 @@ struct of_serial_info {
int line;
};
+/* Nuvoton NPCM timeout register */
+#define UART_NPCM_TOR 7
+#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
+
+static int npcm_startup(struct uart_port *port)
+{
+ /*
+ * Nuvoton calls the scratch register 'UART_TOR' (timeout
+ * register). Enable it, and set TIOC (timeout interrupt
+ * comparator) to be 0x20 for correct operation.
+ */
+ serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
+
+ return serial8250_do_startup(port);
+}
+
+/* Nuvoton NPCM UARTs have a custom divisor calculation */
+static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int *frac)
+{
+ return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
+}
+
+static int npcm_setup(struct uart_port *port)
+{
+ port->get_divisor = npcm_get_divisor;
+ port->startup = npcm_startup;
+ return 0;
+}
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -36,37 +69,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct device *dev = &ofdev->dev;
struct device_node *np = dev->of_node;
struct uart_port *port = &up->port;
- u32 clk, spd, prop;
- int ret, irq;
+ u32 spd;
+ int ret;
memset(port, 0, sizeof *port);
pm_runtime_enable(&ofdev->dev);
pm_runtime_get_sync(&ofdev->dev);
- if (of_property_read_u32(np, "clock-frequency", &clk)) {
-
- /* Get clk rate through clk driver if present */
- info->clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(info->clk)) {
- ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
- goto err_pmruntime;
- }
-
- clk = clk_get_rate(info->clk);
- }
- /* If current-speed was set, then try not to change it. */
- if (of_property_read_u32(np, "current-speed", &spd) == 0)
- port->custom_divisor = clk / (16 * spd);
-
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_err_probe(dev, ret, "invalid address\n");
goto err_pmruntime;
}
- port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
- UPF_FIXED_TYPE;
+ port->dev = &ofdev->dev;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
spin_lock_init(&port->lock);
if (resource_type(&resource) == IORESOURCE_IO) {
@@ -75,70 +93,31 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
} else {
port->mapbase = resource.start;
port->mapsize = resource_size(&resource);
+ port->flags |= UPF_IOREMAP;
+ }
- /* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
- if (prop >= port->mapsize) {
- ret = dev_err_probe(dev, -EINVAL, "reg-offset %u exceeds region size %pa\n",
- prop, &port->mapsize);
- goto err_pmruntime;
- }
+ ret = uart_read_and_validate_port_properties(port);
+ if (ret)
+ goto err_pmruntime;
- port->mapbase += prop;
- port->mapsize -= prop;
+ /* Get clk rate through clk driver if present */
+ if (!port->uartclk) {
+ info->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(info->clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
+ goto err_pmruntime;
}
- port->iotype = UPIO_MEM;
- if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
- switch (prop) {
- case 1:
- port->iotype = UPIO_MEM;
- break;
- case 2:
- port->iotype = UPIO_MEM16;
- break;
- case 4:
- port->iotype = of_device_is_big_endian(np) ?
- UPIO_MEM32BE : UPIO_MEM32;
- break;
- default:
- ret = dev_err_probe(dev, -EINVAL, "unsupported reg-io-width (%u)\n",
- prop);
- goto err_pmruntime;
- }
- }
- port->flags |= UPF_IOREMAP;
+ port->uartclk = clk_get_rate(info->clk);
}
+ /* If current-speed was set, then try not to change it. */
+ if (of_property_read_u32(np, "current-speed", &spd) == 0)
+ port->custom_divisor = port->uartclk / (16 * spd);
/* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */
if (of_device_is_compatible(np, "mrvl,mmp-uart"))
port->regshift = 2;
- /* Check for registers offset within the devices address range */
- if (of_property_read_u32(np, "reg-shift", &prop) == 0)
- port->regshift = prop;
-
- /* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
- port->fifosize = prop;
-
- /* Check for a fixed line number */
- ret = of_alias_get_id(np, "serial");
- if (ret >= 0)
- port->line = ret;
-
- irq = of_irq_get(np, 0);
- if (irq < 0) {
- if (irq == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto err_pmruntime;
- }
- /* IRQ support not mandatory */
- irq = 0;
- }
-
- port->irq = irq;
-
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) {
ret = PTR_ERR(info->rst);
@@ -150,12 +129,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
goto err_pmruntime;
port->type = type;
- port->uartclk = clk;
-
- if (of_property_read_bool(np, "no-loopback-test"))
- port->flags |= UPF_SKIP_TEST;
-
- port->dev = &ofdev->dev;
port->rs485_config = serial8250_em485_config;
port->rs485_supported = serial8250_em485_supported;
up->rs485_start_tx = serial8250_em485_start_tx;
@@ -164,10 +137,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
switch (type) {
case PORT_RT2880:
ret = rt288x_setup(port);
- if (ret)
- goto err_pmruntime;
+ break;
+ case PORT_NPCM:
+ ret = npcm_setup(port);
+ break;
+ default:
+ /* Nothing to do */
+ ret = 0;
break;
}
+ if (ret)
+ goto err_pmruntime;
if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) &&
(of_device_is_compatible(np, "fsl,ns16550") ||
@@ -240,7 +220,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
platform_set_drvdata(ofdev, info);
return 0;
err_dispose:
- irq_dispose_mapping(port8250.port.irq);
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
err_free:
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6942990a333c8b..66901d93089a3c 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1394,11 +1394,7 @@ static int omap8250_probe(struct platform_device *pdev)
struct uart_8250_port up;
struct resource *regs;
void __iomem *membase;
- int irq, ret;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -1419,7 +1415,6 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev;
up.port.mapbase = regs->start;
up.port.membase = membase;
- up.port.irq = irq;
/*
* It claims to be 16C750 compatible however it is a little different.
* It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
@@ -1429,13 +1424,9 @@ static int omap8250_probe(struct platform_device *pdev)
* or pm callback.
*/
up.port.type = PORT_8250;
- up.port.iotype = UPIO_MEM;
- up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW |
- UPF_HARD_FLOW;
+ up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | UPF_HARD_FLOW;
up.port.private_data = priv;
- up.port.regshift = OMAP_UART_REGSHIFT;
- up.port.fifosize = 64;
up.tx_loadsz = 64;
up.capabilities = UART_CAP_FIFO;
#ifdef CONFIG_PM
@@ -1461,14 +1452,14 @@ static int omap8250_probe(struct platform_device *pdev)
up.rs485_stop_tx = serial8250_em485_stop_tx;
up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
- ret = of_alias_get_id(np, "serial");
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias\n");
+ ret = uart_read_port_properties(&up.port);
+ if (ret)
return ret;
- }
- up.port.line = ret;
- if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) {
+ up.port.regshift = OMAP_UART_REGSHIFT;
+ up.port.fifosize = 64;
+
+ if (!up.port.uartclk) {
struct clk *clk;
clk = devm_clk_get(&pdev->dev, NULL);
@@ -1560,8 +1551,8 @@ static int omap8250_probe(struct platform_device *pdev)
}
#endif
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
- ret = devm_request_irq(&pdev->dev, irq, omap8250_irq, 0,
+ irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
dev_name(&pdev->dev), priv);
if (ret < 0)
return ret;
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index 2dda737b1660bd..2fbb5851f788b7 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -7,23 +7,31 @@
* Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
+#include <linux/bits.h>
+#include <linux/circ_buf.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp_types.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
#include <linux/pci.h>
+#include <linux/pm.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
-#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/string.h>
-#include <linux/units.h>
+#include <linux/time.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/8250_pci.h>
+#include <linux/types.h>
+#include <linux/units.h>
#include <asm/byteorder.h>
@@ -67,6 +75,7 @@
#define SYSLOCK_RETRY_CNT 1000
#define UART_RX_BYTE_FIFO 0x00
+#define UART_TX_BYTE_FIFO 0x00
#define UART_FIFO_CTL 0x02
#define UART_ACTV_REG 0x11
@@ -81,10 +90,10 @@
#define ADCL_CFG_PIN_SEL BIT(1)
#define ADCL_CFG_EN BIT(0)
-#define UART_BIT_SAMPLE_CNT 16
+#define UART_BIT_SAMPLE_CNT_8 8
+#define UART_BIT_SAMPLE_CNT_16 16
#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
-#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
#define UART_WAKE_REG 0x8C
#define UART_WAKE_MASK_REG 0x90
@@ -95,13 +104,19 @@
(UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
#define UART_BAUD_CLK_DIVISOR_REG 0x54
+#define FRAC_DIV_CFG_REG 0x58
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
#define UART_BURST_STATUS_REG 0x9C
+#define UART_TX_BURST_FIFO 0xA0
#define UART_RX_BURST_FIFO 0xA4
+#define UART_BIT_DIVISOR_8 0x26731000
+#define UART_BIT_DIVISOR_16 0x6ef71000
+#define UART_BAUD_4MBPS 4000000
+
#define MAX_PORTS 4
#define PORT_OFFSET 0x100
#define RX_BUF_SIZE 512
@@ -109,6 +124,7 @@
#define UART_BURST_SIZE 4
#define UART_BST_STAT_RX_COUNT_MASK 0x00FF
+#define UART_BST_STAT_TX_COUNT_MASK 0xFF00
#define UART_BST_STAT_IIR_INT_PEND 0x100000
#define UART_LSR_OVERRUN_ERR_CLR 0x43
#define UART_BST_STAT_LSR_RX_MASK 0x9F000000
@@ -116,6 +132,7 @@
#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000
#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000
#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
+#define UART_BST_STAT_LSR_THRE 0x20000000
struct pci1xxxx_8250 {
unsigned int nr;
@@ -206,15 +223,21 @@ static int pci1xxxx_get_num_ports(struct pci_dev *dev)
static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
unsigned int baud, unsigned int *frac)
{
+ unsigned int uart_sample_cnt;
unsigned int quot;
+ if (baud >= UART_BAUD_4MBPS)
+ uart_sample_cnt = UART_BIT_SAMPLE_CNT_8;
+ else
+ uart_sample_cnt = UART_BIT_SAMPLE_CNT_16;
+
/*
* Calculate baud rate sampling period in nanoseconds.
* Fractional part x denotes x/255 parts of a nanosecond.
*/
- quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
- *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
- 255 / UART_BIT_SAMPLE_CNT / baud;
+ quot = NSEC_PER_SEC / (baud * uart_sample_cnt);
+ *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) *
+ 255 / uart_sample_cnt / baud;
return quot;
}
@@ -222,6 +245,11 @@ static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int frac)
{
+ if (baud >= UART_BAUD_4MBPS)
+ writel(UART_BIT_DIVISOR_8, port->membase + FRAC_DIV_CFG_REG);
+ else
+ writel(UART_BIT_DIVISOR_16, port->membase + FRAC_DIV_CFG_REG);
+
writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
port->membase + UART_BAUD_CLK_DIVISOR_REG);
}
@@ -233,7 +261,16 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
u32 delay_in_baud_periods;
u32 baud_period_in_ns;
u32 mode_cfg = 0;
+ u32 sample_cnt;
u32 clock_div;
+ u32 frac_div;
+
+ frac_div = readl(port->membase + FRAC_DIV_CFG_REG);
+
+ if (frac_div == UART_BIT_DIVISOR_16)
+ sample_cnt = UART_BIT_SAMPLE_CNT_16;
+ else
+ sample_cnt = UART_BIT_SAMPLE_CNT_8;
/*
* pci1xxxx's uart hardware supports only RTS delay after
@@ -249,7 +286,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
baud_period_in_ns =
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
- UART_BIT_SAMPLE_CNT;
+ sample_cnt;
delay_in_baud_periods =
rs485->delay_rts_after_send * NSEC_PER_MSEC /
baud_period_in_ns;
@@ -344,6 +381,105 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
}
}
+static void pci1xxxx_process_write_data(struct uart_port *port,
+ struct circ_buf *xmit,
+ int *data_empty_count,
+ u32 *valid_byte_count)
+{
+ u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
+
+ /*
+ * Each transaction transfers data in DWORDs. If there are less than
+ * four remaining valid_byte_count to transfer or if the circular
+ * buffer has insufficient space for a DWORD, the data is transferred
+ * one byte at a time.
+ */
+ while (valid_burst_count) {
+ if (*data_empty_count - UART_BURST_SIZE < 0)
+ break;
+ if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE))
+ break;
+ writel(*(unsigned int *)&xmit->buf[xmit->tail],
+ port->membase + UART_TX_BURST_FIFO);
+ *valid_byte_count -= UART_BURST_SIZE;
+ *data_empty_count -= UART_BURST_SIZE;
+ valid_burst_count -= UART_BYTE_SIZE;
+
+ xmit->tail = (xmit->tail + UART_BURST_SIZE) &
+ (UART_XMIT_SIZE - 1);
+ }
+
+ while (*valid_byte_count) {
+ if (*data_empty_count - UART_BYTE_SIZE < 0)
+ break;
+ writeb(xmit->buf[xmit->tail], port->membase +
+ UART_TX_BYTE_FIFO);
+ *data_empty_count -= UART_BYTE_SIZE;
+ *valid_byte_count -= UART_BYTE_SIZE;
+
+ /*
+ * When the tail of the circular buffer is reached, the next
+ * byte is transferred to the beginning of the buffer.
+ */
+ xmit->tail = (xmit->tail + UART_BYTE_SIZE) &
+ (UART_XMIT_SIZE - 1);
+
+ /*
+ * If there are any pending burst count, data is handled by
+ * transmitting DWORDs at a time.
+ */
+ if (valid_burst_count && (xmit->tail <
+ (UART_XMIT_SIZE - UART_BURST_SIZE)))
+ break;
+ }
+}
+
+static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u32 valid_byte_count;
+ int data_empty_count;
+ struct circ_buf *xmit;
+
+ xmit = &port->state->xmit;
+
+ if (port->x_char) {
+ writeb(port->x_char, port->membase + UART_TX);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) {
+ port->ops->stop_tx(port);
+ } else {
+ data_empty_count = (pci1xxxx_read_burst_status(port) &
+ UART_BST_STAT_TX_COUNT_MASK) >> 8;
+ do {
+ valid_byte_count = uart_circ_chars_pending(xmit);
+
+ pci1xxxx_process_write_data(port, xmit,
+ &data_empty_count,
+ &valid_byte_count);
+
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (data_empty_count && valid_byte_count);
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ /*
+ * With RPM enabled, we have to wait until the FIFO is empty before
+ * the HW can go idle. So we get here once again with empty FIFO and
+ * disable the interrupt and RPM in __stop_tx()
+ */
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ port->ops->stop_tx(port);
+}
+
static int pci1xxxx_handle_irq(struct uart_port *port)
{
unsigned long flags;
@@ -359,6 +495,9 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
if (status & UART_BST_STAT_LSR_RX_MASK)
pci1xxxx_rx_burst(port, status);
+ if (status & UART_BST_STAT_LSR_THRE)
+ pci1xxxx_tx_burst(port, status);
+
spin_unlock_irqrestore(&port->lock, flags);
return 1;
@@ -481,6 +620,17 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
port->port.type = PORT_MCHP16550A;
+ /*
+ * 8250 core considers prescaller value to be always 16.
+ * The MCHP ports support downscaled mode and hence the
+ * functional UART clock can be lower, i.e. 62.5MHz, than
+ * software expects in order to support higher baud rates.
+ * Assign here 64MHz to support 4Mbps.
+ *
+ * The value itself is not really used anywhere except baud
+ * rate calculations, so we can mangle it as we wish.
+ */
+ port->port.uartclk = 64 * HZ_PER_MHZ;
port->port.set_termios = serial8250_do_set_termios;
port->port.get_divisor = pci1xxxx_get_divisor;
port->port.set_divisor = pci1xxxx_set_divisor;
@@ -594,7 +744,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
memset(&uart, 0, sizeof(uart));
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
- uart.port.uartclk = UART_CLOCK_DEFAULT;
uart.port.dev = dev;
if (num_vectors == max_vec_reqd)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8ca061d3bbb921..fc9dd5d45295da 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -38,10 +38,6 @@
#include "8250.h"
-/* Nuvoton NPCM timeout register */
-#define UART_NPCM_TOR 7
-#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
-
/*
* Debugging.
*/
@@ -1329,9 +1325,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
inb_p(ICP);
}
- if (uart_console(port))
- console_lock();
-
/* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on());
save_mcr = serial8250_in_MCR(up);
@@ -1371,9 +1364,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
if (port->flags & UPF_FOURPORT)
outb_p(save_ICP, ICP);
- if (uart_console(port))
- console_unlock();
-
port->irq = (irq > 0) ? irq : 0;
}
@@ -2235,15 +2225,6 @@ int serial8250_do_startup(struct uart_port *port)
UART_DA830_PWREMU_MGMT_FREE);
}
- if (port->type == PORT_NPCM) {
- /*
- * Nuvoton calls the scratch register 'UART_TOR' (timeout
- * register). Enable it, and set TIOC (timeout interrupt
- * comparator) to be 0x20 for correct operation.
- */
- serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
- }
-
#ifdef CONFIG_SERIAL_8250_RSA
/*
* If this is an RSA port, see if we can kick it up to the
@@ -2545,15 +2526,6 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
-/* Nuvoton NPCM UARTs have a custom divisor calculation */
-static unsigned int npcm_get_divisor(struct uart_8250_port *up,
- unsigned int baud)
-{
- struct uart_port *port = &up->port;
-
- return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
-}
-
static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
@@ -2598,8 +2570,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
quot = 0x8001;
else if (magic_multiplier && baud >= port->uartclk / 12)
quot = 0x8002;
- else if (up->port.type == PORT_NPCM)
- quot = npcm_get_divisor(up, baud);
else
quot = uart_get_divisor(port, baud);
@@ -2714,12 +2684,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
*/
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
{
- struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
- unsigned int baud, quot, frac = 0;
- struct ktermios *termios;
struct tty_struct *tty;
- unsigned long flags;
tty = tty_port_tty_get(tport);
if (!tty) {
@@ -2740,21 +2706,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
if (!tty_port_initialized(tport))
goto out_unlock;
- termios = &tty->termios;
-
- baud = serial8250_get_baud_rate(port, termios, NULL);
- quot = serial8250_get_divisor(port, baud, &frac);
-
- serial8250_rpm_get(up);
- uart_port_lock_irqsave(port, &flags);
-
- uart_update_timeout(port, termios->c_cflag, baud);
-
- serial8250_set_divisor(port, baud, quot, frac);
- serial_port_out(port, UART_LCR, up->lcr);
-
- uart_port_unlock_irqrestore(port, flags);
- serial8250_rpm_put(up);
+ serial8250_do_set_termios(port, &tty->termios, NULL);
out_unlock:
mutex_unlock(&tport->mutex);
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index 77686da42ce8e9..f1a51b00b1b9de 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -92,11 +92,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
struct uart_8250_port uart = {};
struct pxa8250_data *data;
struct resource *mmres;
- int irq, ret;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ int ret;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mmres)
@@ -114,21 +110,21 @@ static int serial_pxa_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
- if (ret >= 0)
- uart.port.line = ret;
-
uart.port.type = PORT_XSCALE;
- uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = mmres->start;
- uart.port.regshift = 2;
- uart.port.irq = irq;
- uart.port.fifosize = 64;
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
uart.port.dev = &pdev->dev;
uart.port.uartclk = clk_get_rate(data->clk);
uart.port.pm = serial_pxa_pm;
uart.port.private_data = data;
+
+ ret = uart_read_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = 2;
+ uart.port.fifosize = 64;
uart.dl_write = serial_pxa_dl_write;
ret = serial8250_register_8250_port(&uart);
diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c
index ba352262df75a7..60a80d00d2519b 100644
--- a/drivers/tty/serial/8250/8250_tegra.c
+++ b/drivers/tty/serial/8250/8250_tegra.c
@@ -57,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev)
port = &port8250.port;
spin_lock_init(&port->lock);
- port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
- UPF_FIXED_TYPE;
- port->iotype = UPIO_MEM32;
- port->regshift = 2;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->type = PORT_TEGRA;
- port->irqflags |= IRQF_SHARED;
port->dev = &pdev->dev;
port->handle_break = tegra_uart_handle_break;
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
- if (ret >= 0)
- port->line = ret;
-
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
-
- port->irq = ret;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
@@ -88,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev)
port->mapbase = res->start;
port->mapsize = resource_size(res);
+ ret = uart_read_port_properties(port);
+ if (ret)
+ return ret;
+
+ port->iotype = UPIO_MEM32;
+ port->regshift = 2;
+
uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
if (IS_ERR(uart->rst))
return PTR_ERR(uart->rst);
- if (device_property_read_u32(&pdev->dev, "clock-frequency",
- &port->uartclk)) {
+ if (!port->uartclk) {
uart->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uart->clk)) {
dev_err(&pdev->dev, "failed to get clock!\n");
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 6399a38ecce2ad..670d2ca0f75729 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -162,7 +162,6 @@ static int uniphier_uart_probe(struct platform_device *pdev)
struct uniphier8250_priv *priv;
struct resource *regs;
void __iomem *membase;
- int irq;
int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev)
if (!membase)
return -ENOMEM;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
memset(&up, 0, sizeof(up));
- ret = of_alias_get_id(dev->of_node, "serial");
- if (ret < 0) {
- dev_err(dev, "failed to get alias id\n");
- return ret;
- }
- up.port.line = ret;
-
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
@@ -211,7 +199,10 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.mapbase = regs->start;
up.port.mapsize = resource_size(regs);
up.port.membase = membase;
- up.port.irq = irq;
+
+ ret = uart_read_port_properties(&up.port);
+ if (ret)
+ return ret;
up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32;
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 8b9a2c4902e2c3..47ff50763c048c 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -149,6 +149,7 @@ config SERIAL_8250_PCI
config SERIAL_8250_EXAR
tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
depends on SERIAL_8250 && PCI
+ select SERIAL_8250_PCILIB
default SERIAL_8250
help
This builds support for XR17C1xx, XR17V3xx and some Commtech