/** * struct tegra_uart_chip_data: SOC specific data. * * @tx_fifo_full_status: Status flag available for checking tx fifo full. * @allow_txfifo_reset_fifo_mode: allow_tx fifo reset with fifo mode or not. * Tegra30 does not allow this. * @support_clk_src_div: Clock source support the clock divider. * @fifo_mode_enable_status: Is FIFO mode enabled? * @uart_max_port: Maximum number of UART ports * @max_dma_burst_bytes: Maximum size of DMA bursts * @error_tolerance_low_range: Lowest number in the error tolerance range * @error_tolerance_high_range: Highest number in the error tolerance range
*/ struct tegra_uart_chip_data { bool tx_fifo_full_status; bool allow_txfifo_reset_fifo_mode; bool support_clk_src_div; bool fifo_mode_enable_status; int uart_max_port; int max_dma_burst_bytes; int error_tolerance_low_range; int error_tolerance_high_range;
};
/* * RI - Ring detector is active * CD/DCD/CAR - Carrier detect is always active. For some reason * linux has different names for carrier detect. * DSR - Data Set ready is active as the hardware doesn't support it. * Don't know if the linux support this yet? * CTS - Clear to send. Always set to active, as the hardware handles * CTS automatically.
*/ if (tup->enable_modem_interrupt) return TIOCM_RI | TIOCM_CD | TIOCM_DSR | TIOCM_CTS; return TIOCM_CTS;
}
/** * tegra_uart_wait_cycle_time: Wait for N UART clock periods * * @tup: Tegra serial port data structure. * @cycles: Number of clock periods to wait. * * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART * clock speed is 16X the current baud rate.
*/ staticvoid tegra_uart_wait_cycle_time(struct tegra_uart_port *tup, unsignedint cycles)
{ if (tup->current_baud)
udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16));
}
/* Wait for a symbol-time. */ staticvoid tegra_uart_wait_sym_time(struct tegra_uart_port *tup, unsignedint syms)
{ if (tup->current_baud)
udelay(DIV_ROUND_UP(syms * tup->symb_bit * 1000000,
tup->current_baud));
}
/* Dummy read to ensure the write is posted */
tegra_uart_read(tup, UART_SCR);
/* * For all tegra devices (up to t210), there is a hardware issue that * requires software to wait for 32 UART clock periods for the flush * to propagate, otherwise data could be lost.
*/
tegra_uart_wait_cycle_time(tup, 32);
do {
lsr = tegra_uart_read(tup, UART_LSR); if ((lsr & UART_LSR_TEMT) && !(lsr & UART_LSR_DR)) break;
udelay(1);
} while (--tmout);
if (tup->rts_active)
set_rts(tup, true);
}
staticlong tegra_get_tolerance_rate(struct tegra_uart_port *tup, unsignedint baud, long rate)
{ int i;
for (i = 0; i < tup->n_adjustable_baud_rates; ++i) { if (baud >= tup->baud_tolerance[i].lower_range_baud &&
baud <= tup->baud_tolerance[i].upper_range_baud) return (rate + (rate *
tup->baud_tolerance[i].tolerance) / 10000);
}
return rate;
}
staticint tegra_check_rate_in_range(struct tegra_uart_port *tup)
{ long diff;
diff = ((long)(tup->configured_rate - tup->required_rate) * 10000)
/ tup->required_rate; if (diff < (tup->cdata->error_tolerance_low_range * 100) ||
diff > (tup->cdata->error_tolerance_high_range * 100)) {
dev_err(tup->uport.dev, "configured baud rate is out of range by %ld", diff); return -EIO;
}
tup->tx_dma_desc = dmaengine_prep_slave_single(tup->tx_dma_chan,
tx_phys_addr, tup->tx_bytes, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT); if (!tup->tx_dma_desc) {
dev_err(tup->uport.dev, "Not able to get desc for Tx\n"); return -EIO;
}
tup->rx_dma_desc = dmaengine_prep_slave_single(tup->rx_dma_chan,
tup->rx_dma_buf_phys, count, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT); if (!tup->rx_dma_desc) {
dev_err(tup->uport.dev, "Not able to get desc for Rx\n"); return -EIO;
}
msr = tegra_uart_read(tup, UART_MSR); if (!(msr & UART_MSR_ANY_DELTA)) return;
if (msr & UART_MSR_TERI)
tup->uport.icount.rng++; if (msr & UART_MSR_DDSR)
tup->uport.icount.dsr++; /* We may only get DDCD when HW init and reset */ if (msr & UART_MSR_DDCD)
uart_handle_dcd_change(&tup->uport, msr & UART_MSR_DCD); /* Will start/stop_tx accordingly */ if (msr & UART_MSR_DCTS)
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
}
switch ((iir >> 1) & 0x7) { case 0: /* Modem signal change interrupt */
tegra_uart_handle_modem_signal_change(u); break;
case 1: /* Transmit interrupt only triggered when using PIO */
tup->ier_shadow &= ~UART_IER_THRI;
tegra_uart_write(tup, tup->ier_shadow, UART_IER);
tegra_uart_handle_tx_pio(tup); break;
case 4: /* End of data */ case 6: /* Rx timeout */ if (!tup->use_rx_pio) {
is_rx_int = tup->rx_in_progress; /* Disable Rx interrupts */
ier = tup->ier_shadow;
ier &= ~(UART_IER_RDI | UART_IER_RLSI |
UART_IER_RTOIE | TEGRA_UART_IER_EORD);
tup->ier_shadow = ier;
tegra_uart_write(tup, ier, UART_IER); break;
}
fallthrough; case 2: /* Receive */ if (!tup->use_rx_pio) {
is_rx_start = tup->rx_in_progress;
tup->ier_shadow &= ~UART_IER_RDI;
tegra_uart_write(tup, tup->ier_shadow,
UART_IER);
} else {
do_handle_rx_pio(tup);
} break;
case 3: /* Receive error */
tegra_uart_decode_rx_error(tup,
tegra_uart_read(tup, UART_LSR)); break;
case 5: /* break nothing to handle */ case 7: /* break nothing to handle */ break;
}
}
}
ret = clk_prepare_enable(tup->uart_clk); if (ret) {
dev_err(tup->uport.dev, "could not enable clk\n"); return ret;
}
/* Reset the UART controller to clear all previous status.*/
reset_control_assert(tup->rst);
udelay(10);
reset_control_deassert(tup->rst);
tup->rx_in_progress = 0;
tup->tx_in_progress = 0;
/* * Set the trigger level * * For PIO mode: * * For receive, this will interrupt the CPU after that many number of * bytes are received, for the remaining bytes the receive timeout * interrupt is received. Rx high watermark is set to 4. * * For transmit, if the trasnmit interrupt is enabled, this will * interrupt the CPU when the number of entries in the FIFO reaches the * low watermark. Tx low watermark is set to 16 bytes. * * For DMA mode: * * Set the Tx trigger to 16. This should match the DMA burst size that * programmed in the DMA registers.
*/
tup->fcr_shadow = UART_FCR_ENABLE_FIFO;
/* Dummy read to ensure the write is posted */
tegra_uart_read(tup, UART_SCR);
if (tup->cdata->fifo_mode_enable_status) {
ret = tegra_uart_wait_fifo_mode_enabled(tup); if (ret < 0) {
clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev, "Failed to enable FIFO mode: %d\n", ret); return ret;
}
} else { /* * For all tegra devices (up to t210), there is a hardware * issue that requires software to wait for 3 UART clock * periods after enabling the TX fifo, otherwise data could * be lost.
*/
tegra_uart_wait_cycle_time(tup, 3);
}
/* * Initialize the UART with default configuration * (115200, N, 8, 1) so that the receive DMA buffer may be * enqueued
*/
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); if (ret < 0) {
clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev, "Failed to set baud rate\n"); return ret;
} if (!tup->use_rx_pio) {
tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR;
tup->fcr_shadow |= UART_FCR_DMA_SELECT;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
} else {
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
}
tup->rx_in_progress = 1;
/* * Enable IE_RXS for the receive status interrupts like line errors. * Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd. * * EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when * the DATA is sitting in the FIFO and couldn't be transferred to the * DMA as the DMA size alignment (4 bytes) is not met. EORD will be * triggered when there is a pause of the incomming data stream for 4 * characters long. * * For pauses in the data which is not aligned to 4 bytes, we get * both the EORD as well as RX_TIMEOUT - SW sees RX_TIMEOUT first * then the EORD.
*/
tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | UART_IER_RDI;
/* * If using DMA mode, enable EORD interrupt to notify about RX * completion.
*/ if (!tup->use_rx_pio)
tup->ier_shadow |= TEGRA_UART_IER_EORD;
if (!tup->use_tx_pio) {
ret = tegra_uart_dma_channel_allocate(tup, false); if (ret < 0) {
dev_err(u->dev, "Tx Dma allocation failed, err = %d\n",
ret); return ret;
}
}
if (!tup->use_rx_pio) {
ret = tegra_uart_dma_channel_allocate(tup, true); if (ret < 0) {
dev_err(u->dev, "Rx Dma allocation failed, err = %d\n",
ret); goto fail_rx_dma;
}
}
ret = tegra_uart_hw_init(tup); if (ret < 0) {
dev_err(u->dev, "Uart HW init failed, err = %d\n", ret); goto fail_hw_init;
}
ret = request_irq(u->irq, tegra_uart_isr, 0,
dev_name(u->dev), tup); if (ret < 0) {
dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); goto fail_request_irq;
} return 0;
fail_request_irq: /* tup->uart_clk is already enabled in tegra_uart_hw_init */
clk_disable_unprepare(tup->uart_clk);
fail_hw_init: if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, true);
fail_rx_dma: if (!tup->use_tx_pio)
tegra_uart_dma_channel_free(tup, false); return ret;
}
/* * Flush any TX data submitted for DMA and PIO. Called when the * TX circular buffer is reset.
*/ staticvoid tegra_uart_flush_buffer(struct uart_port *u)
{ struct tegra_uart_port *tup = to_tegra_uport(u);
tup->tx_bytes = 0; if (tup->tx_dma_chan)
dmaengine_terminate_all(tup->tx_dma_chan);
}
/* Changing configuration, it is safe to stop any rx now */ if (tup->rts_active)
set_rts(tup, false);
/* Clear all interrupts as configuration is going to be changed */
tegra_uart_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER);
tegra_uart_read(tup, UART_IER);
tegra_uart_write(tup, 0, UART_IER);
tegra_uart_read(tup, UART_IER);
/* Baud rate. */
baud = uart_get_baud_rate(u, termios, oldtermios,
parent_clk_rate/max_divider,
parent_clk_rate/16);
uart_port_unlock_irqrestore(u, flags);
ret = tegra_set_baudrate(tup, baud); if (ret < 0) {
dev_err(tup->uport.dev, "Failed to set baud rate\n"); return;
} if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
uart_port_lock_irqsave(u, &flags);
/* Flow control */ if (termios->c_cflag & CRTSCTS) {
tup->mcr_shadow |= TEGRA_UART_MCR_CTS_EN;
tup->mcr_shadow &= ~TEGRA_UART_MCR_RTS_EN;
tegra_uart_write(tup, tup->mcr_shadow, UART_MCR); /* if top layer has asked to set rts active then do so here */ if (tup->rts_active)
set_rts(tup, true);
} else {
tup->mcr_shadow &= ~TEGRA_UART_MCR_CTS_EN;
tup->mcr_shadow &= ~TEGRA_UART_MCR_RTS_EN;
tegra_uart_write(tup, tup->mcr_shadow, UART_MCR);
}
/* update the port timeout based on new settings */
uart_update_timeout(u, termios->c_cflag, baud);
/* Make sure all writes have completed */
tegra_uart_read(tup, UART_IER);
tup->uport.ignore_status_mask = 0; /* Ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0)
tup->uport.ignore_status_mask |= UART_LSR_DR; if (termios->c_iflag & IGNBRK)
tup->uport.ignore_status_mask |= UART_LSR_BI;
staticint tegra_uart_parse_dt(struct platform_device *pdev, struct tegra_uart_port *tup)
{ struct device_node *np = pdev->dev.of_node; int port; int ret; int index;
u32 pval; int count; int n_entries;
port = of_alias_get_id(np, "serial"); if (port < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); return port;
}
tup->uport.line = port;
index = of_property_match_string(np, "dma-names", "rx"); if (index < 0) {
tup->use_rx_pio = true;
dev_info(&pdev->dev, "RX in PIO mode\n");
}
index = of_property_match_string(np, "dma-names", "tx"); if (index < 0) {
tup->use_tx_pio = true;
dev_info(&pdev->dev, "TX in PIO mode\n");
}
n_entries = of_property_count_u32_elems(np, "nvidia,adjust-baud-rates"); if (n_entries > 0) {
tup->n_adjustable_baud_rates = n_entries / 3;
tup->baud_tolerance =
devm_kzalloc(&pdev->dev, (tup->n_adjustable_baud_rates) * sizeof(*tup->baud_tolerance), GFP_KERNEL); if (!tup->baud_tolerance) return -ENOMEM; for (count = 0, index = 0; count < n_entries; count += 3,
index++) {
ret =
of_property_read_u32_index(np, "nvidia,adjust-baud-rates",
count, &pval); if (!ret)
tup->baud_tolerance[index].lower_range_baud =
pval;
ret =
of_property_read_u32_index(np, "nvidia,adjust-baud-rates",
count + 1, &pval); if (!ret)
tup->baud_tolerance[index].upper_range_baud =
pval;
ret =
of_property_read_u32_index(np, "nvidia,adjust-baud-rates",
count + 2, &pval); if (!ret)
tup->baud_tolerance[index].tolerance =
(s32)pval;
}
} else {
tup->n_adjustable_baud_rates = 0;
}
tup->uart_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tup->uart_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(tup->uart_clk), "Couldn't get the clock");
tup->rst = devm_reset_control_get_exclusive(&pdev->dev, "serial"); if (IS_ERR(tup->rst)) {
dev_err(&pdev->dev, "Couldn't get the reset\n"); return PTR_ERR(tup->rst);
}
u->iotype = UPIO_MEM32;
ret = platform_get_irq(pdev, 0); if (ret < 0) return ret;
u->irq = ret;
u->regshift = 2;
ret = uart_add_one_port(&tegra_uart_driver, u); if (ret < 0) {
dev_err(&pdev->dev, "Failed to add uart port, err %d\n", ret); return ret;
} return ret;
}
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.