uart/ns16550: support divisor latch fraction (DLF)

The UART on Quark SE and D2000 supports fractional clock divider.
It is used to limit frequency error for supported baud rates.

Change-Id: I1f39a95db09f4a5a4116edc700a10e4b9ecfa2bd
Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2016-01-06 09:17:02 -08:00 committed by Anas Nashif
parent 0ad859aaf3
commit b9c70ce76a
5 changed files with 58 additions and 18 deletions

View file

@ -67,6 +67,9 @@ endif # PINMUX
if UART_NS16550
config UART_NS16550_DLF
def_bool y
config UART_NS16550_PORT_0
def_bool y
@ -86,6 +89,8 @@ config UART_NS16550_PORT_0_CLK_FREQ
default 32000000
config UART_NS16550_PORT_0_OPTIONS
default 0
config UART_NS16550_PORT_0_DLF
default 0x06
endif # UART_NS16550_PORT_0
@ -108,6 +113,8 @@ config UART_NS16550_PORT_1_CLK_FREQ
default 32000000
config UART_NS16550_PORT_1_OPTIONS
default 0
config UART_NS16550_PORT_1_DLF
default 0x06
endif # UART_NS16550_PORT_1

View file

@ -48,17 +48,9 @@ static int quark_d2000_init(struct device *arg)
/* enable clock gating */
#ifdef CONFIG_UART_NS16550_PORT_0
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 17);
*((unsigned char *)(CONFIG_UART_NS16550_PORT_0_BASE_ADDR
+ SYNOPSIS_UART_DLF_OFFSET)) =
COM1_DLF;
#endif
#ifdef CONFIG_UART_NS16550_PORT_1
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 18);
*((unsigned char *)(CONFIG_UART_NS16550_PORT_1_BASE_ADDR
+ SYNOPSIS_UART_DLF_OFFSET)) =
COM2_DLF;
#endif
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 1);
#endif /* CONFIG_UART_NS16550 */

View file

@ -115,14 +115,6 @@ struct scss_interrupt {
#define LOAPIC_IRQ_COUNT 1
#define LOAPIC_LVT_REG_SPACING 0x10
/* serial port (aka COM port) information */
#define SYNOPSIS_UART_DLF_OFFSET 0xc0
#define SYNOPSIS_UART_DLF_115200_VAL 0x06
#define COM1_DLF SYNOPSIS_UART_DLF_115200_VAL
#define COM2_DLF SYNOPSIS_UART_DLF_115200_VAL
/* UART uses level triggered interrupt, low level */
#define UART_IOAPIC_FLAGS (IOAPIC_LEVEL)

View file

@ -37,6 +37,16 @@ choice
endchoice
config UART_NS16550_DLF
bool "Enable Divisor Latch Fraction (DLF) support"
default n
depends on UART_NS16550 && UART_NS16550_ACCESS_MMIO
help
This enables support for divisor latch fraction (DLF).
It is used to limit frequency error.
Says n if you are not sure if hardware supports this.
# ---------- Port 0 ----------
menuconfig UART_NS16550_PORT_0
@ -108,6 +118,13 @@ config UART_NS16550_PORT_0_OPTIONS
help
Options used for port initialization.
config UART_NS16550_PORT_0_DLF
hex "Port 0 DLF value"
default 0x0
depends on UART_NS16550_PORT_0 && UART_NS16550_DLF
help
Value for DLF register.
config UART_NS16550_PORT_0_PCI
bool "Port 0 is PCI-based"
default n
@ -237,6 +254,13 @@ config UART_NS16550_PORT_1_OPTIONS
help
Options used for port initialization.
config UART_NS16550_PORT_1_DLF
hex "Port 1 DLF value"
default 0x0
depends on UART_NS16550_PORT_1 && UART_NS16550_DLF
help
Value for DLF register.
config UART_NS16550_PORT_1_PCI
bool "Port 1 is PCI-based"
default n

View file

@ -59,6 +59,7 @@
#define REG_MDC 0x04 /* Modem control reg. */
#define REG_LSR 0x05 /* Line status reg. */
#define REG_MSR 0x06 /* Modem status reg. */
#define REG_DLF 0xC0 /* Divisor Latch Fraction */
/* equates for interrupt enable register */
@ -183,6 +184,7 @@
#define MDC(dev) (DEV_CFG(dev)->port + REG_MDC * UART_REG_ADDR_INTERVAL)
#define LSR(dev) (DEV_CFG(dev)->port + REG_LSR * UART_REG_ADDR_INTERVAL)
#define MSR(dev) (DEV_CFG(dev)->port + REG_MSR * UART_REG_ADDR_INTERVAL)
#define DLF(dev) (DEV_CFG(dev)->port + REG_DLF)
#define IIRC(dev) (DEV_DATA(dev)->iir_cache)
@ -201,10 +203,21 @@
/** Device data structure */
struct uart_ns16550_dev_data_t {
uint8_t iir_cache; /**< cache of IIR since it clears when read */
uint8_t dlf; /**< DLF value */
};
static struct uart_driver_api uart_ns16550_driver_api;
#ifdef CONFIG_UART_NS16550_DLF
static inline void set_dlf(struct device *dev, uint32_t val)
{
struct uart_ns16550_dev_data_t * const dev_data = DEV_DATA(dev);
OUTBYTE(DLF(dev), val);
dev_data->dlf = val;
}
#endif
#if defined(CONFIG_UART_NS16550_PCI)
static inline int ns16550_pci_uart_scan(struct device *dev)
@ -274,6 +287,10 @@ static int uart_ns16550_init(struct device *dev)
OUTBYTE(BRDH(dev), (unsigned char)((divisor >> 8) & 0xff));
}
#ifdef CONFIG_UART_NS16550_DLF
set_dlf(dev, dev_data->dlf);
#endif
/* 8 data bits, 1 stop bit, no parity, clear DLAB */
OUTBYTE(LCR(dev), LCR_CS8 | LCR_1_STB | LCR_PDIS);
@ -576,7 +593,11 @@ struct uart_device_config uart_ns16550_dev_cfg_0 = {
#endif /* CONFIG_UART_NS16550_PORT_0_PCI */
};
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_0;
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_0 = {
#ifdef CONFIG_UART_NS16550_PORT_0_DLF
.dlf = CONFIG_UART_NS16550_PORT_0_DLF,
#endif
};
DECLARE_DEVICE_INIT_CONFIG(uart_ns16550_0,
CONFIG_UART_NS16550_PORT_0_NAME,
@ -610,7 +631,11 @@ struct uart_device_config uart_ns16550_dev_cfg_1 = {
#endif /* CONFIG_UART_NS16550_PORT_1_PCI */
};
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_1;
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_1 = {
#ifdef CONFIG_UART_NS16550_PORT_1_DLF
.dlf = CONFIG_UART_NS16550_PORT_1_DLF,
#endif
};
DECLARE_DEVICE_INIT_CONFIG(uart_ns16550_1,
CONFIG_UART_NS16550_PORT_1_NAME,