xref: /kvm-unit-tests/lib/arm/io.c (revision d3aacb4f57d05f74f2030dbe12e7dfd6aa1b273d)
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 extern void halt(int code);
18 
19 /*
20  * Use this guess for the pl011 base in order to make an attempt at
21  * having earlier printf support. We'll overwrite it with the real
22  * base address that we read from the device tree later.
23  */
24 #define QEMU_MACH_VIRT_PL011_BASE 0x09000000UL
25 
26 static struct spinlock uart_lock;
27 static volatile u8 *uart0_base = (u8 *)QEMU_MACH_VIRT_PL011_BASE;
28 
29 static void uart0_init(void)
30 {
31 	const char *compatible = "arm,pl011";
32 	struct dt_pbus_reg base;
33 	int ret;
34 
35 	ret = dt_pbus_get_base_compatible(compatible, &base);
36 	assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
37 
38 	if (ret) {
39 		printf("%s: %s not found in the device tree, aborting...\n",
40 			__func__, compatible);
41 		abort();
42 	}
43 
44 	uart0_base = ioremap(base.addr, base.size);
45 }
46 
47 void io_init(void)
48 {
49 	uart0_init();
50 	chr_testdev_init();
51 }
52 
53 void puts(const char *s)
54 {
55 	spin_lock(&uart_lock);
56 	while (*s)
57 		writeb(*s++, uart0_base);
58 	spin_unlock(&uart_lock);
59 }
60 
61 void exit(int code)
62 {
63 	chr_testdev_exit(code);
64 	halt(code);
65 }
66