uart: ns16550: support Apollo Lake PRV_CLOCK_PARAMS (PCP) register
The UARTs on the Apollo Lake SoCs have PLLs that feed the baud rate generators. This patch allows a user to specify custom M/N values for those PLLs when custom/high-speed baud rates are required. I'm not entirely satisfied with the way the PCP values are configured, because it requires tweaking data in both Kconfig and DeviceTree. For the time being I've merely taken my cue from another similar feature (the DLF register support) and have punted on figuring out the "right way" to expose UART configuration to the application. Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
parent
b5578d8de3
commit
5dd1bf15fc
2 changed files with 111 additions and 12 deletions
|
@ -25,6 +25,16 @@ config UART_NS16550_DLF
|
|||
|
||||
Says n if you are not sure if hardware supports this.
|
||||
|
||||
config UART_NS16550_PCP
|
||||
bool "Enable Apollo Lake PRV_CLOCK_PARAMS (PCP) support"
|
||||
depends on SOC_APOLLO_LAKE && UART_NS16550
|
||||
help
|
||||
This enables configuration of the clock blocks that feed
|
||||
the UARTs on Apollo Lake SoCs, allowing the generation of
|
||||
custom baud rates.
|
||||
|
||||
Say n unless you know you need this feature.
|
||||
|
||||
config UART_NS16550_LINE_CTRL
|
||||
bool "Enable Serial Line Control for Apps"
|
||||
depends on UART_LINE_CTRL && UART_NS16550
|
||||
|
@ -99,6 +109,16 @@ config UART_NS16550_PORT_0_DLF
|
|||
help
|
||||
Value for DLF register.
|
||||
|
||||
config UART_NS16550_PORT_0_PCP
|
||||
hex "Port 0 PCP value"
|
||||
default 0
|
||||
depends on UART_NS16550_PORT_0 && UART_NS16550_PCP
|
||||
help
|
||||
Value for PRV_CLOCK_PARAMS register. If left at its default
|
||||
value (0), then the kernel will not attempt to set the PCP
|
||||
for this UART; otherwise be sure the device tree for this
|
||||
port has sys_clk_freq set accordingly.
|
||||
|
||||
config UART_NS16550_PORT_0_PCI
|
||||
bool "Port 0 is PCI-based"
|
||||
depends on UART_NS16550_PCI && UART_NS16550_PORT_0
|
||||
|
@ -156,6 +176,16 @@ config UART_NS16550_PORT_1_DLF
|
|||
help
|
||||
Value for DLF register.
|
||||
|
||||
config UART_NS16550_PORT_1_PCP
|
||||
hex "Port 1 PCP value"
|
||||
default 0
|
||||
depends on UART_NS16550_PORT_1 && UART_NS16550_PCP
|
||||
help
|
||||
Value for PRV_CLOCK_PARAMS register. If left at its default
|
||||
value (0), then the kernel will not attempt to set the PCP
|
||||
for this UART; otherwise be sure the device tree for this
|
||||
port has sys_clk_freq set accordingly.
|
||||
|
||||
config UART_NS16550_PORT_1_PCI
|
||||
bool "Port 1 is PCI-based"
|
||||
depends on UART_NS16550_PCI && UART_NS16550_PORT_1
|
||||
|
@ -186,6 +216,16 @@ config UART_NS16550_PORT_2_DLF
|
|||
help
|
||||
Value for DLF register.
|
||||
|
||||
config UART_NS16550_PORT_2_PCP
|
||||
hex "Port 2 PCP value"
|
||||
default 0
|
||||
depends on UART_NS16550_PORT_2 && UART_NS16550_PCP
|
||||
help
|
||||
Value for PRV_CLOCK_PARAMS register. If left at its default
|
||||
value (0), then the kernel will not attempt to set the PCP
|
||||
for this UART; otherwise be sure the device tree for this
|
||||
port has sys_clk_freq set accordingly.
|
||||
|
||||
config UART_NS16550_PORT_2_PCI
|
||||
bool "Port 2 is PCI-based"
|
||||
depends on UART_NS16550_PCI && UART_NS16550_PORT_2
|
||||
|
@ -215,6 +255,16 @@ config UART_NS16550_PORT_3_DLF
|
|||
help
|
||||
Value for DLF register.
|
||||
|
||||
config UART_NS16550_PORT_3_PCP
|
||||
hex "Port 3 PCP value"
|
||||
default 0
|
||||
depends on UART_NS16550_PORT_3 && UART_NS16550_PCP
|
||||
help
|
||||
Value for PRV_CLOCK_PARAMS register. If left at its default
|
||||
value (0), then the kernel will not attempt to set the PCP
|
||||
for this UART; otherwise be sure the device tree for this
|
||||
port has sys_clk_freq set accordingly.
|
||||
|
||||
config UART_NS16550_PORT_3_PCI
|
||||
bool "Port 3 is PCI-based"
|
||||
depends on UART_NS16550_PCI && UART_NS16550_PORT_3
|
||||
|
|
|
@ -42,18 +42,19 @@
|
|||
|
||||
/* register definitions */
|
||||
|
||||
#define REG_THR 0x00 /* Transmitter holding reg. */
|
||||
#define REG_RDR 0x00 /* Receiver data reg. */
|
||||
#define REG_BRDL 0x00 /* Baud rate divisor (LSB) */
|
||||
#define REG_BRDH 0x01 /* Baud rate divisor (MSB) */
|
||||
#define REG_IER 0x01 /* Interrupt enable reg. */
|
||||
#define REG_IIR 0x02 /* Interrupt ID reg. */
|
||||
#define REG_FCR 0x02 /* FIFO control reg. */
|
||||
#define REG_LCR 0x03 /* Line control reg. */
|
||||
#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 */
|
||||
#define REG_THR 0x00 /* Transmitter holding reg. */
|
||||
#define REG_RDR 0x00 /* Receiver data reg. */
|
||||
#define REG_BRDL 0x00 /* Baud rate divisor (LSB) */
|
||||
#define REG_BRDH 0x01 /* Baud rate divisor (MSB) */
|
||||
#define REG_IER 0x01 /* Interrupt enable reg. */
|
||||
#define REG_IIR 0x02 /* Interrupt ID reg. */
|
||||
#define REG_FCR 0x02 /* FIFO control reg. */
|
||||
#define REG_LCR 0x03 /* Line control reg. */
|
||||
#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 */
|
||||
#define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */
|
||||
|
||||
/* equates for interrupt enable register */
|
||||
|
||||
|
@ -78,6 +79,11 @@
|
|||
#define FCR_RCVRCLR 0x02 /* clear RCVR FIFO */
|
||||
#define FCR_XMITCLR 0x04 /* clear XMIT FIFO */
|
||||
|
||||
/* equates for Apollo Lake clock control register (PRV_CLOCK_PARAMS) */
|
||||
|
||||
#define PCP_UPDATE 0x80000000 /* update clock */
|
||||
#define PCP_EN 0x00000001 /* enable clock output */
|
||||
|
||||
/*
|
||||
* Per PC16550D (Literature Number: SNLS378B):
|
||||
*
|
||||
|
@ -187,6 +193,7 @@
|
|||
#define LSR(dev) (DEV_DATA(dev)->port + REG_LSR * UART_REG_ADDR_INTERVAL)
|
||||
#define MSR(dev) (DEV_DATA(dev)->port + REG_MSR * UART_REG_ADDR_INTERVAL)
|
||||
#define DLF(dev) (DEV_DATA(dev)->port + REG_DLF)
|
||||
#define PCP(dev) (DEV_DATA(dev)->port + REG_PCP)
|
||||
|
||||
#define IIRC(dev) (DEV_DATA(dev)->iir_cache)
|
||||
|
||||
|
@ -196,13 +203,17 @@
|
|||
|
||||
#ifdef UART_NS16550_ACCESS_IOPORT
|
||||
#define INBYTE(x) sys_in8(x)
|
||||
#define INWORD(x) sys_in32(x)
|
||||
#define OUTBYTE(x, d) sys_out8(d, x)
|
||||
#define OUTWORD(x, d) sys_out32(d, x)
|
||||
#ifndef UART_REG_ADDR_INTERVAL
|
||||
#define UART_REG_ADDR_INTERVAL 1 /* address diff of adjacent regs. */
|
||||
#endif /* UART_REG_ADDR_INTERVAL */
|
||||
#else
|
||||
#define INBYTE(x) sys_read8(x)
|
||||
#define INWORD(x) sys_read32(x)
|
||||
#define OUTBYTE(x, d) sys_write8(d, x)
|
||||
#define OUTWORD(x, d) sys_write32(d, x)
|
||||
#ifndef UART_REG_ADDR_INTERVAL
|
||||
#define UART_REG_ADDR_INTERVAL 4 /* address diff of adjacent regs. */
|
||||
#endif
|
||||
|
@ -215,6 +226,10 @@ struct uart_ns16550_device_config {
|
|||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
uart_irq_config_func_t irq_config_func;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PCP
|
||||
u32_t pcp;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Device data structure */
|
||||
|
@ -250,6 +265,20 @@ static inline void set_dlf(struct device *dev, u32_t val)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PCP
|
||||
static inline void set_pcp(struct device *dev)
|
||||
{
|
||||
const struct uart_ns16550_device_config * const dev_cfg = DEV_CFG(dev);
|
||||
u32_t pcp = dev_cfg->pcp;
|
||||
|
||||
if (pcp) {
|
||||
pcp |= PCP_EN;
|
||||
OUTWORD(PCP(dev), pcp & ~PCP_UPDATE);
|
||||
OUTWORD(PCP(dev), pcp | PCP_UPDATE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_baud_rate(struct device *dev, u32_t baud_rate)
|
||||
{
|
||||
const struct uart_ns16550_device_config * const dev_cfg = DEV_CFG(dev);
|
||||
|
@ -339,6 +368,10 @@ static int uart_ns16550_init(struct device *dev)
|
|||
set_dlf(dev, dev_data->dlf);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PCP
|
||||
set_pcp(dev);
|
||||
#endif
|
||||
|
||||
set_baud_rate(dev, dev_data->baud_rate);
|
||||
|
||||
/* 8 data bits, 1 stop bit, no parity, clear DLAB */
|
||||
|
@ -765,6 +798,10 @@ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_0 = {
|
|||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.irq_config_func = irq_config_func_0,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PORT_0_PCP
|
||||
.pcp = CONFIG_UART_NS16550_PORT_0_PCP
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_0 = {
|
||||
|
@ -819,6 +856,10 @@ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_1 = {
|
|||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.irq_config_func = irq_config_func_1,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PORT_1_PCP
|
||||
.pcp = CONFIG_UART_NS16550_PORT_1_PCP
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_1 = {
|
||||
|
@ -873,6 +914,10 @@ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_2 = {
|
|||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.irq_config_func = irq_config_func_2,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PORT_2_PCP
|
||||
.pcp = CONFIG_UART_NS16550_PORT_2_PCP
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_2 = {
|
||||
|
@ -927,6 +972,10 @@ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_3 = {
|
|||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.irq_config_func = irq_config_func_3,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_PORT_3_PCP
|
||||
.pcp = CONFIG_UART_NS16550_PORT_3_PCP
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_ns16550_dev_data_t uart_ns16550_dev_data_3 = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue