// SPDX-License-Identifier: GPL-2.0+ /* * Synopsys DesignWare 8250 driver. * * Copyright 2011 Picochip, Jamie Iles. * Copyright 2013 Intel Corporation * * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the * 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/clk.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/io.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/reset.h> #include <linux/slab.h> #include <linux/workqueue.h>
/* Override any modem control signals if needed */ if (offset == UART_MSR) {
value |= d->msr_mask_on;
value &= ~d->msr_mask_off;
}
return value;
}
/* * This function is being called as part of the uart_port::serial_out() * routine. Hence, it must not call serial_port_out() or serial_out() * against the modified registers here, i.e. LCR.
*/ staticvoid dw8250_force_idle(struct uart_port *p)
{ struct uart_8250_port *up = up_to_u8250p(p); unsignedint lsr;
/* * The following call currently performs serial_out() * against the FCR register. Because it differs to LCR * there will be no infinite loop, but if it ever gets * modified, we might need a new custom version of it * that avoids infinite recursion.
*/
serial8250_clear_and_reinit_fifos(up);
/* * With PSLVERR_RESP_EN parameter set to 1, the device generates an * error response when an attempt to read an empty RBR with FIFO * enabled.
*/ if (up->fcr & UART_FCR_ENABLE_FIFO) {
lsr = serial_port_in(p, UART_LSR); if (!(lsr & UART_LSR_DR)) return;
}
serial_port_in(p, UART_RX);
}
/* * This function is being called as part of the uart_port::serial_out() * routine. Hence, it must not call serial_port_out() or serial_out() * against the modified registers here, i.e. LCR.
*/ staticvoid dw8250_check_lcr(struct uart_port *p, unsignedint offset, u32 value)
{ struct dw8250_data *d = to_dw8250_data(p->private_data); void __iomem *addr = p->membase + (offset << p->regshift); int tries = 1000;
if (offset != UART_LCR || d->uart_16550_compatible) return;
/* Make sure LCR write wasn't ignored */ while (tries--) {
u32 lcr = serial_port_in(p, offset);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) return;
dw8250_force_idle(p);
#ifdef CONFIG_64BIT if (p->type == PORT_OCTEON)
__raw_writeq(value & 0xff, addr); else #endif if (p->iotype == UPIO_MEM32)
writel(value, addr); elseif (p->iotype == UPIO_MEM32BE)
iowrite32be(value, addr); else
writeb(value, addr);
} /* * FIXME: this deadlocks if port->lock is already held * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
*/
}
/* Returns once the transmitter is empty or we run out of retries */ staticvoid dw8250_tx_wait_empty(struct uart_port *p)
{ struct uart_8250_port *up = up_to_u8250p(p); unsignedint tries = 20000; unsignedint delay_threshold = tries - 1000; unsignedint lsr;
/* The device is first given a chance to empty without delay, * to avoid slowdowns at high bitrates. If after 1000 tries * the buffer has still not emptied, allow more time for low-
* speed links. */ if (tries < delay_threshold)
udelay (1);
}
}
staticvoid dw8250_serial_out38x(struct uart_port *p, unsignedint offset, u32 value)
{ /* Allow the TX to drain before we reconfigure */ if (offset == UART_LCR)
dw8250_tx_wait_empty(p);
/* * There are ways to get Designware-based UARTs into a state where * they are asserting UART_IIR_RX_TIMEOUT but there is no actual * data available. If we see such a case then we'll do a bogus * read. If we don't do this then the "RX TIMEOUT" interrupt will * fire forever. * * This problem has only been observed so far when not in DMA mode * so we limit the workaround only to non-DMA mode.
*/ if (!up->dma && rx_timeout) {
uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
uart_port_unlock_irqrestore(p, flags);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */ if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
uart_port_unlock_irqrestore(p, flags);
/* * We have no choice but to defer the uartclk update due to two * deadlocks. First one is caused by a recursive mutex lock which * happens when clk_set_rate() is called from dw8250_set_termios(). * Second deadlock is more tricky and is caused by an inverted order of * the clk and tty-port mutexes lock. It happens if clock rate change * is requested asynchronously while set_termios() is executed between * tty-port mutex lock and clk_set_rate() function invocation and * vise-versa. Anyway if we didn't have the reference clock alteration * in the dw8250_set_termios() method we wouldn't have needed this * deferred event handling complication.
*/ if (event == POST_RATE_CHANGE) {
queue_work(system_unbound_wq, &d->clk_work); return NOTIFY_OK;
}
clk_disable_unprepare(d->clk);
rate = clk_round_rate(d->clk, newrate); if (rate > 0) { /* * Note that any clock-notifier worker will block in * serial8250_update_uartclk() until we are done.
*/
ret = clk_set_rate(d->clk, newrate); if (!ret)
p->uartclk = rate;
}
clk_prepare_enable(d->clk);
/* * dw8250_fallback_dma_filter will prevent the UART from getting just any free * channel on platforms that have DMA engines, but don't have any channels * assigned to the UART. * * REVISIT: This is a work around for limitation in the DMA Engine API. Once the * core problem is fixed, this function is no longer needed.
*/ staticbool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param)
{ returnfalse;
}
if (device_property_read_bool(dev, "dcd-override")) { /* Always report DCD as active */
data->msr_mask_on |= UART_MSR_DCD;
data->msr_mask_off |= UART_MSR_DDCD;
}
if (device_property_read_bool(dev, "dsr-override")) { /* Always report DSR as active */
data->msr_mask_on |= UART_MSR_DSR;
data->msr_mask_off |= UART_MSR_DDSR;
}
if (device_property_read_bool(dev, "cts-override")) { /* Always report CTS as active */
data->msr_mask_on |= UART_MSR_CTS;
data->msr_mask_off |= UART_MSR_DCTS;
}
if (device_property_read_bool(dev, "ri-override")) { /* Always report Ring indicator as inactive */
data->msr_mask_off |= UART_MSR_RI;
data->msr_mask_off |= UART_MSR_TERI;
}
/* 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 dev_err_probe(dev, PTR_ERR(data->clk), "failed to get baudclk\n");
data->pdata = device_get_match_data(p->dev); if (data->pdata)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */ if (data->uart_16550_compatible)
p->handle_irq = NULL; elseif (data->pdata)
p->handle_irq = dw8250_handle_irq;
dw8250_setup_dma_filter(p, data);
if (!data->skip_autocfg)
dw8250_setup_port(p);
/* If we have a valid fifosize, try hooking up DMA */ if (p->fifosize) {
data->data.dma.rxconf.src_maxburst = p->fifosize / 4;
data->data.dma.txconf.dst_maxburst = p->fifosize / 4;
up->dma = &data->data.dma;
}
data->data.line = serial8250_register_8250_port(up); if (data->data.line < 0) return data->data.line;
/* * Some platforms may provide a reference clock shared between several * devices. In this case any clock state change must be known to the * UART port at least post factum.
*/ if (data->clk) {
err = clk_notifier_register(data->clk, &data->clk_notifier); if (err) return dev_err_probe(dev, err, "Failed to set the clock notifier\n");
queue_work(system_unbound_wq, &data->clk_work);
}
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
MODULE_ALIAS("platform:dw-apb-uart");
Messung V0.5
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.