summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-07-31 11:38:56 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-01 11:13:58 +0200
commita7cd4b737c1120382c4fae826c61306761ee0b23 (patch)
tree413c6160338509f5843936772975ab6ff5b8e7a1
parentserial/ns16550: Use standard register names (diff)
downloadrtems-a7cd4b737c1120382c4fae826c61306761ee0b23.tar.bz2
serial/ns16550: Precision clock synthesizer
Set the FIFO control register while DLAB == 1 in the line control register. At least on the QorIQ T4240 the driver still works with the re-ordered FIFO control register access.
-rw-r--r--bsps/include/libchip/ns16550.h1
-rw-r--r--bsps/shared/dev/serial/ns16550-context.c80
2 files changed, 68 insertions, 13 deletions
diff --git a/bsps/include/libchip/ns16550.h b/bsps/include/libchip/ns16550.h
index 4f1b98bf0b..f053c8767f 100644
--- a/bsps/include/libchip/ns16550.h
+++ b/bsps/include/libchip/ns16550.h
@@ -69,6 +69,7 @@ typedef struct {
uint32_t clock;
uint32_t initial_baud;
bool has_fractional_divider_register;
+ bool has_precision_clock_synthesizer;
uint8_t modem_control;
uint8_t line_control;
uint32_t baud_divisor;
diff --git a/bsps/shared/dev/serial/ns16550-context.c b/bsps/shared/dev/serial/ns16550-context.c
index 5f5ef27c77..a783edc2e6 100644
--- a/bsps/shared/dev/serial/ns16550-context.c
+++ b/bsps/shared/dev/serial/ns16550-context.c
@@ -53,20 +53,52 @@
static uint32_t NS16550_GetBaudDivisor(ns16550_context *ctx, uint32_t baud)
{
- uint32_t clock = ctx->clock;
- uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
+ uint32_t clock;
+ uint32_t baudDivisor;
+ uint32_t err;
+ uint32_t actual;
+ uint32_t newErr;
+
+ if (ctx->clock != 0) {
+ clock = ctx->clock;
+ } else {
+ clock = 115200;
+ }
+
+ baudDivisor = clock / (baud * 16);
+
+ if (ctx->has_precision_clock_synthesizer) {
+ uint32_t i;
- if (ctx->has_fractional_divider_register) {
+ err = baud;
+ baudDivisor = 0x0001ffff;
+
+ for (i = 2; i <= 0x10000; i *= 2) {
+ uint32_t fout;
+ uint32_t fin;
+
+ fin = i - 1;
+ fout = (baud * fin * 16) / clock;
+ actual = (clock * fout) / (16 * fin);
+ newErr = actual > baud ? actual - baud : baud - actual;
+
+ if (newErr < err) {
+ err = newErr;
+ baudDivisor = fin | (fout << 16);
+ }
+ }
+ } else if (ctx->has_fractional_divider_register) {
uint32_t fractionalDivider = 0x10;
- uint32_t err = baud;
uint32_t mulVal;
uint32_t divAddVal;
+ err = baud;
clock /= 16 * baudDivisor;
+
for (mulVal = 1; mulVal < 16; ++mulVal) {
for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
- uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
- uint32_t newErr = actual > baud ? actual - baud : baud - actual;
+ actual = (mulVal * clock) / (mulVal + divAddVal);
+ newErr = actual > baud ? actual - baud : baud - actual;
if (newErr < err) {
err = newErr;
@@ -159,19 +191,35 @@ bool ns16550_probe(rtems_termios_device_context *base)
(uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
);
- /* Clear the divisor latch and set the character size to eight bits */
- /* with one stop bit and no parity checking. */
- ucDataByte = EIGHT_BITS;
- ctx->line_control = ucDataByte;
- (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
-
/* Enable and reset transmit and receive FIFOs. TJA */
ucDataByte = SP_FIFO_ENABLE;
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
+
+ if (ctx->has_precision_clock_synthesizer) {
+ /*
+ * Enable precision clock synthesizer. This must be done with DLAB == 1 in
+ * the line control register.
+ */
+ ucDataByte |= 0x10;
+ }
+
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
+ /* Clear the divisor latch and set the character size to eight bits */
+ /* with one stop bit and no parity checking. */
+ ucDataByte = EIGHT_BITS;
+ ctx->line_control = ucDataByte;
+
+ if (ctx->has_precision_clock_synthesizer) {
+ (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 24));
+ (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte );
+ (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 16));
+ } else {
+ (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+ }
+
ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
/* Set data terminal ready. */
@@ -666,7 +714,13 @@ static bool ns16550_set_attributes(
/*
* Now write the line control
*/
- (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
+ if (ctx->has_precision_clock_synthesizer) {
+ (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 24));
+ (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
+ (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 16));
+ } else {
+ (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
+ }
rtems_termios_device_lock_release(base, &lock_context);
}