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
3 changed files with 206 additions and 82 deletions
|
@ -66,6 +66,12 @@ config UART_NS16550_ACCESS_IOPORT
|
||||||
When enabled, NS16550 will not be a memory mapped device. This option
|
When enabled, NS16550 will not be a memory mapped device. This option
|
||||||
must be selected at SoC/board level if needed.
|
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"
|
menu "NS16550 Workarounds"
|
||||||
|
|
||||||
config UART_NS16550_WA_ISR_REENABLE_INTERRUPT
|
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)
|
#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 */
|
/* device config */
|
||||||
struct uart_ns16550_device_config {
|
struct uart_ns16550_device_config {
|
||||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
union {
|
||||||
DEVICE_MMIO_ROM;
|
DEVICE_MMIO_ROM;
|
||||||
#else
|
|
||||||
uint32_t port;
|
uint32_t port;
|
||||||
#endif
|
};
|
||||||
uint32_t sys_clk_freq;
|
uint32_t sys_clk_freq;
|
||||||
const struct device *clock_dev;
|
const struct device *clock_dev;
|
||||||
clock_control_subsys_t clock_subsys;
|
clock_control_subsys_t clock_subsys;
|
||||||
|
@ -246,13 +226,14 @@ struct uart_ns16550_device_config {
|
||||||
#if defined(CONFIG_PINCTRL)
|
#if defined(CONFIG_PINCTRL)
|
||||||
const struct pinctrl_dev_config *pincfg;
|
const struct pinctrl_dev_config *pincfg;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||||
|
bool io_map;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Device data structure */
|
/** Device data structure */
|
||||||
struct uart_ns16550_dev_data {
|
struct uart_ns16550_dev_data {
|
||||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
|
||||||
DEVICE_MMIO_RAM;
|
DEVICE_MMIO_RAM;
|
||||||
#endif
|
|
||||||
struct uart_config uart_config;
|
struct uart_config uart_config;
|
||||||
struct k_spinlock lock;
|
struct k_spinlock lock;
|
||||||
uint8_t fifo_size;
|
uint8_t fifo_size;
|
||||||
|
@ -272,6 +253,82 @@ struct uart_ns16550_dev_data {
|
||||||
#endif
|
#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)
|
static inline uint8_t reg_interval(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct uart_ns16550_device_config *config = dev->config;
|
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)
|
static inline uintptr_t get_port(const struct device *dev)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
uintptr_t port;
|
||||||
return DEVICE_MMIO_GET(dev);
|
#if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS)
|
||||||
#else
|
|
||||||
const struct uart_ns16550_device_config *config = dev->config;
|
const struct uart_ns16550_device_config *config = dev->config;
|
||||||
|
|
||||||
return config->port;
|
if (config->io_map) {
|
||||||
|
port = config->port;
|
||||||
|
} else {
|
||||||
|
#else
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
port = DEVICE_MMIO_GET(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t pclk)
|
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;
|
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 */
|
uint32_t divisor; /* baud rate divisor */
|
||||||
uint8_t lcr_cache;
|
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;
|
/ baud_rate) >> 4;
|
||||||
|
|
||||||
/* set the DLAB to access the baud rate divisor registers */
|
/* set the DLAB to access the baud rate divisor registers */
|
||||||
lcr_cache = INBYTE(LCR(dev));
|
lcr_cache = ns16550_inbyte(dev_cfg, LCR(dev));
|
||||||
OUTBYTE(LCR(dev), LCR_DLAB | lcr_cache);
|
ns16550_outbyte(dev_cfg, LCR(dev), LCR_DLAB | lcr_cache);
|
||||||
OUTBYTE(BRDL(dev), (unsigned char)(divisor & 0xff));
|
ns16550_outbyte(dev_cfg, BRDL(dev), (unsigned char)(divisor & 0xff));
|
||||||
OUTBYTE(BRDH(dev), (unsigned char)((divisor >> 8) & 0xff));
|
ns16550_outbyte(dev_cfg, BRDH(dev), (unsigned char)((divisor >> 8) & 0xff));
|
||||||
|
|
||||||
/* restore the DLAB to access the baud rate divisor registers */
|
/* 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;
|
dev_data->uart_config.baudrate = baud_rate;
|
||||||
}
|
}
|
||||||
|
@ -343,7 +408,7 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UART_NS16550_DLF_ENABLED
|
#if UART_NS16550_DLF_ENABLED
|
||||||
OUTBYTE(DLF(dev), dev_data->dlf);
|
ns16550_outbyte(dev_cfg, DLF(dev), dev_data->dlf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UART_NS16550_PCP_ENABLED
|
#if UART_NS16550_PCP_ENABLED
|
||||||
|
@ -351,8 +416,8 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
|
|
||||||
if (pcp) {
|
if (pcp) {
|
||||||
pcp |= PCP_EN;
|
pcp |= PCP_EN;
|
||||||
OUTWORD(PCP(dev), pcp & ~PCP_UPDATE);
|
ns16550_outbyte(dev_cfg, PCP(dev), pcp & ~PCP_UPDATE);
|
||||||
OUTWORD(PCP(dev), pcp | PCP_UPDATE);
|
ns16550_outbyte(dev_cfg, PCP(dev), pcp | PCP_UPDATE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -374,7 +439,7 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
|
|
||||||
set_baud_rate(dev, cfg->baudrate, pclk);
|
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;
|
struct uart_config uart_cfg;
|
||||||
|
|
||||||
switch (cfg->data_bits) {
|
switch (cfg->data_bits) {
|
||||||
|
@ -422,7 +487,7 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
dev_data->uart_config = *cfg;
|
dev_data->uart_config = *cfg;
|
||||||
|
|
||||||
/* data bits, stop bits, parity, clear DLAB */
|
/* data bits, stop bits, parity, clear DLAB */
|
||||||
OUTBYTE(LCR(dev),
|
ns16550_outbyte(dev_cfg, LCR(dev),
|
||||||
uart_cfg.data_bits | uart_cfg.stop_bits | uart_cfg.parity);
|
uart_cfg.data_bits | uart_cfg.stop_bits | uart_cfg.parity);
|
||||||
|
|
||||||
mdc = MCR_OUT2 | MCR_RTS | MCR_DTR;
|
mdc = MCR_OUT2 | MCR_RTS | MCR_DTR;
|
||||||
|
@ -433,21 +498,21 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OUTBYTE(MDC(dev), mdc);
|
ns16550_outbyte(dev_cfg, MDC(dev), mdc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program FIFO: enabled, mode 0 (set for compatibility with quark),
|
* Program FIFO: enabled, mode 0 (set for compatibility with quark),
|
||||||
* generate the interrupt at 8th byte
|
* generate the interrupt at 8th byte
|
||||||
* Clear TX and RX FIFO
|
* Clear TX and RX FIFO
|
||||||
*/
|
*/
|
||||||
OUTBYTE(FCR(dev),
|
ns16550_outbyte(dev_cfg, FCR(dev),
|
||||||
FCR_FIFO | FCR_MODE0 | FCR_FIFO_8 | FCR_RCVRCLR | FCR_XMITCLR
|
FCR_FIFO | FCR_MODE0 | FCR_FIFO_8 | FCR_RCVRCLR | FCR_XMITCLR
|
||||||
#ifdef CONFIG_UART_NS16550_VARIANT_NS16750
|
#ifdef CONFIG_UART_NS16550_VARIANT_NS16750
|
||||||
| FCR_FIFO_64
|
| FCR_FIFO_64
|
||||||
#endif
|
#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
|
#ifdef CONFIG_UART_NS16550_VARIANT_NS16750
|
||||||
dev_data->fifo_size = 64;
|
dev_data->fifo_size = 64;
|
||||||
#elif defined(CONFIG_UART_NS16550_VARIANT_NS16950)
|
#elif defined(CONFIG_UART_NS16550_VARIANT_NS16950)
|
||||||
|
@ -460,10 +525,10 @@ static int uart_ns16550_configure(const struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the port */
|
/* clear the port */
|
||||||
INBYTE(RDR(dev));
|
ns16550_inbyte(dev_cfg, RDR(dev));
|
||||||
|
|
||||||
/* disable interrupts */
|
/* disable interrupts */
|
||||||
OUTBYTE(IER(dev), 0x00);
|
ns16550_outbyte(dev_cfg, IER(dev), 0x00);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
k_spin_unlock(&dev_data->lock, key);
|
k_spin_unlock(&dev_data->lock, key);
|
||||||
|
@ -503,7 +568,6 @@ static int uart_ns16550_init(const struct device *dev)
|
||||||
|
|
||||||
ARG_UNUSED(dev_cfg);
|
ARG_UNUSED(dev_cfg);
|
||||||
|
|
||||||
#ifndef CONFIG_UART_NS16550_ACCESS_IOPORT
|
|
||||||
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie)
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie)
|
||||||
if (dev_cfg->pcie) {
|
if (dev_cfg->pcie) {
|
||||||
struct pcie_bar mbar;
|
struct pcie_bar mbar;
|
||||||
|
@ -520,10 +584,16 @@ static int uart_ns16550_init(const struct device *dev)
|
||||||
} else
|
} else
|
||||||
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) */
|
#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 */
|
/* Map directly from DTS */
|
||||||
|
if (!dev_cfg->io_map) {
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#endif
|
||||||
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
||||||
}
|
}
|
||||||
#endif /* !UART_NS15660_ACCESS_IOPORT */
|
}
|
||||||
|
|
||||||
ret = uart_ns16550_configure(dev, &data->uart_config);
|
ret = uart_ns16550_configure(dev, &data->uart_config);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
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)
|
static int uart_ns16550_poll_in(const struct device *dev, unsigned char *c)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
struct uart_ns16550_dev_data *data = dev->data;
|
||||||
|
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
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 */
|
/* got a character */
|
||||||
*c = INBYTE(RDR(dev));
|
*c = ns16550_inbyte(dev_cfg, RDR(dev));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,12 +648,13 @@ static void uart_ns16550_poll_out(const struct device *dev,
|
||||||
unsigned char c)
|
unsigned char c)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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)
|
static int uart_ns16550_err_check(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
@ -622,11 +695,12 @@ static int uart_ns16550_fifo_fill(const struct device *dev,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
struct uart_ns16550_dev_data *data = dev->data;
|
||||||
|
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||||
int i;
|
int i;
|
||||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
for (i = 0; (i < size) && (i < data->fifo_size); i++) {
|
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);
|
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)
|
const int size)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
struct uart_ns16550_dev_data *data = dev->data;
|
||||||
|
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
|
||||||
int i;
|
int i;
|
||||||
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
for (i = 0; (i < size) && (INBYTE(LSR(dev)) & LSR_RXRDY) != 0; i++) {
|
for (i = 0; (i < size) && (ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_RXRDY) != 0; i++) {
|
||||||
rx_data[i] = INBYTE(RDR(dev));
|
rx_data[i] = ns16550_inbyte(dev_cfg, RDR(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
k_spin_unlock(&data->lock, key);
|
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)
|
static void uart_ns16550_irq_tx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM)
|
#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
|
#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);
|
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)
|
static void uart_ns16550_irq_tx_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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)
|
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM)
|
||||||
struct uart_ns16550_dev_data *const dev_data = dev->data;
|
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)
|
static int uart_ns16550_irq_tx_complete(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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;
|
== (LSR_TEMT | LSR_THRE)) ? 1 : 0;
|
||||||
|
|
||||||
k_spin_unlock(&data->lock, key);
|
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)
|
static void uart_ns16550_irq_rx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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)
|
static void uart_ns16550_irq_rx_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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)
|
static void uart_ns16550_irq_err_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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)
|
static void uart_ns16550_irq_err_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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)
|
static int uart_ns16550_irq_update(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_ns16550_dev_data *data = dev->data;
|
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);
|
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);
|
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
|
#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);
|
ns16550_outbyte(dev_cfg, IER(dev), 0U);
|
||||||
OUTBYTE(IER(dev), cached_ier);
|
ns16550_outbyte(dev_cfg, IER(dev), cached_ier);
|
||||||
#endif
|
#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_RTS:
|
||||||
case UART_LINE_CTRL_DTR:
|
case UART_LINE_CTRL_DTR:
|
||||||
key = k_spin_lock(&data->lock);
|
key = k_spin_lock(&data->lock);
|
||||||
mdc = INBYTE(MDC(dev));
|
mdc = ns16550_inbyte(dev_cfg, MDC(dev));
|
||||||
|
|
||||||
if (ctrl == UART_LINE_CTRL_RTS) {
|
if (ctrl == UART_LINE_CTRL_RTS) {
|
||||||
chg = MCR_RTS;
|
chg = MCR_RTS;
|
||||||
|
@ -979,7 +1067,7 @@ static int uart_ns16550_line_ctrl_set(const struct device *dev,
|
||||||
} else {
|
} else {
|
||||||
mdc &= ~(chg);
|
mdc &= ~(chg);
|
||||||
}
|
}
|
||||||
OUTBYTE(MDC(dev), mdc);
|
ns16550_outbyte(dev_cfg, MDC(dev), mdc);
|
||||||
k_spin_unlock(&data->lock, key);
|
k_spin_unlock(&data->lock, key);
|
||||||
return 0;
|
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 UART_NS16550_DLF_ENABLED
|
||||||
if (cmd == CMD_SET_DLF) {
|
if (cmd == CMD_SET_DLF) {
|
||||||
struct uart_ns16550_dev_data * const dev_data = dev->data;
|
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);
|
k_spinlock_key_t key = k_spin_lock(&dev_data->lock);
|
||||||
|
|
||||||
dev_data->dlf = p;
|
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);
|
k_spin_unlock(&dev_data->lock, key);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1095,13 +1184,27 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_UART_NS16550_ACCESS_IOPORT
|
#ifdef CONFIG_UART_NS16550_ACCESS_IOPORT
|
||||||
#define DEV_CONFIG_REG_INIT(n) \
|
#define REG_INIT(n) \
|
||||||
.port = DT_INST_REG_ADDR(n),
|
.port = DT_INST_REG_ADDR(n), \
|
||||||
|
.io_map = true,
|
||||||
#else
|
#else
|
||||||
#define DEV_CONFIG_REG_INIT_PCIE0(n) DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)),
|
#define REG_INIT_PCIE1(n)
|
||||||
#define DEV_CONFIG_REG_INIT_PCIE1(n)
|
#define REG_INIT_PCIE0(n) DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)),
|
||||||
#define DEV_CONFIG_REG_INIT(n) \
|
|
||||||
_CONCAT(DEV_CONFIG_REG_INIT_PCIE, DT_INST_ON_BUS(n, pcie))(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
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#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) \
|
#define DEV_DATA_DLF_INIT(n) \
|
||||||
_CONCAT(DEV_DATA_DLF, DT_INST_NODE_HAS_PROP(n, dlf))(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) \
|
#define UART_NS16550_DEVICE_INIT(n) \
|
||||||
UART_NS16550_IRQ_FUNC_DECLARE(n); \
|
UART_NS16550_IRQ_FUNC_DECLARE(n); \
|
||||||
DEV_PCIE_DECLARE(n); \
|
DEV_PCIE_DECLARE(n); \
|
||||||
IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \
|
IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \
|
||||||
(PINCTRL_DT_INST_DEFINE(n))); \
|
(PINCTRL_DT_INST_DEFINE(n))); \
|
||||||
static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##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), ( \
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \
|
||||||
.sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
|
.sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
|
||||||
.clock_dev = NULL, \
|
.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, \
|
DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \
|
||||||
&uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \
|
&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_driver_api); \
|
||||||
UART_NS16550_IRQ_FUNC_DEFINE(n)
|
UART_NS16550_IRQ_FUNC_DEFINE(n)
|
||||||
|
|
||||||
|
|
|
@ -17,3 +17,7 @@ properties:
|
||||||
dlf:
|
dlf:
|
||||||
type: int
|
type: int
|
||||||
description: divisor latch fraction (DLF, if supported)
|
description: divisor latch fraction (DLF, if supported)
|
||||||
|
|
||||||
|
io-mapped:
|
||||||
|
type: boolean
|
||||||
|
description: specify registers are IO mapped or memory mapped
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue