diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2012-06-14 14:27:58 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2012-06-15 15:59:32 +0200 |
commit | c39148d62fc891e26d9672e01e7b7eb372697335 (patch) | |
tree | 2eed1c4683bf544bb09835f70cb34d1fe34103da /c/src/libchip | |
parent | score: Fix performance issue for 64-bit timestamps (diff) | |
download | rtems-c39148d62fc891e26d9672e01e7b7eb372697335.tar.bz2 |
libchip: Add support for NS16550 with FDR
Diffstat (limited to 'c/src/libchip')
-rw-r--r-- | c/src/libchip/serial/ns16550.c | 56 | ||||
-rw-r--r-- | c/src/libchip/serial/ns16550_p.h | 8 | ||||
-rw-r--r-- | c/src/libchip/serial/serial.h | 2 |
3 files changed, 44 insertions, 22 deletions
diff --git a/c/src/libchip/serial/ns16550.c b/c/src/libchip/serial/ns16550.c index a8fdf983c7..3277b7ef0d 100644 --- a/c/src/libchip/serial/ns16550.c +++ b/c/src/libchip/serial/ns16550.c @@ -95,6 +95,40 @@ console_fns ns16550_fns_polled = { false /* deviceOutputUsesInterrupts */ }; +static uint32_t NS16550_GetBaudDivisor(const console_tbl *c, uint32_t baud) +{ + uint32_t clock = c->ulClock; + uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16); + + if (c->deviceType == SERIAL_NS16550_WITH_FDR) { + uint32_t fractionalDivider = 0x10; + uint32_t err = baud; + uint32_t mulVal; + uint32_t divAddVal; + + 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; + + if (newErr < err) { + err = newErr; + fractionalDivider = (mulVal << 4) | divAddVal; + } + } + } + + (*c->setRegister)( + c->ulCtrlPort1, + NS16550_FRACTIONAL_DIVIDER, + fractionalDivider + ); + } + + return baudDivisor; +} + /* * ns16550_init */ @@ -133,10 +167,7 @@ NS16550_STATIC void ns16550_init(int minor) /* Set the divisor latch and set the baud rate. */ - ulBaudDivisor = NS16550_Baud( - (uint32_t) c->ulClock, - (uint32_t) ((uintptr_t)c->pDeviceParams) - ); + ulBaudDivisor = NS16550_GetBaudDivisor(c, (uintptr_t) c->pDeviceParams); ucDataByte = SP_LINE_DLAB; (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte); @@ -413,23 +444,18 @@ NS16550_STATIC int ns16550_set_attributes( setRegister_f setReg; getRegister_f getReg; uint32_t Irql; + const console_tbl *c = Console_Port_Tbl [minor]; - pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1; - setReg = Console_Port_Tbl[minor]->setRegister; - getReg = Console_Port_Tbl[minor]->getRegister; + pNS16550 = c->ulCtrlPort1; + setReg = c->setRegister; + getReg = c->getRegister; /* * Calculate the baud rate divisor */ - baud_requested = t->c_cflag & CBAUD; - if (!baud_requested) - baud_requested = B9600; /* default to 9600 baud */ - - ulBaudDivisor = NS16550_Baud( - (uint32_t) Console_Port_Tbl[minor]->ulClock, - rtems_termios_baud_to_number(baud_requested) - ); + baud_requested = rtems_termios_baud_to_number(t->c_cflag); + ulBaudDivisor = NS16550_GetBaudDivisor(c, baud_requested); ucLineControl = 0; diff --git a/c/src/libchip/serial/ns16550_p.h b/c/src/libchip/serial/ns16550_p.h index be99cf1475..1e261612f2 100644 --- a/c/src/libchip/serial/ns16550_p.h +++ b/c/src/libchip/serial/ns16550_p.h @@ -49,6 +49,7 @@ extern "C" { #define NS16550_LINE_STATUS 5 #define NS16550_MODEM_STATUS 6 #define NS16550_SCRATCH_PAD 7 +#define NS16550_FRACTIONAL_DIVIDER 10 /* * Define serial port interrupt enable register structure. @@ -106,13 +107,6 @@ extern "C" { #define EIGHT_BITS 0x3 /* eight bits per character */ /* - * Line speed divisor definition. - */ - -#define NS16550_Baud(_clock, _baud_rate) \ - ((((_clock) == 0) ? 115200 : (_clock))/(_baud_rate*16)) - -/* * Define serial port modem control register structure. */ diff --git a/c/src/libchip/serial/serial.h b/c/src/libchip/serial/serial.h index 7fe1da4f3e..6faa4d34a0 100644 --- a/c/src/libchip/serial/serial.h +++ b/c/src/libchip/serial/serial.h @@ -104,6 +104,8 @@ typedef struct _console_flow { typedef enum { SERIAL_MC68681, /* Motorola MC68681 or Exar 88681 */ SERIAL_NS16550, /* National Semiconductor NS16550 */ + SERIAL_NS16550_WITH_FDR, /* National Semiconductor NS16550 + with Fractional Divider Register (FDR) */ SERIAL_Z85C30, /* Zilog Z85C30 */ SERIAL_CUSTOM /* BSP specific driver */ } console_devs; |