15e61cba0SAndrew Jones /*
25e61cba0SAndrew Jones * Each architecture must implement puts() and exit() with the I/O
35e61cba0SAndrew Jones * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's
45e61cba0SAndrew Jones * what's done here, along with initialization functions for those
55e61cba0SAndrew Jones * devices.
65e61cba0SAndrew Jones *
75e61cba0SAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
85e61cba0SAndrew Jones *
95e61cba0SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2.
105e61cba0SAndrew Jones */
118cca5668SAndrew Jones #include <libcflat.h>
128cca5668SAndrew Jones #include <devicetree.h>
138cca5668SAndrew Jones #include <chr-testdev.h>
149431507cSAlexandru Elisei #include <config.h>
15e3f0c462SAlexandru Elisei #include <asm/psci.h>
168cca5668SAndrew Jones #include <asm/spinlock.h>
178cca5668SAndrew Jones #include <asm/io.h>
185e61cba0SAndrew Jones
190df901e0SAndrew Jones #include "io.h"
200df901e0SAndrew Jones
219431507cSAlexandru Elisei static struct spinlock uart_lock;
225e61cba0SAndrew Jones /*
23725134dbSAlexandru Elisei * Use this guess for the uart base in order to make an attempt at
245e61cba0SAndrew Jones * having earlier printf support. We'll overwrite it with the real
25d70582c2SAndrew Jones * base address that we read from the device tree later. This is
26725134dbSAlexandru Elisei * the address we expect the virtual machine manager to put in
27d70582c2SAndrew Jones * its generated device tree.
285e61cba0SAndrew Jones */
299431507cSAlexandru Elisei #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE
309431507cSAlexandru Elisei static volatile u8 *uart0_base = UART_EARLY_BASE;
31*8c065edfSThomas Huth bool is_pl011_uart;
325e61cba0SAndrew Jones
uart0_init_fdt(void)338dcc4003SNikos Nikoleris static void uart0_init_fdt(void)
345e61cba0SAndrew Jones {
35725134dbSAlexandru Elisei /*
36725134dbSAlexandru Elisei * kvm-unit-tests uses the uart only for output. Both uart models have
37725134dbSAlexandru Elisei * the TX register at offset 0 from the base address, so there is no
38725134dbSAlexandru Elisei * need to treat them separately.
39725134dbSAlexandru Elisei */
40725134dbSAlexandru Elisei const char *compatible[] = {"arm,pl011", "ns16550a"};
415e61cba0SAndrew Jones struct dt_pbus_reg base;
42725134dbSAlexandru Elisei int i, ret;
435e61cba0SAndrew Jones
44d70582c2SAndrew Jones ret = dt_get_default_console_node();
45d70582c2SAndrew Jones assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND);
46d70582c2SAndrew Jones
47d70582c2SAndrew Jones if (ret == -FDT_ERR_NOTFOUND) {
48d70582c2SAndrew Jones
49725134dbSAlexandru Elisei for (i = 0; i < ARRAY_SIZE(compatible); i++) {
50725134dbSAlexandru Elisei ret = dt_pbus_get_base_compatible(compatible[i], &base);
515e61cba0SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
525e61cba0SAndrew Jones
53725134dbSAlexandru Elisei if (ret == 0)
54725134dbSAlexandru Elisei break;
55725134dbSAlexandru Elisei }
56725134dbSAlexandru Elisei
575e61cba0SAndrew Jones if (ret) {
58725134dbSAlexandru Elisei printf("%s: Compatible uart not found in the device tree, "
59725134dbSAlexandru Elisei "aborting...\n", __func__);
605e61cba0SAndrew Jones abort();
615e61cba0SAndrew Jones }
625e61cba0SAndrew Jones
63*8c065edfSThomas Huth is_pl011_uart = (i == 0);
64d70582c2SAndrew Jones } else {
65*8c065edfSThomas Huth is_pl011_uart = !fdt_node_check_compatible(dt_fdt(), ret,
66*8c065edfSThomas Huth "arm,pl011");
67a8743efaSAndrew Jones ret = dt_pbus_translate_node(ret, 0, &base);
68a8743efaSAndrew Jones assert(ret == 0);
69d70582c2SAndrew Jones }
70d70582c2SAndrew Jones
715e61cba0SAndrew Jones uart0_base = ioremap(base.addr, base.size);
728dcc4003SNikos Nikoleris }
738dcc4003SNikos Nikoleris
748dcc4003SNikos Nikoleris #ifdef CONFIG_EFI
758dcc4003SNikos Nikoleris
768dcc4003SNikos Nikoleris #include <acpi.h>
778dcc4003SNikos Nikoleris
uart0_init_acpi(void)788dcc4003SNikos Nikoleris static void uart0_init_acpi(void)
798dcc4003SNikos Nikoleris {
808dcc4003SNikos Nikoleris struct spcr_descriptor *spcr = find_acpi_table_addr(SPCR_SIGNATURE);
818dcc4003SNikos Nikoleris
828dcc4003SNikos Nikoleris assert_msg(spcr, "Unable to find ACPI SPCR");
838dcc4003SNikos Nikoleris uart0_base = ioremap(spcr->serial_port.address, spcr->serial_port.bit_width);
848dcc4003SNikos Nikoleris }
858dcc4003SNikos Nikoleris #else
868dcc4003SNikos Nikoleris
uart0_init_acpi(void)878dcc4003SNikos Nikoleris static void uart0_init_acpi(void)
888dcc4003SNikos Nikoleris {
898dcc4003SNikos Nikoleris assert_msg(false, "ACPI not available");
908dcc4003SNikos Nikoleris }
918dcc4003SNikos Nikoleris
928dcc4003SNikos Nikoleris #endif
938dcc4003SNikos Nikoleris
io_init(void)948dcc4003SNikos Nikoleris void io_init(void)
958dcc4003SNikos Nikoleris {
968dcc4003SNikos Nikoleris if (dt_available())
978dcc4003SNikos Nikoleris uart0_init_fdt();
988dcc4003SNikos Nikoleris else
998dcc4003SNikos Nikoleris uart0_init_acpi();
100d70582c2SAndrew Jones
1019431507cSAlexandru Elisei if (uart0_base != UART_EARLY_BASE) {
102d70582c2SAndrew Jones printf("WARNING: early print support may not work. "
103d70582c2SAndrew Jones "Found uart at %p, but early base is %p.\n",
1049431507cSAlexandru Elisei uart0_base, UART_EARLY_BASE);
105d70582c2SAndrew Jones }
1065e61cba0SAndrew Jones
1075e61cba0SAndrew Jones chr_testdev_init();
1085e61cba0SAndrew Jones }
1095e61cba0SAndrew Jones
puts(const char * s)1105e61cba0SAndrew Jones void puts(const char *s)
1115e61cba0SAndrew Jones {
1125e61cba0SAndrew Jones spin_lock(&uart_lock);
1135e61cba0SAndrew Jones while (*s)
1145e61cba0SAndrew Jones writeb(*s++, uart0_base);
1155e61cba0SAndrew Jones spin_unlock(&uart_lock);
1165e61cba0SAndrew Jones }
1175e61cba0SAndrew Jones
__getchar(void)11841c0f78cSEric Auger int __getchar(void)
11941c0f78cSEric Auger {
120*8c065edfSThomas Huth int c = -1;
12141c0f78cSEric Auger
122*8c065edfSThomas Huth spin_lock(&uart_lock);
12341c0f78cSEric Auger
124*8c065edfSThomas Huth if (is_pl011_uart) {
125*8c065edfSThomas Huth if (!(readb(uart0_base + 6 * 4) & 0x10)) /* RX not empty? */
126*8c065edfSThomas Huth c = readb(uart0_base);
127*8c065edfSThomas Huth } else {
128*8c065edfSThomas Huth if (readb(uart0_base + 5) & 0x01) /* RX data ready? */
129*8c065edfSThomas Huth c = readb(uart0_base);
130*8c065edfSThomas Huth }
131*8c065edfSThomas Huth
132*8c065edfSThomas Huth spin_unlock(&uart_lock);
13341c0f78cSEric Auger
13441c0f78cSEric Auger return c;
13541c0f78cSEric Auger }
136764aa0b8SAndrew Jones
137764aa0b8SAndrew Jones /*
138764aa0b8SAndrew Jones * Defining halt to take 'code' as an argument guarantees that it will
139764aa0b8SAndrew Jones * be in x0/r0 when we halt. That gives us a final chance to see the exit
140764aa0b8SAndrew Jones * status while inspecting the halted unit test state.
141764aa0b8SAndrew Jones */
142764aa0b8SAndrew Jones extern void halt(int code);
143764aa0b8SAndrew Jones
exit(int code)1445e61cba0SAndrew Jones void exit(int code)
1455e61cba0SAndrew Jones {
1467e214062SAlexandru Elisei /*
1477e214062SAlexandru Elisei * Print the test return code in the following format which is
1487e214062SAlexandru Elisei * consistent with powerpc and s390x. The runner can pick it
1497e214062SAlexandru Elisei * up when chr-testdev is not present.
1507e214062SAlexandru Elisei */
1517e214062SAlexandru Elisei printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
1527e214062SAlexandru Elisei
1535e61cba0SAndrew Jones chr_testdev_exit(code);
154e3f0c462SAlexandru Elisei psci_system_off();
1555e61cba0SAndrew Jones halt(code);
15696d79976SAndre Przywara __builtin_unreachable();
1575e61cba0SAndrew Jones }
158