// SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2020, Broadcom */ /* * 8250-core based driver for Broadcom ns16550a UARTs * * This driver uses the standard 8250 driver core but adds additional * optional features including the ability to use a baud rate clock * mux for more accurate high speed baud rate selection and also * an optional DMA engine. *
*/
staticvoid udma_writel(struct brcmuart_priv *priv, int reg_type, int offset, u32 value)
{
writel(value, priv->regs[reg_type] + offset);
}
staticvoid udma_set(struct brcmuart_priv *priv, int reg_type, int offset, u32 bits)
{ void __iomem *reg = priv->regs[reg_type] + offset;
u32 value;
value = readl(reg);
value |= bits;
writel(value, reg);
}
staticvoid udma_unset(struct brcmuart_priv *priv, int reg_type, int offset, u32 bits)
{ void __iomem *reg = priv->regs[reg_type] + offset;
u32 value;
value = readl(reg);
value &= ~bits;
writel(value, reg);
}
/* * The UART DMA engine hardware can be used by multiple UARTS, but * only one at a time. Sharing is not currently supported so * the first UART to request the DMA engine will get it and any * subsequent requests by other UARTS will fail.
*/ staticint brcmuart_arbitration(struct brcmuart_priv *priv, bool acquire)
{
u32 rx_grant;
u32 tx_grant; int waits; int ret = 0;
/* * Setup buffer close to happen when 32 character times have * elapsed since the last character was received.
*/
udma_writel(priv, REGS_DMA_RX, UDMA_RX_BUFFER_CLOSE, 16*10*32);
value = (RX_BUFS_COUNT << UDMA_RX_CTRL_NUM_BUF_USED_SHIFT)
| UDMA_RX_CTRL_BUF_CLOSE_MODE
| UDMA_RX_CTRL_BUF_CLOSE_ENA;
udma_writel(priv, REGS_DMA_RX, UDMA_RX_CTRL, value);
udma_writel(priv, REGS_DMA_RX, UDMA_RX_BLOCKOUT_COUNTER, 0);
daddr = priv->rx_addr; for (x = 0; x < RX_BUFS_COUNT; x++) {
/* Set RX transfer length to 0 for unknown */
udma_writel(priv, REGS_DMA_RX, UDMA_RX_TRANSFER_LEN, 0);
/* Clear the RX ready bit for all buffers */ for (x = 0; x < RX_BUFS_COUNT; x++)
udma_unset(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(x),
UDMA_RX_BUFX_STATUS_DATA_RDY);
/* If TX is running, set the TX ABORT */
value = udma_readl(priv, REGS_DMA_TX, UDMA_TX_CTRL); if (value & UDMA_TX_CTRL_ENA)
udma_set(priv, REGS_DMA_TX, UDMA_TX_CTRL, UDMA_TX_CTRL_ABORT);
priv->tx_running = false; return 0;
}
/* * NOTE: printk's in this routine will hang the system if this is * the console tty
*/ staticint brcmuart_tx_dma(struct uart_8250_port *p)
{ struct brcmuart_priv *priv = p->port.private_data; struct tty_port *tport = &p->port.state->port;
u32 tx_size;
if (uart_tx_stopped(&p->port) || priv->tx_running ||
kfifo_is_empty(&tport->xmit_fifo)) { return 0;
}
/* Make sure we're still in sync with the hardware */
status = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_STATUS(index));
length = udma_readl(priv, REGS_DMA_RX, UDMA_RX_BUFx_DATA_LEN(index));
if ((status & UDMA_RX_BUFX_STATUS_DATA_RDY) == 0) {
dev_err(up->dev, "RX done interrupt but DATA_RDY not found\n"); return;
} if (status & (UDMA_RX_BUFX_STATUS_OVERRUN_ERR |
UDMA_RX_BUFX_STATUS_FRAME_ERR |
UDMA_RX_BUFX_STATUS_PARITY_ERR)) { if (status & UDMA_RX_BUFX_STATUS_OVERRUN_ERR) {
up->icount.overrun++;
dev_warn(up->dev, "RX OVERRUN Error\n");
} if (status & UDMA_RX_BUFX_STATUS_FRAME_ERR) {
up->icount.frame++;
dev_warn(up->dev, "RX FRAMING Error\n");
} if (status & UDMA_RX_BUFX_STATUS_PARITY_ERR) {
up->icount.parity++;
dev_warn(up->dev, "RX PARITY Error\n");
}
}
copied = (u32)tty_insert_flip_string(
tty_port,
priv->rx_bufs + (index * RX_BUF_SIZE),
length); if (copied != length) {
dev_warn(up->dev, "Flip buffer overrun of %d bytes\n",
length - copied);
up->icount.overrun += length - copied;
}
up->icount.rx += length; if (status & UDMA_RX_BUFX_STATUS_CLOSE_EXPIRED)
priv->dma_rx_partial_buf++; elseif (length != RX_BUF_SIZE) /* * This is a bug in the controller that doesn't cause * any problems but will be fixed in the future.
*/
priv->rx_missing_close_timeout++; else
priv->dma_rx_full_buf++;
res = serial8250_do_startup(port); if (!priv->dma_enabled) return res; /* * Disable the Receive Data Interrupt because the DMA engine * will handle this. * * Synchronize UART_IER access against the console.
*/
uart_port_lock_irq(port);
up->ier &= ~UART_IER_RDI;
serial_port_out(port, UART_IER, up->ier);
uart_port_unlock_irq(port);
/* * Not all clocks run at the exact specified rate, so set each requested * rate and then get the actual rate.
*/ staticvoid init_real_clk_rates(struct device *dev, struct brcmuart_priv *priv)
{ int x; int rc;
/* If the Baud Mux Clock was not specified, just return */ if (priv->baud_mux_clk == NULL) return;
/* Try default_mux_rate first */
quot = find_quot(up->dev, priv->default_mux_rate, baud, &percent); if (quot) {
best_percent = percent;
best_freq = priv->default_mux_rate;
best_quot = quot;
} /* If more than 1% error, find the closest match for specified baud */ if (best_percent > 100) { for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) {
freq = priv->real_rates[i]; if (freq == 0 || freq == priv->default_mux_rate) continue;
quot = find_quot(up->dev, freq, baud, &percent); if (!quot) continue;
if (percent < best_percent) {
best_percent = percent;
best_freq = freq;
best_quot = quot;
}
}
} if (!best_freq) {
dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud); return;
}
rc = clk_set_rate(priv->baud_mux_clk, best_freq); if (rc)
dev_err(up->dev, "Error selecting BAUD MUX clock\n");
/* Error over 3 percent will cause data errors */ if (best_percent > 300)
dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n",
baud, percent / 100, percent % 100);
/* calc nanoseconds for 1.5 characters time at the given baud rate */
i = NSEC_PER_SEC / real_baud / 10;
i += (i / 2);
priv->char_wait = ns_to_ktime(i);
/* * There's a bug in some 8250 cores where we get a timeout * interrupt but there is no data ready.
*/ if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT) && !(priv->shutdown)) {
uart_port_lock_irqsave(p, &flags);
status = serial_port_in(p, UART_LSR); if ((status & UART_LSR_DR) == 0) {
ier = serial_port_in(p, UART_IER); /* * if Receive Data Interrupt is enabled and * we're uing hardware flow control, deassert * RTS and wait for any chars in the pipeline to * arrive and then check for DR again.
*/ if ((ier & UART_IER_RDI) && (up->mcr & UART_MCR_AFE)) {
ier &= ~(UART_IER_RLSI | UART_IER_RDI);
serial_port_out(p, UART_IER, ier);
mcr = serial_port_in(p, UART_MCR);
mcr &= ~UART_MCR_RTS;
serial_port_out(p, UART_MCR, mcr);
hrtimer_start(&priv->hrt, priv->char_wait,
HRTIMER_MODE_REL);
} else {
serial_port_in(p, UART_RX);
}
uart_port_lock_irqsave(p, &flags);
status = serial_port_in(p, UART_LSR);
/* * If a character did not arrive after the timeout, clear the false * receive timeout.
*/ if ((status & UART_LSR_DR) == 0) {
serial_port_in(p, UART_RX);
priv->rx_bad_timeout_no_char++;
} else {
priv->rx_bad_timeout_late_char++;
}
/* re-enable receive unless upper layer has disabled it */ if ((up->ier & (UART_IER_RLSI | UART_IER_RDI)) ==
(UART_IER_RLSI | UART_IER_RDI)) {
status = serial_port_in(p, UART_IER);
status |= (UART_IER_RLSI | UART_IER_RDI);
serial_port_out(p, UART_IER, status);
status = serial_port_in(p, UART_MCR);
status |= UART_MCR_RTS;
serial_port_out(p, UART_MCR, status);
}
uart_port_unlock_irqrestore(p, flags); return HRTIMER_NORESTART;
}
for (x = 0; x < REGS_MAX; x++) {
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM,
reg_names[x]); if (!regs) break;
priv->regs[x] = devm_ioremap(dev, regs->start,
resource_size(regs)); if (!priv->regs[x]) return -ENOMEM; if (x == REGS_8250) {
mapbase = regs->start;
membase = priv->regs[x];
}
}
/* We should have just the uart base registers or all the registers */ if (x != 1 && x != REGS_MAX) return dev_err_probe(dev, -EINVAL, "%s registers not specified\n",
reg_names[x]);
/* if the DMA registers were specified, try to enable DMA */ if (x > REGS_DMA_RX) { if (brcmuart_arbitration(priv, 1) == 0) {
u32 txrev = 0;
u32 rxrev = 0;
/* See if a Baud clock has been specified */
baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud");
ret = PTR_ERR_OR_ZERO(baud_mux_clk); if (ret) goto release_dma; if (baud_mux_clk) {
dev_dbg(dev, "BAUD MUX clock found\n");
/* * This will prevent resume from enabling RTS before the * baud rate has been restored.
*/
uart_port_lock_irqsave(port, &flags);
priv->saved_mctrl = port->mctrl;
port->mctrl &= ~TIOCM_RTS;
uart_port_unlock_irqrestore(port, flags);
ret = clk_prepare_enable(priv->baud_mux_clk); if (ret)
dev_err(dev, "Error enabling BAUD MUX clock\n");
/* * The hardware goes back to it's default after suspend * so get the "clk" back in sync.
*/
ret = clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate); if (ret)
dev_err(dev, "Error restoring default BAUD MUX clock\n"); if (priv->dma_enabled) { if (brcmuart_arbitration(priv, 1)) {
dev_err(dev, "Timeout arbitrating for DMA hardware on resume\n"); return(-EBUSY);
}
brcmuart_init_dma_hardware(priv);
start_rx_dma(serial8250_get_port(priv->line));
}
serial8250_resume_port(priv->line);
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.