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> 148cca5668SAndrew Jones #include <asm/spinlock.h> 158cca5668SAndrew Jones #include <asm/io.h> 165e61cba0SAndrew Jones 175e61cba0SAndrew Jones extern void halt(int code); 185e61cba0SAndrew Jones 195e61cba0SAndrew Jones /* 205e61cba0SAndrew Jones * Use this guess for the pl011 base in order to make an attempt at 215e61cba0SAndrew Jones * having earlier printf support. We'll overwrite it with the real 22d70582c2SAndrew Jones * base address that we read from the device tree later. This is 23d70582c2SAndrew Jones * the address we expect QEMU's mach-virt machine type to put in 24d70582c2SAndrew Jones * its generated device tree. 255e61cba0SAndrew Jones */ 26d70582c2SAndrew Jones #define UART_EARLY_BASE 0x09000000UL 275e61cba0SAndrew Jones 285e61cba0SAndrew Jones static struct spinlock uart_lock; 29d70582c2SAndrew Jones static volatile u8 *uart0_base = (u8 *)UART_EARLY_BASE; 305e61cba0SAndrew Jones 315e61cba0SAndrew Jones static void uart0_init(void) 325e61cba0SAndrew Jones { 335e61cba0SAndrew Jones const char *compatible = "arm,pl011"; 345e61cba0SAndrew Jones struct dt_pbus_reg base; 355e61cba0SAndrew Jones int ret; 365e61cba0SAndrew Jones 37d70582c2SAndrew Jones ret = dt_get_default_console_node(); 38d70582c2SAndrew Jones assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); 39d70582c2SAndrew Jones 40d70582c2SAndrew Jones if (ret == -FDT_ERR_NOTFOUND) { 41d70582c2SAndrew Jones 425e61cba0SAndrew Jones ret = dt_pbus_get_base_compatible(compatible, &base); 435e61cba0SAndrew Jones assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); 445e61cba0SAndrew Jones 455e61cba0SAndrew Jones if (ret) { 46d70582c2SAndrew Jones printf("%s: %s not found in the device tree, " 47d70582c2SAndrew Jones "aborting...\n", 485e61cba0SAndrew Jones __func__, compatible); 495e61cba0SAndrew Jones abort(); 505e61cba0SAndrew Jones } 515e61cba0SAndrew Jones 52d70582c2SAndrew Jones } else { 53*a8743efaSAndrew Jones ret = dt_pbus_translate_node(ret, 0, &base); 54*a8743efaSAndrew Jones assert(ret == 0); 55d70582c2SAndrew Jones } 56d70582c2SAndrew Jones 575e61cba0SAndrew Jones uart0_base = ioremap(base.addr, base.size); 58d70582c2SAndrew Jones 59d70582c2SAndrew Jones if (uart0_base != (u8 *)UART_EARLY_BASE) { 60d70582c2SAndrew Jones printf("WARNING: early print support may not work. " 61d70582c2SAndrew Jones "Found uart at %p, but early base is %p.\n", 62d70582c2SAndrew Jones uart0_base, (u8 *)UART_EARLY_BASE); 63d70582c2SAndrew Jones } 645e61cba0SAndrew Jones } 655e61cba0SAndrew Jones 665e61cba0SAndrew Jones void io_init(void) 675e61cba0SAndrew Jones { 685e61cba0SAndrew Jones uart0_init(); 695e61cba0SAndrew Jones chr_testdev_init(); 705e61cba0SAndrew Jones } 715e61cba0SAndrew Jones 725e61cba0SAndrew Jones void puts(const char *s) 735e61cba0SAndrew Jones { 745e61cba0SAndrew Jones spin_lock(&uart_lock); 755e61cba0SAndrew Jones while (*s) 765e61cba0SAndrew Jones writeb(*s++, uart0_base); 775e61cba0SAndrew Jones spin_unlock(&uart_lock); 785e61cba0SAndrew Jones } 795e61cba0SAndrew Jones 805e61cba0SAndrew Jones void exit(int code) 815e61cba0SAndrew Jones { 825e61cba0SAndrew Jones chr_testdev_exit(code); 835e61cba0SAndrew Jones halt(code); 845e61cba0SAndrew Jones } 85