blob: a111530f4802d7fee0d581dac167e01b6e3a7866 [file] [log] [blame]
/*
* Each architecture must implement puts() and exit() with the I/O
* devices exposed from QEMU, e.g. pl011 and chr-testdev. That's
* what's done here, along with initialization functions for those
* devices.
*
* Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
#include <libcflat.h>
#include <devicetree.h>
#include <chr-testdev.h>
#include <asm/spinlock.h>
#include <asm/io.h>
extern void halt(int code);
/*
* Use this guess for the pl011 base in order to make an attempt at
* having earlier printf support. We'll overwrite it with the real
* base address that we read from the device tree later. This is
* the address we expect QEMU's mach-virt machine type to put in
* its generated device tree.
*/
#define UART_EARLY_BASE 0x09000000UL
static struct spinlock uart_lock;
static volatile u8 *uart0_base = (u8 *)UART_EARLY_BASE;
static void uart0_init(void)
{
const char *compatible = "arm,pl011";
struct dt_pbus_reg base;
int ret;
ret = dt_get_default_console_node();
assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND);
if (ret == -FDT_ERR_NOTFOUND) {
ret = dt_pbus_get_base_compatible(compatible, &base);
assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
if (ret) {
printf("%s: %s not found in the device tree, "
"aborting...\n",
__func__, compatible);
abort();
}
} else {
ret = dt_pbus_translate_node(ret, 0, &base);
assert(ret == 0);
}
uart0_base = ioremap(base.addr, base.size);
if (uart0_base != (u8 *)UART_EARLY_BASE) {
printf("WARNING: early print support may not work. "
"Found uart at %p, but early base is %p.\n",
uart0_base, (u8 *)UART_EARLY_BASE);
}
}
void io_init(void)
{
uart0_init();
chr_testdev_init();
}
void puts(const char *s)
{
spin_lock(&uart_lock);
while (*s)
writeb(*s++, uart0_base);
spin_unlock(&uart_lock);
}
void exit(int code)
{
chr_testdev_exit(code);
halt(code);
}