1 /* 2 * Each architecture must implement puts() and exit() with the I/O 3 * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's 4 * what's done here, along with initialization functions for those 5 * devices. 6 * 7 * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2. 10 */ 11 #include <libcflat.h> 12 #include <devicetree.h> 13 #include <chr-testdev.h> 14 #include <config.h> 15 #include <asm/psci.h> 16 #include <asm/spinlock.h> 17 #include <asm/io.h> 18 19 #include "io.h" 20 21 static struct spinlock uart_lock; 22 /* 23 * Use this guess for the uart base in order to make an attempt at 24 * having earlier printf support. We'll overwrite it with the real 25 * base address that we read from the device tree later. This is 26 * the address we expect the virtual machine manager to put in 27 * its generated device tree. 28 */ 29 #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE 30 static volatile u8 *uart0_base = UART_EARLY_BASE; 31 bool is_pl011_uart; 32 33 static void uart0_init_fdt(void) 34 { 35 /* 36 * kvm-unit-tests uses the uart only for output. Both uart models have 37 * the TX register at offset 0 from the base address, so there is no 38 * need to treat them separately. 39 */ 40 const char *compatible[] = {"arm,pl011", "ns16550a"}; 41 struct dt_pbus_reg base; 42 int i, ret; 43 44 ret = dt_get_default_console_node(); 45 assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); 46 47 if (ret == -FDT_ERR_NOTFOUND) { 48 49 for (i = 0; i < ARRAY_SIZE(compatible); i++) { 50 ret = dt_pbus_get_base_compatible(compatible[i], &base); 51 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 52 53 if (ret == 0) 54 break; 55 } 56 57 if (ret) { 58 printf("%s: Compatible uart not found in the device tree, " 59 "aborting...\n", __func__); 60 abort(); 61 } 62 63 is_pl011_uart = (i == 0); 64 } else { 65 is_pl011_uart = !fdt_node_check_compatible(dt_fdt(), ret, 66 "arm,pl011"); 67 ret = dt_pbus_translate_node(ret, 0, &base); 68 assert(ret == 0); 69 } 70 71 uart0_base = ioremap(base.addr, base.size); 72 } 73 74 #ifdef CONFIG_EFI 75 76 #include <acpi.h> 77 78 static void uart0_init_acpi(void) 79 { 80 struct spcr_descriptor *spcr = find_acpi_table_addr(SPCR_SIGNATURE); 81 82 assert_msg(spcr, "Unable to find ACPI SPCR"); 83 uart0_base = ioremap(spcr->serial_port.address, spcr->serial_port.bit_width); 84 } 85 #else 86 87 static void uart0_init_acpi(void) 88 { 89 assert_msg(false, "ACPI not available"); 90 } 91 92 #endif 93 94 void io_init(void) 95 { 96 if (dt_available()) 97 uart0_init_fdt(); 98 else 99 uart0_init_acpi(); 100 101 if (uart0_base != UART_EARLY_BASE) { 102 printf("WARNING: early print support may not work. " 103 "Found uart at %p, but early base is %p.\n", 104 uart0_base, UART_EARLY_BASE); 105 } 106 107 chr_testdev_init(); 108 } 109 110 void puts(const char *s) 111 { 112 spin_lock(&uart_lock); 113 while (*s) 114 writeb(*s++, uart0_base); 115 spin_unlock(&uart_lock); 116 } 117 118 int __getchar(void) 119 { 120 int c = -1; 121 122 spin_lock(&uart_lock); 123 124 if (is_pl011_uart) { 125 if (!(readb(uart0_base + 6 * 4) & 0x10)) /* RX not empty? */ 126 c = readb(uart0_base); 127 } else { 128 if (readb(uart0_base + 5) & 0x01) /* RX data ready? */ 129 c = readb(uart0_base); 130 } 131 132 spin_unlock(&uart_lock); 133 134 return c; 135 } 136 137 /* 138 * Defining halt to take 'code' as an argument guarantees that it will 139 * be in x0/r0 when we halt. That gives us a final chance to see the exit 140 * status while inspecting the halted unit test state. 141 */ 142 extern void halt(int code); 143 144 void exit(int code) 145 { 146 /* 147 * Print the test return code in the following format which is 148 * consistent with powerpc and s390x. The runner can pick it 149 * up when chr-testdev is not present. 150 */ 151 printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 152 153 chr_testdev_exit(code); 154 psci_system_off(); 155 halt(code); 156 __builtin_unreachable(); 157 } 158