Files
OpenCellular/chip/g/uartn.c
Mary Ruthven f9368ac88e g: remove buffering on ap and ec uart
We wanted to reduce the number of interrupts that uart was producing so
we increased the number of characters needed in the fifos before it
would trigger an interrupt. Right now it needs 4 characters. If you
aren't printing a multiple of four characters, then not all text will be
printed.

This change changes the rxilvl back to 1. This will make using the
consoles and testing cr50 functionality more reliable.

BUG=chrome-os-partner:62158
BRANCH=none
TEST=login and boot still work fine. The AP and EC consoles print all
output correctly.

Change-Id: I2d48d02a275173d560c03e5363845a5afc94df7a
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/434891
Reviewed-by: Scott Collyer <scollyer@chromium.org>
2017-01-31 17:07:40 -08:00

163 lines
3.9 KiB
C

/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "clock.h"
#include "common.h"
#include "gpio.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "uart.h"
#include "util.h"
#define USE_UART_INTERRUPTS (!(defined(CONFIG_CUSTOMIZED_RO) && \
defined(SECTION_IS_RO)))
struct uartn_interrupts {
int tx_int;
int rx_int;
};
static struct uartn_interrupts interrupt[] = {
{GC_IRQNUM_UART0_TXINT, GC_IRQNUM_UART0_RXINT},
{GC_IRQNUM_UART1_TXINT, GC_IRQNUM_UART1_RXINT},
{GC_IRQNUM_UART2_TXINT, GC_IRQNUM_UART2_RXINT},
};
void uartn_tx_start(int uart)
{
if (!uart_init_done())
return;
/* If interrupt is already enabled, nothing to do */
if (GR_UART_ICTRL(uart) & GC_UART_ICTRL_TX_MASK)
return;
/* Do not allow deep sleep while transmit in progress */
disable_sleep(SLEEP_MASK_UART);
/*
* Re-enable the transmit interrupt, then forcibly trigger the
* interrupt. This works around a hardware problem with the
* UART where the FIFO only triggers the interrupt when its
* threshold is _crossed_, not just met.
*/
/* TODO(crosbug.com/p/33819): Do we need this hack here? Find out. */
REG_WRITE_MLV(GR_UART_ICTRL(uart), GC_UART_ICTRL_TX_MASK,
GC_UART_ICTRL_TX_LSB, 1);
task_trigger_irq(interrupt[uart].tx_int);
}
void uartn_tx_stop(int uart)
{
/* Disable the TX interrupt */
REG_WRITE_MLV(GR_UART_ICTRL(uart), GC_UART_ICTRL_TX_MASK,
GC_UART_ICTRL_TX_LSB, 0);
/* Re-allow deep sleep */
enable_sleep(SLEEP_MASK_UART);
}
int uartn_tx_in_progress(int uart)
{
/* Transmit is in progress unless the TX FIFO is empty and idle. */
return !(GR_UART_STATE(uart) & (GC_UART_STATE_TXIDLE_MASK |
GC_UART_STATE_TXEMPTY_MASK));
}
void uartn_tx_flush(int uart)
{
timestamp_t ts;
int i;
/* Wait until TX FIFO is idle. */
while (uartn_tx_in_progress(uart))
;
/*
* Even when uartn_tx_in_progress() returns false, the chip seems to
* be still trasmitting, resetting at this point results in an eaten
* last symbol. Let's just wait some time (required to transmit 10
* bits at 115200 baud).
*/
ts = get_time(); /* Start time. */
for (i = 0; i < 1000; i++) /* Limit it in case timer is not running. */
if ((get_time().val - ts.val) > ((1000000 * 10) / 115200))
return;
}
int uartn_tx_ready(int uart)
{
/* True if the TX buffer is not completely full */
return !(GR_UART_STATE(uart) & GC_UART_STATE_TX_MASK);
}
int uartn_rx_available(int uart)
{
/* True if the RX buffer is not completely empty. */
return !(GR_UART_STATE(uart) & GC_UART_STATE_RXEMPTY_MASK);
}
void uartn_write_char(int uart, char c)
{
/* Wait for space in transmit FIFO. */
while (!uartn_tx_ready(uart))
;
GR_UART_WDATA(uart) = c;
}
int uartn_read_char(int uart)
{
return GR_UART_RDATA(uart);
}
void uartn_disable_interrupt(int uart)
{
task_disable_irq(interrupt[uart].tx_int);
task_disable_irq(interrupt[uart].rx_int);
}
void uartn_enable_interrupt(int uart)
{
task_enable_irq(interrupt[uart].tx_int);
task_enable_irq(interrupt[uart].rx_int);
}
void uartn_enable(int uart)
{
/* Enable TX and RX. Disable HW flow control and loopback. */
GR_UART_CTRL(uart) = 0x03;
}
/* Disable TX, RX, HW flow control, and loopback */
void uartn_disable(int uart)
{
GR_UART_CTRL(uart) = 0;
}
void uartn_init(int uart)
{
long long setting = (16 * (1 << UART_NCO_WIDTH) *
(long long)CONFIG_UART_BAUD_RATE / PCLK_FREQ);
/* set frequency */
GR_UART_NCO(uart) = setting;
/*
* Interrupt when RX fifo has anything, when TX fifo <= half
* empty and reset (clear) both FIFOs
*/
GR_UART_FIFO(uart) = 0x63;
/* enable RX interrupts in block */
/* Note: doesn't do anything unless turned on in NVIC */
GR_UART_ICTRL(uart) = 0x02;
#if USE_UART_INTERRUPTS
/* Enable interrupts for UART */
uartn_enable_interrupt(uart);
#endif
}