diff options
-rw-r--r-- | core/chip.c | 2 | ||||
-rw-r--r-- | platforms/Makefile.inc | 3 | ||||
-rw-r--r-- | platforms/qemu/Makefile.inc | 6 | ||||
-rw-r--r-- | platforms/qemu/qemu.c | 143 |
4 files changed, 152 insertions, 2 deletions
diff --git a/core/chip.c b/core/chip.c index 7059ec3..c735df6 100644 --- a/core/chip.c +++ b/core/chip.c @@ -75,7 +75,7 @@ void init_chips(void) prlog(PR_NOTICE, "CHIP: Detected Mambo simulator\n"); } if (dt_node_is_compatible(dt_root, "qemu,powernv")) { - proc_chip_quirks |= QUIRK_NO_CHIPTOD | QUIRK_NO_PBA | QUIRK_NO_OCC_IRQ; + proc_chip_quirks |= QUIRK_NO_CHIPTOD | QUIRK_NO_PBA; prlog(PR_NOTICE, "CHIP: Detected Qemu simulator\n"); } diff --git a/platforms/Makefile.inc b/platforms/Makefile.inc index 12c82c8..90cd0f1 100644 --- a/platforms/Makefile.inc +++ b/platforms/Makefile.inc @@ -7,5 +7,6 @@ include $(SRC)/$(PLATDIR)/ibm-fsp/Makefile.inc include $(SRC)/$(PLATDIR)/rhesus/Makefile.inc include $(SRC)/$(PLATDIR)/astbmc/Makefile.inc include $(SRC)/$(PLATDIR)/mambo/Makefile.inc +include $(SRC)/$(PLATDIR)/qemu/Makefile.inc -$(PLATFORMS): $(IBM_FSP) $(RHESUS) $(ASTBMC) $(MAMBO) +$(PLATFORMS): $(IBM_FSP) $(RHESUS) $(ASTBMC) $(MAMBO) $(QEMU) diff --git a/platforms/qemu/Makefile.inc b/platforms/qemu/Makefile.inc new file mode 100644 index 0000000..11a44db --- /dev/null +++ b/platforms/qemu/Makefile.inc @@ -0,0 +1,6 @@ +SUBDIRS += $(PLATDIR)/qemu + +QEMU_OBJS = qemu.o +QEMU = $(PLATDIR)/qemu/built-in.o +$(QEMU): $(QEMU_OBJS:%=$(PLATDIR)/qemu/%) + diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c new file mode 100644 index 0000000..43e1221 --- /dev/null +++ b/platforms/qemu/qemu.c @@ -0,0 +1,143 @@ +/* Copyright 2013-2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <skiboot.h> +#include <device.h> +#include <lpc.h> +#include <console.h> +#include <opal.h> +#include <psi.h> + +static void qemu_init(void) +{ + /* Setup UART console for use by Linux via OPAL API */ + if (!dummy_console_enabled()) + uart_setup_opal_console(); +} + +static void qemu_dt_fixup_uart(struct dt_node *lpc) +{ + /* + * The official OF ISA/LPC binding is a bit odd, it prefixes + * the unit address for IO with "i". It uses 2 cells, the first + * one indicating IO vs. Memory space (along with bits to + * represent aliasing). + * + * We pickup that binding and add to it "2" as a indication + * of FW space. + * + * TODO: Probe the UART instead if the LPC bus allows for it + */ + struct dt_node *uart; + char namebuf[32]; +#define UART_IO_BASE 0x3f8 +#define UART_IO_COUNT 8 +#define UART_LPC_IRQ 4 + + snprintf(namebuf, sizeof(namebuf), "serial@i%x", UART_IO_BASE); + uart = dt_new(lpc, namebuf); + + dt_add_property_cells(uart, "reg", + 1, /* IO space */ + UART_IO_BASE, UART_IO_COUNT); + dt_add_property_strings(uart, "compatible", + "ns16550", + "pnpPNP,501"); + dt_add_property_cells(uart, "clock-frequency", 1843200); + dt_add_property_cells(uart, "current-speed", 115200); + dt_add_property_cells(uart, "interrupts", UART_LPC_IRQ); + dt_add_property_cells(uart, "interrupt-parent", lpc->phandle); + + /* + * This is needed by Linux for some obscure reasons, + * we'll eventually need to sanitize it but in the meantime + * let's make sure it's there + */ + dt_add_property_strings(uart, "device_type", "serial"); +} + +/* + * This adds the legacy RTC device to the device-tree + * for Linux to use + */ +static void qemu_dt_fixup_rtc(struct dt_node *lpc) +{ + struct dt_node *rtc; + char namebuf[32]; + + /* + * Follows the structure expected by the kernel file + * arch/powerpc/sysdev/rtc_cmos_setup.c + */ + snprintf(namebuf, sizeof(namebuf), "rtc@i%x", 0x70); + rtc = dt_new(lpc, namebuf); + dt_add_property_string(rtc, "compatible", "pnpPNP,b00"); + dt_add_property_cells(rtc, "reg", + 1, /* IO space */ + 0x70, 2); +} + +static void qemu_dt_fixup(void) +{ + struct dt_node *n, *primary_lpc = NULL; + + /* Find the primary LPC bus */ + dt_for_each_compatible(dt_root, n, "ibm,power8-lpc") { + if (!primary_lpc || dt_has_node_property(n, "primary", NULL)) + primary_lpc = n; + if (dt_has_node_property(n, "#address-cells", NULL)) + break; + } + + if (!primary_lpc) + return; + + qemu_dt_fixup_rtc(primary_lpc); + qemu_dt_fixup_uart(primary_lpc); +} + +static void qemu_ext_irq_serirq_cpld(unsigned int chip_id) +{ + lpc_all_interrupts(chip_id); +} + +static bool qemu_probe(void) +{ + if (!dt_node_is_compatible(dt_root, "qemu,powernv")) + return false; + + /* Add missing bits of device-tree such as the UART */ + qemu_dt_fixup(); + + psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT); + + /* + * Setup UART and use it as console. For now, we + * don't expose the interrupt as we know it's not + * working properly yet + */ + uart_init(true); + + return true; +} + +DECLARE_PLATFORM(qemu) = { + .name = "Qemu", + .probe = qemu_probe, + .init = qemu_init, + .external_irq = qemu_ext_irq_serirq_cpld, +}; |