1bd744d46SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only 2bd744d46SAndrew Jones /* 3bd744d46SAndrew Jones * Each architecture must implement puts() and exit() with the I/O 4bd744d46SAndrew Jones * devices exposed from QEMU, e.g. ns16550a. 5bd744d46SAndrew Jones * 6bd744d46SAndrew Jones * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com> 7bd744d46SAndrew Jones */ 8bd744d46SAndrew Jones #include <libcflat.h> 9bd744d46SAndrew Jones #include <config.h> 1022f287f4SAndrew Jones #include <devicetree.h> 11bd744d46SAndrew Jones #include <asm/io.h> 12*9ccb00e4SAndrew Jones #include <asm/sbi.h> 1322f287f4SAndrew Jones #include <asm/setup.h> 14bd744d46SAndrew Jones #include <asm/spinlock.h> 15bd744d46SAndrew Jones 16bd744d46SAndrew Jones /* 17bd744d46SAndrew Jones * Use this guess for the uart base in order to make an attempt at 18bd744d46SAndrew Jones * having earlier printf support. We'll overwrite it with the real 19bd744d46SAndrew Jones * base address that we read from the device tree later. This is 20bd744d46SAndrew Jones * the address we expect the virtual machine manager to put in 21bd744d46SAndrew Jones * its generated device tree. 22bd744d46SAndrew Jones */ 23bd744d46SAndrew Jones #define UART_EARLY_BASE ((u8 *)(unsigned long)CONFIG_UART_EARLY_BASE) 24bd744d46SAndrew Jones static volatile u8 *uart0_base = UART_EARLY_BASE; 25bd744d46SAndrew Jones static struct spinlock uart_lock; 26bd744d46SAndrew Jones 2722f287f4SAndrew Jones static void uart0_init_fdt(void) 2822f287f4SAndrew Jones { 2922f287f4SAndrew Jones const char *compatible[] = {"ns16550a"}; 3022f287f4SAndrew Jones struct dt_pbus_reg base; 3122f287f4SAndrew Jones int i, ret; 3222f287f4SAndrew Jones 3322f287f4SAndrew Jones ret = dt_get_default_console_node(); 3422f287f4SAndrew Jones assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); 3522f287f4SAndrew Jones 3622f287f4SAndrew Jones if (ret == -FDT_ERR_NOTFOUND) { 3722f287f4SAndrew Jones for (i = 0; i < ARRAY_SIZE(compatible); i++) { 3822f287f4SAndrew Jones ret = dt_pbus_get_base_compatible(compatible[i], &base); 3922f287f4SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 4022f287f4SAndrew Jones if (ret == 0) 4122f287f4SAndrew Jones break; 4222f287f4SAndrew Jones } 4322f287f4SAndrew Jones 4422f287f4SAndrew Jones if (ret) { 4522f287f4SAndrew Jones printf("%s: Compatible uart not found in the device tree, aborting...\n", 4622f287f4SAndrew Jones __func__); 4722f287f4SAndrew Jones abort(); 4822f287f4SAndrew Jones } 4922f287f4SAndrew Jones } else { 5022f287f4SAndrew Jones ret = dt_pbus_translate_node(ret, 0, &base); 5122f287f4SAndrew Jones assert(ret == 0); 5222f287f4SAndrew Jones } 5322f287f4SAndrew Jones 5422f287f4SAndrew Jones uart0_base = ioremap(base.addr, base.size); 5522f287f4SAndrew Jones } 5622f287f4SAndrew Jones 5722f287f4SAndrew Jones static void uart0_init_acpi(void) 5822f287f4SAndrew Jones { 5922f287f4SAndrew Jones assert_msg(false, "ACPI not available"); 6022f287f4SAndrew Jones } 6122f287f4SAndrew Jones 6222f287f4SAndrew Jones void io_init(void) 6322f287f4SAndrew Jones { 6422f287f4SAndrew Jones if (dt_available()) 6522f287f4SAndrew Jones uart0_init_fdt(); 6622f287f4SAndrew Jones else 6722f287f4SAndrew Jones uart0_init_acpi(); 6822f287f4SAndrew Jones 6922f287f4SAndrew Jones if (uart0_base != UART_EARLY_BASE) { 7022f287f4SAndrew Jones printf("WARNING: early print support may not work. " 7122f287f4SAndrew Jones "Found uart at %p, but early base is %p.\n", 7222f287f4SAndrew Jones uart0_base, UART_EARLY_BASE); 7322f287f4SAndrew Jones } 7422f287f4SAndrew Jones } 7522f287f4SAndrew Jones 76bd744d46SAndrew Jones void puts(const char *s) 77bd744d46SAndrew Jones { 78bd744d46SAndrew Jones spin_lock(&uart_lock); 79bd744d46SAndrew Jones while (*s) 80bd744d46SAndrew Jones writeb(*s++, uart0_base); 81bd744d46SAndrew Jones spin_unlock(&uart_lock); 82bd744d46SAndrew Jones } 83bd744d46SAndrew Jones 84bd744d46SAndrew Jones /* 85bd744d46SAndrew Jones * Defining halt to take 'code' as an argument guarantees that it will 86bd744d46SAndrew Jones * be in a0 when we halt. That gives us a final chance to see the exit 87bd744d46SAndrew Jones * status while inspecting the halted unit test state. 88bd744d46SAndrew Jones */ 89bd744d46SAndrew Jones void halt(int code); 90bd744d46SAndrew Jones 91bd744d46SAndrew Jones void exit(int code) 92bd744d46SAndrew Jones { 93bd744d46SAndrew Jones printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 94*9ccb00e4SAndrew Jones sbi_shutdown(); 95bd744d46SAndrew Jones halt(code); 96bd744d46SAndrew Jones __builtin_unreachable(); 97bd744d46SAndrew Jones } 98