mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
serial: pl011: rp1 uart support
Signed-off-by: Phil Elwell <phil@raspberrypi.com> ARM: pl011: Add rs485 to the RP1 support pl011_axi_probe, added for RP1 support, lacks the rs485 additions that appeared during its development. Signed-off-by: Phil Elwell <phil@raspberrypi.com> tty/serial: pl011: restrict RX burst FIFO threshold If the associated DMA controller has lower burst length support than the level the FIFO is set to, then bytes will be left in the RX FIFO at the end of a DMA block - requiring a round-trip through the timeout interrupt handler rather than an end-of-block DMA interrupt. Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com> tty/serial: pl011: Also unregister pl011_axi_platform_driver See: https://github.com/raspberrypi/linux/issues/6379 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
This commit is contained in:
@@ -152,6 +152,20 @@ static const struct vendor_data vendor_sbsa = {
|
||||
.fixed_options = true,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_arm_axi = {
|
||||
.reg_offset = pl011_std_offsets,
|
||||
.ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
|
||||
.fr_busy = UART01x_FR_BUSY,
|
||||
.fr_dsr = UART01x_FR_DSR,
|
||||
.fr_cts = UART01x_FR_CTS,
|
||||
.fr_ri = UART011_FR_RI,
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
.always_enabled = false,
|
||||
.fixed_options = false,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_SPCR_TABLE
|
||||
static const struct vendor_data vendor_qdt_qdf2400_e44 = {
|
||||
.reg_offset = pl011_std_offsets,
|
||||
@@ -480,6 +494,12 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
"RX DMA disabled - no residue processing\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* DMA controllers with smaller burst capabilities than 1/4
|
||||
* the FIFO depth will leave more bytes than expected in the
|
||||
* RX FIFO if mismatched.
|
||||
*/
|
||||
rx_conf.src_maxburst = min(caps.max_burst, rx_conf.src_maxburst);
|
||||
}
|
||||
dmaengine_slave_config(chan, &rx_conf);
|
||||
uap->dmarx.chan = chan;
|
||||
@@ -3080,6 +3100,87 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int pl011_axi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_amba_port *uap;
|
||||
struct vendor_data *vendor = &vendor_arm_axi;
|
||||
struct resource *r;
|
||||
unsigned int periphid;
|
||||
int portnr, ret, irq;
|
||||
|
||||
portnr = pl011_find_free_port();
|
||||
if (portnr < 0)
|
||||
return portnr;
|
||||
|
||||
uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
|
||||
GFP_KERNEL);
|
||||
if (!uap)
|
||||
return -ENOMEM;
|
||||
|
||||
uap->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(uap->clk))
|
||||
return PTR_ERR(uap->clk);
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "cts-event-workaround")) {
|
||||
vendor->cts_event_workaround = true;
|
||||
dev_info(&pdev->dev, "cts_event_workaround enabled\n");
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
periphid = 0x00241011; /* A safe default */
|
||||
of_property_read_u32(pdev->dev.of_node, "arm,primecell-periphid",
|
||||
&periphid);
|
||||
|
||||
uap->reg_offset = vendor->reg_offset;
|
||||
uap->vendor = vendor;
|
||||
uap->fifosize = (AMBA_REV_BITS(periphid) < 3) ? 16 : 32;
|
||||
uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
|
||||
uap->port.irq = irq;
|
||||
uap->port.ops = &amba_pl011_pops;
|
||||
uap->port.rs485_config = pl011_rs485_config;
|
||||
uap->port.rs485_supported = pl011_rs485_supported;
|
||||
|
||||
snprintf(uap->type, sizeof(uap->type), "PL011 AXI");
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, uap);
|
||||
|
||||
return pl011_register_port(uap);
|
||||
}
|
||||
|
||||
static void pl011_axi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_amba_port *uap = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&amba_reg, &uap->port);
|
||||
pl011_unregister_port(uap);
|
||||
}
|
||||
|
||||
static const struct of_device_id pl011_axi_of_match[] = {
|
||||
{ .compatible = "arm,pl011-axi" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pl011_axi_of_match);
|
||||
|
||||
static struct platform_driver pl011_axi_platform_driver = {
|
||||
.probe = pl011_axi_probe,
|
||||
.remove = pl011_axi_remove,
|
||||
.driver = {
|
||||
.name = "pl011-axi",
|
||||
.pm = &pl011_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(pl011_axi_of_match),
|
||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct amba_id pl011_ids[] = {
|
||||
{
|
||||
.id = 0x00041011,
|
||||
@@ -3113,12 +3214,15 @@ static int __init pl011_init(void)
|
||||
|
||||
if (platform_driver_register(&arm_sbsa_uart_platform_driver))
|
||||
pr_warn("could not register SBSA UART platform driver\n");
|
||||
if (platform_driver_register(&pl011_axi_platform_driver))
|
||||
pr_warn("could not register PL011 AXI platform driver\n");
|
||||
return amba_driver_register(&pl011_driver);
|
||||
}
|
||||
|
||||
static void __exit pl011_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&arm_sbsa_uart_platform_driver);
|
||||
platform_driver_unregister(&pl011_axi_platform_driver);
|
||||
amba_driver_unregister(&pl011_driver);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user