You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
3.5 KiB
120 lines
3.5 KiB
/* |
|
* Copyright (c) 2020 Intel Corporation |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/kernel.h> |
|
#include <zephyr/sys/device_mmio.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/drivers/pcie/pcie.h> |
|
|
|
|
|
#if DT_PROP_OR(DT_CHOSEN(zephyr_console), io_mapped, 0) != 0 |
|
#define UART_IS_IOPORT_ACCESS 1 |
|
#endif |
|
|
|
#if defined(UART_IS_IOPORT_ACCESS) |
|
/* Legacy I/O Port Access to a NS16550 UART */ |
|
#define IN(reg) sys_in8(reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) |
|
#define OUT(reg, val) sys_out8(val, reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) |
|
#elif defined(X86_SOC_EARLY_SERIAL_PCIDEV) |
|
/* "Modern" mapping of a UART into a PCI MMIO device. The registers |
|
* are still bytes, but spaced at a 32 bit stride instead of packed |
|
* together. |
|
*/ |
|
static mm_reg_t mmio; |
|
#define IN(reg) (sys_read32(mmio + reg * 4) & 0xff) |
|
#define OUT(reg, val) sys_write32((val) & 0xff, mmio + reg * 4) |
|
#elif defined(X86_SOC_EARLY_SERIAL_MMIO8_ADDR) |
|
/* Still other devices use a MMIO region containing packed byte |
|
* registers |
|
*/ |
|
#ifdef DEVICE_MMIO_IS_IN_RAM |
|
static mm_reg_t mmio; |
|
#define BASE mmio |
|
#else |
|
#define BASE X86_SOC_EARLY_SERIAL_MMIO8_ADDR |
|
#endif /* DEVICE_MMIO_IS_IN_RAM */ |
|
#define IN(reg) sys_read8(BASE + reg) |
|
#define OUT(reg, val) sys_write8(val, BASE + reg) |
|
#else |
|
#error "Unsupported configuration" |
|
#endif |
|
|
|
#define REG_THR 0x00 /* Transmitter holding reg. */ |
|
#define REG_IER 0x01 /* Interrupt enable reg. */ |
|
#define REG_FCR 0x02 /* FIFO control reg. */ |
|
#define REG_LCR 0x03 /* Line control reg. */ |
|
#define REG_MCR 0x04 /* Modem control reg. */ |
|
#define REG_LSR 0x05 /* Line status reg. */ |
|
#define REG_BRDL 0x00 /* Baud rate divisor (LSB) */ |
|
#define REG_BRDH 0x01 /* Baud rate divisor (MSB) */ |
|
|
|
#define IER_DISABLE 0x00 |
|
#define LCR_8N1 (BIT(0) | BIT(1)) |
|
#define LCR_DLAB_SELECT BIT(7) |
|
#define MCR_DTR BIT(0) |
|
#define MCR_RTS BIT(1) |
|
#define LSR_THRE BIT(5) |
|
|
|
#define FCR_FIFO BIT(0) /* enable XMIT and RCVR FIFO */ |
|
#define FCR_RCVRCLR BIT(1) /* clear RCVR FIFO */ |
|
#define FCR_XMITCLR BIT(2) /* clear XMIT FIFO */ |
|
#define FCR_FIFO_1 0 /* 1 byte in RCVR FIFO */ |
|
|
|
static bool early_serial_init_done; |
|
static uint32_t suppressed_chars; |
|
|
|
static void serout(int c) |
|
{ |
|
while ((IN(REG_LSR) & LSR_THRE) == 0) { |
|
} |
|
OUT(REG_THR, c); |
|
} |
|
|
|
int arch_printk_char_out(int c) |
|
{ |
|
if (!early_serial_init_done) { |
|
suppressed_chars++; |
|
return c; |
|
} |
|
|
|
if (c == '\n') { |
|
serout('\r'); |
|
} |
|
serout(c); |
|
return c; |
|
} |
|
|
|
void z_x86_early_serial_init(void) |
|
{ |
|
#if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_IS_IOPORT_ACCESS) |
|
#ifdef X86_SOC_EARLY_SERIAL_PCIDEV |
|
struct pcie_bar mbar; |
|
pcie_get_mbar(X86_SOC_EARLY_SERIAL_PCIDEV, 0, &mbar); |
|
pcie_set_cmd(X86_SOC_EARLY_SERIAL_PCIDEV, PCIE_CONF_CMDSTAT_MEM, true); |
|
device_map(&mmio, mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE); |
|
#else |
|
device_map(&mmio, X86_SOC_EARLY_SERIAL_MMIO8_ADDR, 0x1000, K_MEM_CACHE_NONE); |
|
#endif |
|
|
|
#endif /* DEVICE_MMIO_IS_IN_RAM */ |
|
|
|
OUT(REG_IER, IER_DISABLE); /* Disable interrupts */ |
|
OUT(REG_LCR, LCR_DLAB_SELECT); /* DLAB select */ |
|
OUT(REG_BRDL, 1); /* Baud divisor = 1 */ |
|
OUT(REG_BRDH, 0); |
|
OUT(REG_LCR, LCR_8N1); /* LCR = 8n1 + DLAB off */ |
|
OUT(REG_MCR, MCR_DTR | MCR_RTS); |
|
|
|
/* Turn on FIFO. Some hardware needs this before transmitting */ |
|
OUT(REG_FCR, FCR_FIFO | FCR_FIFO_1 | FCR_RCVRCLR | FCR_XMITCLR); |
|
|
|
early_serial_init_done = true; |
|
|
|
if (suppressed_chars != 0U) { |
|
printk("WARNING: %u chars lost before early serial init\n", |
|
suppressed_chars); |
|
} |
|
}
|
|
|