18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 16550 serial console support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Original copied from <file:arch/ppc/boot/common/ns16550.c> 68c2ecf20Sopenharmony_ci * (which had no copyright) 78c2ecf20Sopenharmony_ci * Modifications: 2006 (c) MontaVista Software, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Modified by: Mark A. Greer <mgreer@mvista.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <stdarg.h> 128c2ecf20Sopenharmony_ci#include <stddef.h> 138c2ecf20Sopenharmony_ci#include "types.h" 148c2ecf20Sopenharmony_ci#include "string.h" 158c2ecf20Sopenharmony_ci#include "stdio.h" 168c2ecf20Sopenharmony_ci#include "io.h" 178c2ecf20Sopenharmony_ci#include "ops.h" 188c2ecf20Sopenharmony_ci#include "of.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define UART_DLL 0 /* Out: Divisor Latch Low */ 218c2ecf20Sopenharmony_ci#define UART_DLM 1 /* Out: Divisor Latch High */ 228c2ecf20Sopenharmony_ci#define UART_FCR 2 /* Out: FIFO Control Register */ 238c2ecf20Sopenharmony_ci#define UART_LCR 3 /* Out: Line Control Register */ 248c2ecf20Sopenharmony_ci#define UART_MCR 4 /* Out: Modem Control Register */ 258c2ecf20Sopenharmony_ci#define UART_LSR 5 /* In: Line Status Register */ 268c2ecf20Sopenharmony_ci#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 278c2ecf20Sopenharmony_ci#define UART_LSR_DR 0x01 /* Receiver data ready */ 288c2ecf20Sopenharmony_ci#define UART_MSR 6 /* In: Modem Status Register */ 298c2ecf20Sopenharmony_ci#define UART_SCR 7 /* I/O: Scratch Register */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned char *reg_base; 328c2ecf20Sopenharmony_cistatic u32 reg_shift; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int ns16550_open(void) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci out_8(reg_base + (UART_FCR << reg_shift), 0x06); 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void ns16550_putc(unsigned char c) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0); 438c2ecf20Sopenharmony_ci out_8(reg_base, c); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic unsigned char ns16550_getc(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0); 498c2ecf20Sopenharmony_ci return in_8(reg_base); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic u8 ns16550_tstc(void) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint ns16550_console_init(void *devp, struct serial_console_data *scdp) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int n; 608c2ecf20Sopenharmony_ci u32 reg_offset; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (dt_get_virtual_reg(devp, (void **)®_base, 1) < 1) { 638c2ecf20Sopenharmony_ci printf("virt reg parse fail...\r\n"); 648c2ecf20Sopenharmony_ci return -1; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci n = getprop(devp, "reg-offset", ®_offset, sizeof(reg_offset)); 688c2ecf20Sopenharmony_ci if (n == sizeof(reg_offset)) 698c2ecf20Sopenharmony_ci reg_base += be32_to_cpu(reg_offset); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci n = getprop(devp, "reg-shift", ®_shift, sizeof(reg_shift)); 728c2ecf20Sopenharmony_ci if (n != sizeof(reg_shift)) 738c2ecf20Sopenharmony_ci reg_shift = 0; 748c2ecf20Sopenharmony_ci else 758c2ecf20Sopenharmony_ci reg_shift = be32_to_cpu(reg_shift); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci scdp->open = ns16550_open; 788c2ecf20Sopenharmony_ci scdp->putc = ns16550_putc; 798c2ecf20Sopenharmony_ci scdp->getc = ns16550_getc; 808c2ecf20Sopenharmony_ci scdp->tstc = ns16550_tstc; 818c2ecf20Sopenharmony_ci scdp->close = NULL; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 85