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. This is 23 * the address we expect QEMU's mach-virt machine type to put in 24 * its generated device tree. 25 */ 26 #define UART_EARLY_BASE 0x09000000UL 27 28 static struct spinlock uart_lock; 29 static volatile u8 *uart0_base = (u8 *)UART_EARLY_BASE; 30 31 static void uart0_init(void) 32 { 33 const char *compatible = "arm,pl011"; 34 struct dt_pbus_reg base; 35 int ret; 36 37 ret = dt_get_default_console_node(); 38 assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); 39 40 if (ret == -FDT_ERR_NOTFOUND) { 41 42 ret = dt_pbus_get_base_compatible(compatible, &base); 43 assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 44 45 if (ret) { 46 printf("%s: %s not found in the device tree, " 47 "aborting...\n", 48 __func__, compatible); 49 abort(); 50 } 51 52 } else { 53 assert(dt_pbus_translate_node(ret, 0, &base) == 0); 54 } 55 56 uart0_base = ioremap(base.addr, base.size); 57 58 if (uart0_base != (u8 *)UART_EARLY_BASE) { 59 printf("WARNING: early print support may not work. " 60 "Found uart at %p, but early base is %p.\n", 61 uart0_base, (u8 *)UART_EARLY_BASE); 62 } 63 } 64 65 void io_init(void) 66 { 67 uart0_init(); 68 chr_testdev_init(); 69 } 70 71 void puts(const char *s) 72 { 73 spin_lock(&uart_lock); 74 while (*s) 75 writeb(*s++, uart0_base); 76 spin_unlock(&uart_lock); 77 } 78 79 void exit(int code) 80 { 81 chr_testdev_exit(code); 82 halt(code); 83 } 84