zephyr/arch/x86/core/early_serial.c

62 lines
1.6 KiB
C

/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <devicetree.h>
#include <kernel.h>
#include <sys/util.h>
/* Super-primitive 8250/16550 serial output-only driver, 115200 8n1 */
#define PORT ((io_port_t)DT_REG_ADDR(DT_INST(0, ns16550)))
#define REG_IER 0x01 /* Interrupt enable reg. */
#define REG_LCR 0x03 /* Line control reg. */
#define REG_MCR 0x04 /* Modem control reg. */
#define REG_LSR 0x05 /* Line status reg. */
#define REG_DL_LO 0x00 /* Divisor latch low byte */
#define REG_DL_HI 0x01 /* Divisor latch high byte */
#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 LCR_THRE BIT(5)
static void serout(int c)
{
while (!(sys_in8(PORT + REG_LSR) & LCR_THRE)) {
}
sys_out8(c, PORT);
}
static int console_out(int c)
{
if (c == '\n') {
serout('\r');
}
serout(c);
return c;
}
extern void __printk_hook_install(int (*fn)(int));
void z_x86_early_serial_init(void)
{
/* In fact Qemu already has most of this set up and works by
* default
*/
sys_out8(IER_DISABLE, PORT + REG_IER); /* Disable interrupts */
sys_out8(LCR_DLAB_SELECT, PORT + REG_LCR); /* DLAB select */
sys_out8(1, PORT + REG_DL_LO); /* Baud divisor = 1 */
sys_out8(0, PORT + REG_DL_HI);
sys_out8(LCR_8N1, PORT + REG_LCR); /* LCR = 8n1 + DLAB off */
sys_out8(MCR_DTR | MCR_RTS, PORT + REG_MCR);
/* Will be replaced later when a real serial driver comes up */
__printk_hook_install(console_out);
}