162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 16550 serial console support. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Original copied from <file:arch/ppc/boot/common/ns16550.c> 662306a36Sopenharmony_ci * (which had no copyright) 762306a36Sopenharmony_ci * Modifications: 2006 (c) MontaVista Software, Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Modified by: Mark A. Greer <mgreer@mvista.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <stdarg.h> 1262306a36Sopenharmony_ci#include <stddef.h> 1362306a36Sopenharmony_ci#include "types.h" 1462306a36Sopenharmony_ci#include "string.h" 1562306a36Sopenharmony_ci#include "stdio.h" 1662306a36Sopenharmony_ci#include "io.h" 1762306a36Sopenharmony_ci#include "ops.h" 1862306a36Sopenharmony_ci#include "of.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define UART_DLL 0 /* Out: Divisor Latch Low */ 2162306a36Sopenharmony_ci#define UART_DLM 1 /* Out: Divisor Latch High */ 2262306a36Sopenharmony_ci#define UART_FCR 2 /* Out: FIFO Control Register */ 2362306a36Sopenharmony_ci#define UART_LCR 3 /* Out: Line Control Register */ 2462306a36Sopenharmony_ci#define UART_MCR 4 /* Out: Modem Control Register */ 2562306a36Sopenharmony_ci#define UART_LSR 5 /* In: Line Status Register */ 2662306a36Sopenharmony_ci#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 2762306a36Sopenharmony_ci#define UART_LSR_DR 0x01 /* Receiver data ready */ 2862306a36Sopenharmony_ci#define UART_MSR 6 /* In: Modem Status Register */ 2962306a36Sopenharmony_ci#define UART_SCR 7 /* I/O: Scratch Register */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic unsigned char *reg_base; 3262306a36Sopenharmony_cistatic u32 reg_shift; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int ns16550_open(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci out_8(reg_base + (UART_FCR << reg_shift), 0x06); 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void ns16550_putc(unsigned char c) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0); 4362306a36Sopenharmony_ci out_8(reg_base, c); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic unsigned char ns16550_getc(void) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0); 4962306a36Sopenharmony_ci return in_8(reg_base); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic u8 ns16550_tstc(void) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciint ns16550_console_init(void *devp, struct serial_console_data *scdp) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci int n; 6062306a36Sopenharmony_ci u32 reg_offset; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (dt_get_virtual_reg(devp, (void **)®_base, 1) < 1) { 6362306a36Sopenharmony_ci printf("virt reg parse fail...\r\n"); 6462306a36Sopenharmony_ci return -1; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci n = getprop(devp, "reg-offset", ®_offset, sizeof(reg_offset)); 6862306a36Sopenharmony_ci if (n == sizeof(reg_offset)) 6962306a36Sopenharmony_ci reg_base += be32_to_cpu(reg_offset); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci n = getprop(devp, "reg-shift", ®_shift, sizeof(reg_shift)); 7262306a36Sopenharmony_ci if (n != sizeof(reg_shift)) 7362306a36Sopenharmony_ci reg_shift = 0; 7462306a36Sopenharmony_ci else 7562306a36Sopenharmony_ci reg_shift = be32_to_cpu(reg_shift); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci scdp->open = ns16550_open; 7862306a36Sopenharmony_ci scdp->putc = ns16550_putc; 7962306a36Sopenharmony_ci scdp->getc = ns16550_getc; 8062306a36Sopenharmony_ci scdp->tstc = ns16550_tstc; 8162306a36Sopenharmony_ci scdp->close = NULL; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 85