xref: /kvm-unit-tests/lib/arm/io.c (revision 8c065edf33c01d4919d22332607353650b9a2890)
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