xref: /kvm-unit-tests/lib/arm/io.c (revision 728e71ee457384eb1cf2d5111d1e4329498581db)
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 <asm/spinlock.h>
15 #include <asm/io.h>
16 
17 #include "io.h"
18 
19 extern void halt(int code);
20 
21 /*
22  * Use this guess for the pl011 base in order to make an attempt at
23  * having earlier printf support. We'll overwrite it with the real
24  * base address that we read from the device tree later. This is
25  * the address we expect QEMU's mach-virt machine type to put in
26  * its generated device tree.
27  */
28 #define UART_EARLY_BASE 0x09000000UL
29 
30 static struct spinlock uart_lock;
31 static volatile u8 *uart0_base = (u8 *)UART_EARLY_BASE;
32 
33 static void uart0_init(void)
34 {
35 	const char *compatible = "arm,pl011";
36 	struct dt_pbus_reg base;
37 	int ret;
38 
39 	ret = dt_get_default_console_node();
40 	assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND);
41 
42 	if (ret == -FDT_ERR_NOTFOUND) {
43 
44 		ret = dt_pbus_get_base_compatible(compatible, &base);
45 		assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
46 
47 		if (ret) {
48 			printf("%s: %s not found in the device tree, "
49 				"aborting...\n",
50 				__func__, compatible);
51 			abort();
52 		}
53 
54 	} else {
55 		ret = dt_pbus_translate_node(ret, 0, &base);
56 		assert(ret == 0);
57 	}
58 
59 	uart0_base = ioremap(base.addr, base.size);
60 
61 	if (uart0_base != (u8 *)UART_EARLY_BASE) {
62 		printf("WARNING: early print support may not work. "
63 		       "Found uart at %p, but early base is %p.\n",
64 			uart0_base, (u8 *)UART_EARLY_BASE);
65 	}
66 }
67 
68 void io_init(void)
69 {
70 	uart0_init();
71 	chr_testdev_init();
72 }
73 
74 void puts(const char *s)
75 {
76 	spin_lock(&uart_lock);
77 	while (*s)
78 		writeb(*s++, uart0_base);
79 	spin_unlock(&uart_lock);
80 }
81 
82 void exit(int code)
83 {
84 	chr_testdev_exit(code);
85 	halt(code);
86 }
87