drivers: serial: ns16550: Enable simultaneous support of IO, MMIO and PCIe
Enabled simultaneous support by adding a DTS variable named “io-mapped”. There are 3 possibilities through instance in dtsi file. Under PCIe, PCIe ns16550. Under soc and has a variable io-mapped, legacy(IO mapped). Under soc and don’t have a variable io-mapped, MMIO mapped. Simultaneous access can be enabled by a Kconfig. For PCIe instances UART initialization should be done post-kernel as it depends on PCIe initialization. Co-authored-by: Najumon BA <najumon.ba@intel.com> Signed-off-by: Anisetti Avinash Krishna <anisetti.avinash.krishna@intel.com>
This commit is contained in:
parent
4978a651a7
commit
26133e995d
|
@ -66,6 +66,12 @@ config UART_NS16550_ACCESS_IOPORT
|
|||
When enabled, NS16550 will not be a memory mapped device. This option
|
||||
must be selected at SoC/board level if needed.
|
||||
|
||||
config UART_NS16550_SIMULT_ACCESS
|
||||
bool
|
||||
help
|
||||
When enabled, NS16550 supports IO, MMIO, PCIe UART devices simultaneously.
|
||||
For io-mapped instances, io-mapped DTS property need to be added in dtsi.
|
||||
|
||||
menu "NS16550 Workarounds"
|
||||
|
||||
config UART_NS16550_WA_ISR_REENABLE_INTERRUPT
|
||||
|
|
|
@ -204,32 +204,12 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
|
|||
|
||||
#define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache)
|
||||
|
||||
#ifdef CONFIG_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)
|
||||
#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)
|
||||
#endif /* CONFIG_UART_NS16550_ACCESS_IOPORT */
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_ACCESS_WORD_ONLY
|
||||
#undef INBYTE
|
||||
#define INBYTE(x) INWORD(x)
|
||||
#undef OUTBYTE
|
||||
#define OUTBYTE(x, d) OUTWORD(x, d)
|
||||
#endif
|
||||
|
||||
/* device config */
|
||||
struct uart_ns16550_device_config {
|
||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||
DEVICE_MMIO_ROM;
|
||||
#else
|
||||
uint32_t port;
|
||||
#endif
|
||||
union {
|
||||
DEVICE_MMIO_ROM;
|
||||
uint32_t port;
|
||||
};
|
||||
uint32_t sys_clk_freq;
|
||||
const struct device *clock_dev;
|
||||
clock_control_subsys_t clock_subsys;
|
||||
|
@ -246,13 +226,14 @@ struct uart_ns16550_device_config {
|
|||
#if defined(CONFIG_PINCTRL)
|
||||
const struct pinctrl_dev_config *pincfg;
|
||||
#endif
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
bool io_map;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Device data structure */
|
||||
struct uart_ns16550_dev_data {
|
||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||
DEVICE_MMIO_RAM;
|
||||
#endif
|
||||
struct uart_config uart_config;
|
||||
struct k_spinlock lock;
|
||||
uint8_t fifo_size;
|
||||
|
@ -272,6 +253,82 @@ struct uart_ns16550_dev_data {
|
|||
#endif
|
||||
};
|
||||
|
||||
static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg,
|
||||
uintptr_t port, uint8_t val)
|
||||
{
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
if (cfg->io_map) {
|
||||
if (IS_ENABLED(CONFIG_UART_NS16550_ACCESS_WORD_ONLY)) {
|
||||
sys_out32(val, port);
|
||||
} else {
|
||||
sys_out8(val, port);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
/* MMIO mapped */
|
||||
if (IS_ENABLED(CONFIG_UART_NS16550_ACCESS_WORD_ONLY)) {
|
||||
sys_write32(val, port);
|
||||
} else {
|
||||
sys_write8(val, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t ns16550_inbyte(const struct uart_ns16550_device_config *cfg,
|
||||
uintptr_t port)
|
||||
{
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
if (cfg->io_map) {
|
||||
if (IS_ENABLED(CONFIG_UART_NS16550_ACCESS_WORD_ONLY)) {
|
||||
return sys_in32(port);
|
||||
} else {
|
||||
return sys_in8(port);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
/* MMIO mapped */
|
||||
if (IS_ENABLED(CONFIG_UART_NS16550_ACCESS_WORD_ONLY)) {
|
||||
return sys_read32(port);
|
||||
} else {
|
||||
return sys_read8(port);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if UART_NS16550_PCP_ENABLED
|
||||
static void ns16550_outword(const struct uart_ns16550_device_config *cfg,
|
||||
uintptr_t port, uint32_t val)
|
||||
{
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
if (cfg->io_map) {
|
||||
sys_out32(val, port);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
/* MMIO mapped */
|
||||
sys_write32(val, port);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ns16550_inword(const struct uart_ns16550_device_config *cfg,
|
||||
uintptr_t port)
|
||||
{
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
if (cfg->io_map) {
|
||||
return sys_in32(port);
|
||||
}
|
||||
#endif
|
||||
/* MMIO mapped */
|
||||
return sys_read32(port);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t reg_interval(const struct device *dev)
|
||||
{
|
||||
const struct uart_ns16550_device_config *config = dev->config;
|
||||
|
@ -283,18 +340,26 @@ static const struct uart_driver_api uart_ns16550_driver_api;
|
|||
|
||||
static inline uintptr_t get_port(const struct device *dev)
|
||||
{
|
||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||
return DEVICE_MMIO_GET(dev);
|
||||
#else
|
||||
uintptr_t port;
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
const struct uart_ns16550_device_config *config = dev->config;
|
||||
|
||||
return config->port;
|
||||
if (config->io_map) {
|
||||
port = config->port;
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
port = DEVICE_MMIO_GET(dev);
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t pclk)
|
||||
{
|
||||
struct uart_ns16550_dev_data * const dev_data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
uint32_t divisor; /* baud rate divisor */
|
||||
uint8_t lcr_cache;
|
||||
|
||||
|
@ -307,13 +372,13 @@ static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t
|
|||
/ baud_rate) >> 4;
|
||||
|
||||
/* set the DLAB to access the baud rate divisor registers */
|
||||
lcr_cache = INBYTE(LCR(dev));
|
||||
OUTBYTE(LCR(dev), LCR_DLAB | lcr_cache);
|
||||
OUTBYTE(BRDL(dev), (unsigned char)(divisor & 0xff));
|
||||
OUTBYTE(BRDH(dev), (unsigned char)((divisor >> 8) & 0xff));
|
||||
lcr_cache = ns16550_inbyte(dev_cfg, LCR(dev));
|
||||
ns16550_outbyte(dev_cfg, LCR(dev), LCR_DLAB | lcr_cache);
|
||||
ns16550_outbyte(dev_cfg, BRDL(dev), (unsigned char)(divisor & 0xff));
|
||||
ns16550_outbyte(dev_cfg, BRDH(dev), (unsigned char)((divisor >> 8) & 0xff));
|
||||
|
||||
/* restore the DLAB to access the baud rate divisor registers */
|
||||
OUTBYTE(LCR(dev), lcr_cache);
|
||||
ns16550_outbyte(dev_cfg, LCR(dev), lcr_cache);
|
||||
|
||||
dev_data->uart_config.baudrate = baud_rate;
|
||||
}
|
||||
|
@ -343,7 +408,7 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
#endif
|
||||
|
||||
#if UART_NS16550_DLF_ENABLED
|
||||
OUTBYTE(DLF(dev), dev_data->dlf);
|
||||
ns16550_outbyte(dev_cfg, DLF(dev), dev_data->dlf);
|
||||
#endif
|
||||
|
||||
#if UART_NS16550_PCP_ENABLED
|
||||
|
@ -351,8 +416,8 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
|
||||
if (pcp) {
|
||||
pcp |= PCP_EN;
|
||||
OUTWORD(PCP(dev), pcp & ~PCP_UPDATE);
|
||||
OUTWORD(PCP(dev), pcp | PCP_UPDATE);
|
||||
ns16550_outbyte(dev_cfg, PCP(dev), pcp & ~PCP_UPDATE);
|
||||
ns16550_outbyte(dev_cfg, PCP(dev), pcp | PCP_UPDATE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -374,7 +439,7 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
|
||||
set_baud_rate(dev, cfg->baudrate, pclk);
|
||||
|
||||
/* Local structure to hold temporary values to pass to OUTBYTE() */
|
||||
/* Local structure to hold temporary values to pass to ns16550_outbyte() */
|
||||
struct uart_config uart_cfg;
|
||||
|
||||
switch (cfg->data_bits) {
|
||||
|
@ -422,8 +487,8 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
dev_data->uart_config = *cfg;
|
||||
|
||||
/* data bits, stop bits, parity, clear DLAB */
|
||||
OUTBYTE(LCR(dev),
|
||||
uart_cfg.data_bits | uart_cfg.stop_bits | uart_cfg.parity);
|
||||
ns16550_outbyte(dev_cfg, LCR(dev),
|
||||
uart_cfg.data_bits | uart_cfg.stop_bits | uart_cfg.parity);
|
||||
|
||||
mdc = MCR_OUT2 | MCR_RTS | MCR_DTR;
|
||||
#if defined(CONFIG_UART_NS16550_VARIANT_NS16750) || \
|
||||
|
@ -433,21 +498,21 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
}
|
||||
#endif
|
||||
|
||||
OUTBYTE(MDC(dev), mdc);
|
||||
ns16550_outbyte(dev_cfg, MDC(dev), mdc);
|
||||
|
||||
/*
|
||||
* Program FIFO: enabled, mode 0 (set for compatibility with quark),
|
||||
* generate the interrupt at 8th byte
|
||||
* Clear TX and RX FIFO
|
||||
*/
|
||||
OUTBYTE(FCR(dev),
|
||||
FCR_FIFO | FCR_MODE0 | FCR_FIFO_8 | FCR_RCVRCLR | FCR_XMITCLR
|
||||
ns16550_outbyte(dev_cfg, FCR(dev),
|
||||
FCR_FIFO | FCR_MODE0 | FCR_FIFO_8 | FCR_RCVRCLR | FCR_XMITCLR
|
||||
#ifdef CONFIG_UART_NS16550_VARIANT_NS16750
|
||||
| FCR_FIFO_64
|
||||
| FCR_FIFO_64
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
if ((INBYTE(IIR(dev)) & IIR_FE) == IIR_FE) {
|
||||
if ((ns16550_inbyte(dev_cfg, IIR(dev)) & IIR_FE) == IIR_FE) {
|
||||
#ifdef CONFIG_UART_NS16550_VARIANT_NS16750
|
||||
dev_data->fifo_size = 64;
|
||||
#elif defined(CONFIG_UART_NS16550_VARIANT_NS16950)
|
||||
|
@ -460,10 +525,10 @@ static int uart_ns16550_configure(const struct device *dev,
|
|||
}
|
||||
|
||||
/* clear the port */
|
||||
INBYTE(RDR(dev));
|
||||
ns16550_inbyte(dev_cfg, RDR(dev));
|
||||
|
||||
/* disable interrupts */
|
||||
OUTBYTE(IER(dev), 0x00);
|
||||
ns16550_outbyte(dev_cfg, IER(dev), 0x00);
|
||||
|
||||
out:
|
||||
k_spin_unlock(&dev_data->lock, key);
|
||||
|
@ -503,7 +568,6 @@ static int uart_ns16550_init(const struct device *dev)
|
|||
|
||||
ARG_UNUSED(dev_cfg);
|
||||
|
||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie)
|
||||
if (dev_cfg->pcie) {
|
||||
struct pcie_bar mbar;
|
||||
|
@ -520,10 +584,16 @@ static int uart_ns16550_init(const struct device *dev)
|
|||
} else
|
||||
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) */
|
||||
{
|
||||
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||
/* Map directly from DTS */
|
||||
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
||||
if (!dev_cfg->io_map) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
||||
}
|
||||
}
|
||||
#endif /* !UART_NS15660_ACCESS_IOPORT */
|
||||
|
||||
ret = uart_ns16550_configure(dev, &data->uart_config);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
|
@ -547,12 +617,13 @@ static int uart_ns16550_init(const struct device *dev)
|
|||
static int uart_ns16550_poll_in(const struct device *dev, unsigned char *c)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
int ret = -1;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
if ((INBYTE(LSR(dev)) & LSR_RXRDY) != 0) {
|
||||
if ((ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_RXRDY) != 0) {
|
||||
/* got a character */
|
||||
*c = INBYTE(RDR(dev));
|
||||
*c = ns16550_inbyte(dev_cfg, RDR(dev));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
@ -577,12 +648,13 @@ static void uart_ns16550_poll_out(const struct device *dev,
|
|||
unsigned char c)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
while ((INBYTE(LSR(dev)) & LSR_THRE) == 0) {
|
||||
while ((ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_THRE) == 0) {
|
||||
}
|
||||
|
||||
OUTBYTE(THR(dev), c);
|
||||
ns16550_outbyte(dev_cfg, THR(dev), c);
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -598,8 +670,9 @@ static void uart_ns16550_poll_out(const struct device *dev,
|
|||
static int uart_ns16550_err_check(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
int check = (INBYTE(LSR(dev)) & LSR_EOB_MASK);
|
||||
int check = (ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_EOB_MASK);
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
|
||||
|
@ -622,11 +695,12 @@ static int uart_ns16550_fifo_fill(const struct device *dev,
|
|||
int size)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
int i;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
for (i = 0; (i < size) && (i < data->fifo_size); i++) {
|
||||
OUTBYTE(THR(dev), tx_data[i]);
|
||||
ns16550_outbyte(dev_cfg, THR(dev), tx_data[i]);
|
||||
}
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
|
@ -647,11 +721,12 @@ static int uart_ns16550_fifo_read(const struct device *dev, uint8_t *rx_data,
|
|||
const int size)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
int i;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
for (i = 0; (i < size) && (INBYTE(LSR(dev)) & LSR_RXRDY) != 0; i++) {
|
||||
rx_data[i] = INBYTE(RDR(dev));
|
||||
for (i = 0; (i < size) && (ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_RXRDY) != 0; i++) {
|
||||
rx_data[i] = ns16550_inbyte(dev_cfg, RDR(dev));
|
||||
}
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
|
@ -667,6 +742,7 @@ static int uart_ns16550_fifo_read(const struct device *dev, uint8_t *rx_data,
|
|||
static void uart_ns16550_irq_tx_enable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM)
|
||||
|
@ -689,7 +765,7 @@ static void uart_ns16550_irq_tx_enable(const struct device *dev)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) | IER_TBE);
|
||||
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) | IER_TBE);
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -702,9 +778,11 @@ static void uart_ns16550_irq_tx_enable(const struct device *dev)
|
|||
static void uart_ns16550_irq_tx_disable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) & (~IER_TBE));
|
||||
ns16550_outbyte(dev_cfg, IER(dev),
|
||||
ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE));
|
||||
|
||||
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM)
|
||||
struct uart_ns16550_dev_data *const dev_data = dev->data;
|
||||
|
@ -758,9 +836,10 @@ static int uart_ns16550_irq_tx_ready(const struct device *dev)
|
|||
static int uart_ns16550_irq_tx_complete(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
int ret = ((INBYTE(LSR(dev)) & (LSR_TEMT | LSR_THRE))
|
||||
int ret = ((ns16550_inbyte(dev_cfg, LSR(dev)) & (LSR_TEMT | LSR_THRE))
|
||||
== (LSR_TEMT | LSR_THRE)) ? 1 : 0;
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
|
@ -776,9 +855,10 @@ static int uart_ns16550_irq_tx_complete(const struct device *dev)
|
|||
static void uart_ns16550_irq_rx_enable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) | IER_RXRDY);
|
||||
ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) | IER_RXRDY);
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -791,9 +871,11 @@ static void uart_ns16550_irq_rx_enable(const struct device *dev)
|
|||
static void uart_ns16550_irq_rx_disable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) & (~IER_RXRDY));
|
||||
ns16550_outbyte(dev_cfg, IER(dev),
|
||||
ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_RXRDY));
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -825,9 +907,11 @@ static int uart_ns16550_irq_rx_ready(const struct device *dev)
|
|||
static void uart_ns16550_irq_err_enable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) | IER_LSR);
|
||||
ns16550_outbyte(dev_cfg, IER(dev),
|
||||
ns16550_inbyte(dev_cfg, IER(dev)) | IER_LSR);
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -842,9 +926,11 @@ static void uart_ns16550_irq_err_enable(const struct device *dev)
|
|||
static void uart_ns16550_irq_err_disable(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
OUTBYTE(IER(dev), INBYTE(IER(dev)) & (~IER_LSR));
|
||||
ns16550_outbyte(dev_cfg, IER(dev),
|
||||
ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_LSR));
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
}
|
||||
|
@ -878,9 +964,10 @@ static int uart_ns16550_irq_is_pending(const struct device *dev)
|
|||
static int uart_ns16550_irq_update(const struct device *dev)
|
||||
{
|
||||
struct uart_ns16550_dev_data *data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||
|
||||
IIRC(dev) = INBYTE(IIR(dev));
|
||||
IIRC(dev) = ns16550_inbyte(dev_cfg, IIR(dev));
|
||||
|
||||
k_spin_unlock(&data->lock, key);
|
||||
|
||||
|
@ -922,10 +1009,11 @@ static void uart_ns16550_isr(const struct device *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT
|
||||
uint8_t cached_ier = INBYTE(IER(dev));
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
uint8_t cached_ier = ns16550_inbyte(dev_cfg, IER(dev));
|
||||
|
||||
OUTBYTE(IER(dev), 0U);
|
||||
OUTBYTE(IER(dev), cached_ier);
|
||||
ns16550_outbyte(dev_cfg, IER(dev), 0U);
|
||||
ns16550_outbyte(dev_cfg, IER(dev), cached_ier);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -966,7 +1054,7 @@ static int uart_ns16550_line_ctrl_set(const struct device *dev,
|
|||
case UART_LINE_CTRL_RTS:
|
||||
case UART_LINE_CTRL_DTR:
|
||||
key = k_spin_lock(&data->lock);
|
||||
mdc = INBYTE(MDC(dev));
|
||||
mdc = ns16550_inbyte(dev_cfg, MDC(dev));
|
||||
|
||||
if (ctrl == UART_LINE_CTRL_RTS) {
|
||||
chg = MCR_RTS;
|
||||
|
@ -979,7 +1067,7 @@ static int uart_ns16550_line_ctrl_set(const struct device *dev,
|
|||
} else {
|
||||
mdc &= ~(chg);
|
||||
}
|
||||
OUTBYTE(MDC(dev), mdc);
|
||||
ns16550_outbyte(dev_cfg, MDC(dev), mdc);
|
||||
k_spin_unlock(&data->lock, key);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1006,10 +1094,11 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd,
|
|||
#if UART_NS16550_DLF_ENABLED
|
||||
if (cmd == CMD_SET_DLF) {
|
||||
struct uart_ns16550_dev_data * const dev_data = dev->data;
|
||||
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
|
||||
|
||||
dev_data->dlf = p;
|
||||
OUTBYTE(DLF(dev), dev_data->dlf);
|
||||
ns16550_outbyte(dev_cfg, DLF(dev), dev_data->dlf);
|
||||
k_spin_unlock(&dev_data->lock, key);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1095,13 +1184,27 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
|
|||
}
|
||||
|
||||
#ifdef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||
#define DEV_CONFIG_REG_INIT(n) \
|
||||
.port = DT_INST_REG_ADDR(n),
|
||||
#define REG_INIT(n) \
|
||||
.port = DT_INST_REG_ADDR(n), \
|
||||
.io_map = true,
|
||||
#else
|
||||
#define DEV_CONFIG_REG_INIT_PCIE0(n) DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)),
|
||||
#define DEV_CONFIG_REG_INIT_PCIE1(n)
|
||||
#define DEV_CONFIG_REG_INIT(n) \
|
||||
_CONCAT(DEV_CONFIG_REG_INIT_PCIE, DT_INST_ON_BUS(n, pcie))(n)
|
||||
#define REG_INIT_PCIE1(n)
|
||||
#define REG_INIT_PCIE0(n) DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)),
|
||||
|
||||
#define DEV_REG_PORT_IO_1(n) \
|
||||
.port = DT_INST_REG_ADDR(n),
|
||||
#define DEV_REG_PORT_IO_0(n) \
|
||||
_CONCAT(REG_INIT_PCIE, DT_INST_ON_BUS(n, pcie))(n)
|
||||
#ifdef CONFIG_UART_NS16550_SIMULT_ACCESS
|
||||
#define DEV_IO_INIT(n) \
|
||||
.io_map = DT_INST_PROP(n, io_mapped),
|
||||
#else
|
||||
#define DEV_IO_INIT(n)
|
||||
#endif
|
||||
|
||||
#define REG_INIT(n) \
|
||||
_CONCAT(DEV_REG_PORT_IO_, DT_INST_PROP(n, io_mapped))(n) \
|
||||
DEV_IO_INIT(n)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
|
@ -1145,13 +1248,24 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
|
|||
#define DEV_DATA_DLF_INIT(n) \
|
||||
_CONCAT(DEV_DATA_DLF, DT_INST_NODE_HAS_PROP(n, dlf))(n)
|
||||
|
||||
/* UART on PCIe should be initialized POST_KERNEL as PCIe loads
|
||||
* as PRE_KERNEL_1 and these UART instances should not load before PCIe.
|
||||
* In some platforms legacy UART instance is used for console and
|
||||
* shell so it should load as PRE_KERNEL_1.
|
||||
*/
|
||||
#define DEV_BOOT_PRIO0(n) PRE_KERNEL_1
|
||||
#define DEV_BOOT_PRIO1(n) POST_KERNEL
|
||||
|
||||
#define NS16550_BOOT_PRIO(n) \
|
||||
_CONCAT(DEV_BOOT_PRIO, DT_INST_ON_BUS(n, pcie))(n)
|
||||
|
||||
#define UART_NS16550_DEVICE_INIT(n) \
|
||||
UART_NS16550_IRQ_FUNC_DECLARE(n); \
|
||||
DEV_PCIE_DECLARE(n); \
|
||||
IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \
|
||||
(PINCTRL_DT_INST_DEFINE(n))); \
|
||||
static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \
|
||||
DEV_CONFIG_REG_INIT(n) \
|
||||
REG_INIT(n) \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \
|
||||
.sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
|
||||
.clock_dev = NULL, \
|
||||
|
@ -1180,7 +1294,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
|
|||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \
|
||||
&uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \
|
||||
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
||||
NS16550_BOOT_PRIO(n), CONFIG_SERIAL_INIT_PRIORITY, \
|
||||
&uart_ns16550_driver_api); \
|
||||
UART_NS16550_IRQ_FUNC_DEFINE(n)
|
||||
|
||||
|
|
|
@ -17,3 +17,7 @@ properties:
|
|||
dlf:
|
||||
type: int
|
||||
description: divisor latch fraction (DLF, if supported)
|
||||
|
||||
io-mapped:
|
||||
type: boolean
|
||||
description: specify registers are IO mapped or memory mapped
|
||||
|
|
Loading…
Reference in a new issue