mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160316-1' into staging
target-arm queue: * loader: Fix incorrect parameter name in load_image_mr() * Implement MRS (banked) and MSR (banked) instructions * virt: Implement versioning for machine model * i.MX: some initial patches preparing for i.MX6 support * new ASPEED AST2400 SoC and palmetto-bmc machine * bcm2835: add some more raspi2 devices * sd: fix segfault running "info qtree" # gpg: Signature made Wed 16 Mar 2016 17:42:43 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160316-1: (21 commits) sd: Fix "info qtree" on boards with SD cards bcm2835_dma: add emulation of Raspberry Pi DMA controller bcm2835_property: implement framebuffer control/configuration properties bcm2835_fb: add framebuffer device for Raspberry Pi bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi hw/arm: Add palmetto-bmc machine hw/arm: Add ASPEED AST2400 SoC model hw/intc: Add (new) ASPEED VIC device model hw/timer: Add ASPEED timer device model i.MX: Add missing descriptions in devices. i.MX: Add i.MX6 CCM and ANALOG device. i.MX: Add the CLK_IPG_HIGH clock i.MX: Remove CCM useless clock computation handling. i.MX: Rename CCM NOCLK to CLK_NONE for naming consistency. i.MX: Allow GPT timer to rollover. arm: virt: Move machine class init code to the abstract machine type arm: virt: Add an abstract ARM virt machine type target-arm: Fix translation level on early translation faults target-arm: Implement MRS (banked) and MSR (banked) instructions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -110,3 +110,4 @@ CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_ASPEED_SOC=y
|
||||
|
||||
@@ -16,3 +16,4 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
|
||||
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
|
||||
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
|
||||
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* AST2400 SoC
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
* Jeremy Kerr <jk@ozlabs.org>
|
||||
*
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/ast2400.h"
|
||||
#include "hw/char/serial.h"
|
||||
|
||||
#define AST2400_UART_5_BASE 0x00184000
|
||||
#define AST2400_IOMEM_SIZE 0x00200000
|
||||
#define AST2400_IOMEM_BASE 0x1E600000
|
||||
#define AST2400_VIC_BASE 0x1E6C0000
|
||||
#define AST2400_TIMER_BASE 0x1E782000
|
||||
|
||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
||||
|
||||
/*
|
||||
* IO handlers: simply catch any reads/writes to IO addresses that aren't
|
||||
* handled by a device mapping.
|
||||
*/
|
||||
|
||||
static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
|
||||
__func__, offset, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
|
||||
__func__, offset, value, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ast2400_io_ops = {
|
||||
.read = ast2400_io_read,
|
||||
.write = ast2400_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ast2400_init(Object *obj)
|
||||
{
|
||||
AST2400State *s = AST2400(obj);
|
||||
|
||||
s->cpu = cpu_arm_init("arm926");
|
||||
|
||||
object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
|
||||
object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
|
||||
object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default());
|
||||
}
|
||||
|
||||
static void ast2400_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
AST2400State *s = AST2400(dev);
|
||||
Error *err = NULL;
|
||||
|
||||
/* IO space */
|
||||
memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
|
||||
"ast2400.io", AST2400_IOMEM_SIZE);
|
||||
memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE,
|
||||
&s->iomem, -1);
|
||||
|
||||
/* VIC */
|
||||
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
|
||||
|
||||
/* Timer */
|
||||
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE);
|
||||
for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||
}
|
||||
|
||||
/* UART - attach an 8250 to the IO space as our UART5 */
|
||||
if (serial_hds[0]) {
|
||||
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
|
||||
serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2,
|
||||
uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
static void ast2400_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = ast2400_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo ast2400_type_info = {
|
||||
.name = TYPE_AST2400,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AST2400State),
|
||||
.instance_init = ast2400_init,
|
||||
.class_init = ast2400_class_init,
|
||||
};
|
||||
|
||||
static void ast2400_register_types(void)
|
||||
{
|
||||
type_register_static(&ast2400_type_info);
|
||||
}
|
||||
|
||||
type_init(ast2400_register_types)
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "hw/arm/bcm2835_peripherals.h"
|
||||
#include "hw/misc/bcm2835_mbox_defs.h"
|
||||
#include "hw/arm/raspi_platform.h"
|
||||
#include "sysemu/char.h"
|
||||
|
||||
/* Peripheral base address on the VC (GPU) system bus */
|
||||
#define BCM2835_VC_PERI_BASE 0x7e000000
|
||||
@@ -48,6 +49,11 @@ static void bcm2835_peripherals_init(Object *obj)
|
||||
object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
|
||||
qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
|
||||
|
||||
/* AUX / UART1 */
|
||||
object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX);
|
||||
object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default());
|
||||
|
||||
/* Mailboxes */
|
||||
object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
|
||||
object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
|
||||
@@ -56,6 +62,16 @@ static void bcm2835_peripherals_init(Object *obj)
|
||||
object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
|
||||
OBJECT(&s->mbox_mr), &error_abort);
|
||||
|
||||
/* Framebuffer */
|
||||
object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB);
|
||||
object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL);
|
||||
object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size",
|
||||
&error_abort);
|
||||
qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default());
|
||||
|
||||
object_property_add_const_link(OBJECT(&s->fb), "dma-mr",
|
||||
OBJECT(&s->gpu_bus_mr), &error_abort);
|
||||
|
||||
/* Property channel */
|
||||
object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
|
||||
object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
|
||||
@@ -63,6 +79,8 @@ static void bcm2835_peripherals_init(Object *obj)
|
||||
"board-rev", &error_abort);
|
||||
qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
|
||||
|
||||
object_property_add_const_link(OBJECT(&s->property), "fb",
|
||||
OBJECT(&s->fb), &error_abort);
|
||||
object_property_add_const_link(OBJECT(&s->property), "dma-mr",
|
||||
OBJECT(&s->gpu_bus_mr), &error_abort);
|
||||
|
||||
@@ -70,6 +88,14 @@ static void bcm2835_peripherals_init(Object *obj)
|
||||
object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI);
|
||||
object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->sdhci), sysbus_get_default());
|
||||
|
||||
/* DMA Channels */
|
||||
object_initialize(&s->dma, sizeof(s->dma), TYPE_BCM2835_DMA);
|
||||
object_property_add_child(obj, "dma", OBJECT(&s->dma), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->dma), sysbus_get_default());
|
||||
|
||||
object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
|
||||
OBJECT(&s->gpu_bus_mr), &error_abort);
|
||||
}
|
||||
|
||||
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
@@ -78,7 +104,8 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
Object *obj;
|
||||
MemoryRegion *ram;
|
||||
Error *err = NULL;
|
||||
uint32_t ram_size;
|
||||
uint32_t ram_size, vcram_size;
|
||||
CharDriverState *chr;
|
||||
int n;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "ram", &err);
|
||||
@@ -131,6 +158,29 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
|
||||
INTERRUPT_UART));
|
||||
|
||||
/* AUX / UART1 */
|
||||
/* TODO: don't call qemu_char_get_next_serial() here, instead set
|
||||
* chardev properties for each uart at the board level, once pl011
|
||||
* (uart0) has been updated to avoid qemu_char_get_next_serial()
|
||||
*/
|
||||
chr = qemu_char_get_next_serial();
|
||||
if (chr == NULL) {
|
||||
chr = qemu_chr_new("bcm2835.uart1", "null", NULL);
|
||||
}
|
||||
qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->aux), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0,
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
|
||||
INTERRUPT_AUX));
|
||||
|
||||
/* Mailboxes */
|
||||
object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err);
|
||||
if (err) {
|
||||
@@ -144,13 +194,33 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
|
||||
INTERRUPT_ARM_MAILBOX));
|
||||
|
||||
/* Property channel */
|
||||
object_property_set_int(OBJECT(&s->property), ram_size, "ram-size", &err);
|
||||
/* Framebuffer */
|
||||
vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
|
||||
"vcram-base", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
|
||||
|
||||
/* Property channel */
|
||||
object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -171,6 +241,13 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -189,6 +266,24 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
/* DMA Channels */
|
||||
object_property_set_bool(OBJECT(&s->dma), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&s->peri_mr, DMA_OFFSET,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 0));
|
||||
memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
|
||||
|
||||
for (n = 0; n <= 12; n++) {
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n,
|
||||
qdev_get_gpio_in_named(DEVICE(&s->ic),
|
||||
BCM2835_IC_GPU_IRQ,
|
||||
INTERRUPT_DMA0 + n));
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
|
||||
@@ -196,6 +291,8 @@ static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = bcm2835_peripherals_realize;
|
||||
/* Reason: realize() method uses qemu_char_get_next_serial() */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo bcm2835_peripherals_type_info = {
|
||||
|
||||
@@ -42,6 +42,8 @@ static void bcm2836_init(Object *obj)
|
||||
&error_abort);
|
||||
object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
|
||||
"board-rev", &error_abort);
|
||||
object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
|
||||
"vcram-size", &error_abort);
|
||||
qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
|
||||
}
|
||||
|
||||
|
||||
@@ -291,6 +291,7 @@ static void fsl_imx25_class_init(ObjectClass *oc, void *data)
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
dc->desc = "i.MX25 SOC";
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx25_type_info = {
|
||||
|
||||
@@ -265,6 +265,7 @@ static void fsl_imx31_class_init(ObjectClass *oc, void *data)
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
dc->desc = "i.MX31 SOC";
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx31_type_info = {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* OpenPOWER Palmetto BMC
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/ast2400.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
static struct arm_boot_info palmetto_bmc_binfo = {
|
||||
.loader_start = AST2400_SDRAM_BASE,
|
||||
.board_id = 0,
|
||||
.nb_cpus = 1,
|
||||
};
|
||||
|
||||
typedef struct PalmettoBMCState {
|
||||
AST2400State soc;
|
||||
MemoryRegion ram;
|
||||
} PalmettoBMCState;
|
||||
|
||||
static void palmetto_bmc_init(MachineState *machine)
|
||||
{
|
||||
PalmettoBMCState *bmc;
|
||||
|
||||
bmc = g_new0(PalmettoBMCState, 1);
|
||||
object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
|
||||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE,
|
||||
&bmc->ram);
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
|
||||
palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
|
||||
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
palmetto_bmc_binfo.ram_size = ram_size;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "OpenPOWER Palmetto BMC";
|
||||
mc->init = palmetto_bmc_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init);
|
||||
+5
-7
@@ -113,6 +113,7 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
|
||||
static void raspi2_init(MachineState *machine)
|
||||
{
|
||||
RasPiState *s = g_new0(RasPiState, 1);
|
||||
uint32_t vcram_size;
|
||||
DriveInfo *di;
|
||||
BlockBackend *blk;
|
||||
BusState *bus;
|
||||
@@ -149,7 +150,9 @@ static void raspi2_init(MachineState *machine)
|
||||
qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
|
||||
object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
|
||||
|
||||
setup_boot(machine, 2, machine->ram_size);
|
||||
vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size",
|
||||
&error_abort);
|
||||
setup_boot(machine, 2, machine->ram_size - vcram_size);
|
||||
}
|
||||
|
||||
static void raspi2_machine_init(MachineClass *mc)
|
||||
@@ -161,11 +164,6 @@ static void raspi2_machine_init(MachineClass *mc)
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->max_cpus = BCM2836_NCPUS;
|
||||
|
||||
/* XXX: Temporary restriction in RAM size from the full 1GB. Since
|
||||
* we do not yet support the framebuffer / GPU, we need to limit
|
||||
* RAM usable by the OS to sit below the peripherals.
|
||||
*/
|
||||
mc->default_ram_size = 0x3F000000; /* BCM2836_PERI_BASE */
|
||||
mc->default_ram_size = 1024 * 1024 * 1024;
|
||||
};
|
||||
DEFINE_MACHINE("raspi2", raspi2_machine_init)
|
||||
|
||||
+38
-19
@@ -1345,7 +1345,32 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_instance_init(Object *obj)
|
||||
static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->init = machvirt_init;
|
||||
/* Start max_cpus at the maximum QEMU supports. We'll further restrict
|
||||
* it later in machvirt_init, where we have more information about the
|
||||
* configuration of the particular instance.
|
||||
*/
|
||||
mc->max_cpus = MAX_CPUMASK_BITS;
|
||||
mc->has_dynamic_sysbus = true;
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
mc->no_cdrom = 1;
|
||||
mc->pci_allow_0_address = true;
|
||||
}
|
||||
|
||||
static const TypeInfo virt_machine_info = {
|
||||
.name = TYPE_VIRT_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.abstract = true,
|
||||
.instance_size = sizeof(VirtMachineState),
|
||||
.class_size = sizeof(VirtMachineClass),
|
||||
.class_init = virt_machine_class_init,
|
||||
};
|
||||
|
||||
static void virt_2_6_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
@@ -1378,34 +1403,28 @@ static void virt_instance_init(Object *obj)
|
||||
"Valid values are 2, 3 and host", NULL);
|
||||
}
|
||||
|
||||
static void virt_class_init(ObjectClass *oc, void *data)
|
||||
static void virt_2_6_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
static GlobalProperty compat_props[] = {
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
mc->desc = "ARM Virtual Machine",
|
||||
mc->init = machvirt_init;
|
||||
/* Start max_cpus at the maximum QEMU supports. We'll further restrict
|
||||
* it later in machvirt_init, where we have more information about the
|
||||
* configuration of the particular instance.
|
||||
*/
|
||||
mc->max_cpus = MAX_CPUMASK_BITS;
|
||||
mc->has_dynamic_sysbus = true;
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
mc->no_cdrom = 1;
|
||||
mc->pci_allow_0_address = true;
|
||||
mc->desc = "QEMU 2.6 ARM Virtual Machine";
|
||||
mc->alias = "virt";
|
||||
mc->compat_props = compat_props;
|
||||
}
|
||||
|
||||
static const TypeInfo machvirt_info = {
|
||||
.name = TYPE_VIRT_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(VirtMachineState),
|
||||
.instance_init = virt_instance_init,
|
||||
.class_size = sizeof(VirtMachineClass),
|
||||
.class_init = virt_class_init,
|
||||
.name = MACHINE_TYPE_NAME("virt-2.6"),
|
||||
.parent = TYPE_VIRT_MACHINE,
|
||||
.instance_init = virt_2_6_instance_init,
|
||||
.class_init = virt_2_6_class_init,
|
||||
};
|
||||
|
||||
static void machvirt_machine_init(void)
|
||||
{
|
||||
type_register_static(&virt_machine_info);
|
||||
type_register_static(&machvirt_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_SH4) += sh_serial.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_vty.o
|
||||
obj-$(CONFIG_DIGIC) += digic-uart.o
|
||||
obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
|
||||
obj-$(CONFIG_RASPI) += bcm2835_aux.o
|
||||
|
||||
common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
|
||||
common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI).
|
||||
* Copyright (c) 2015, Microsoft
|
||||
* Written by Andrew Baumann
|
||||
* Based on pl011.c, copyright terms below:
|
||||
*
|
||||
* Arm PrimeCell PL011 UART
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licensed under the GPL.
|
||||
*
|
||||
* At present only the core UART functions (data path for tx/rx) are
|
||||
* implemented. The following features/registers are unimplemented:
|
||||
* - Line/modem control
|
||||
* - Scratch register
|
||||
* - Extra control
|
||||
* - Baudrate
|
||||
* - SPI interfaces
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/char/bcm2835_aux.h"
|
||||
|
||||
#define AUX_IRQ 0x0
|
||||
#define AUX_ENABLES 0x4
|
||||
#define AUX_MU_IO_REG 0x40
|
||||
#define AUX_MU_IER_REG 0x44
|
||||
#define AUX_MU_IIR_REG 0x48
|
||||
#define AUX_MU_LCR_REG 0x4c
|
||||
#define AUX_MU_MCR_REG 0x50
|
||||
#define AUX_MU_LSR_REG 0x54
|
||||
#define AUX_MU_MSR_REG 0x58
|
||||
#define AUX_MU_SCRATCH 0x5c
|
||||
#define AUX_MU_CNTL_REG 0x60
|
||||
#define AUX_MU_STAT_REG 0x64
|
||||
#define AUX_MU_BAUD_REG 0x68
|
||||
|
||||
/* bits in IER/IIR registers */
|
||||
#define TX_INT 0x1
|
||||
#define RX_INT 0x2
|
||||
|
||||
static void bcm2835_aux_update(BCM2835AuxState *s)
|
||||
{
|
||||
/* signal an interrupt if either:
|
||||
* 1. rx interrupt is enabled and we have a non-empty rx fifo, or
|
||||
* 2. the tx interrupt is enabled (since we instantly drain the tx fifo)
|
||||
*/
|
||||
s->iir = 0;
|
||||
if ((s->ier & RX_INT) && s->read_count != 0) {
|
||||
s->iir |= RX_INT;
|
||||
}
|
||||
if (s->ier & TX_INT) {
|
||||
s->iir |= TX_INT;
|
||||
}
|
||||
qemu_set_irq(s->irq, s->iir != 0);
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
BCM2835AuxState *s = opaque;
|
||||
uint32_t c, res;
|
||||
|
||||
switch (offset) {
|
||||
case AUX_IRQ:
|
||||
return s->iir != 0;
|
||||
|
||||
case AUX_ENABLES:
|
||||
return 1; /* mini UART permanently enabled */
|
||||
|
||||
case AUX_MU_IO_REG:
|
||||
/* "DLAB bit set means access baudrate register" is NYI */
|
||||
c = s->read_fifo[s->read_pos];
|
||||
if (s->read_count > 0) {
|
||||
s->read_count--;
|
||||
if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) {
|
||||
s->read_pos = 0;
|
||||
}
|
||||
}
|
||||
if (s->chr) {
|
||||
qemu_chr_accept_input(s->chr);
|
||||
}
|
||||
bcm2835_aux_update(s);
|
||||
return c;
|
||||
|
||||
case AUX_MU_IER_REG:
|
||||
/* "DLAB bit set means access baudrate register" is NYI */
|
||||
return 0xc0 | s->ier; /* FIFO enables always read 1 */
|
||||
|
||||
case AUX_MU_IIR_REG:
|
||||
res = 0xc0; /* FIFO enables */
|
||||
/* The spec is unclear on what happens when both tx and rx
|
||||
* interrupts are active, besides that this cannot occur. At
|
||||
* present, we choose to prioritise the rx interrupt, since
|
||||
* the tx fifo is always empty. */
|
||||
if (s->read_count != 0) {
|
||||
res |= 0x4;
|
||||
} else {
|
||||
res |= 0x2;
|
||||
}
|
||||
if (s->iir == 0) {
|
||||
res |= 0x1;
|
||||
}
|
||||
return res;
|
||||
|
||||
case AUX_MU_LCR_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
|
||||
return 0;
|
||||
|
||||
case AUX_MU_MCR_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
|
||||
return 0;
|
||||
|
||||
case AUX_MU_LSR_REG:
|
||||
res = 0x60; /* tx idle, empty */
|
||||
if (s->read_count != 0) {
|
||||
res |= 0x1;
|
||||
}
|
||||
return res;
|
||||
|
||||
case AUX_MU_MSR_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__);
|
||||
return 0;
|
||||
|
||||
case AUX_MU_SCRATCH:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
|
||||
return 0;
|
||||
|
||||
case AUX_MU_CNTL_REG:
|
||||
return 0x3; /* tx, rx enabled */
|
||||
|
||||
case AUX_MU_STAT_REG:
|
||||
res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */
|
||||
if (s->read_count > 0) {
|
||||
res |= 0x1; /* data in input buffer */
|
||||
assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN);
|
||||
res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
|
||||
}
|
||||
return res;
|
||||
|
||||
case AUX_MU_BAUD_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
BCM2835AuxState *s = opaque;
|
||||
unsigned char ch;
|
||||
|
||||
switch (offset) {
|
||||
case AUX_ENABLES:
|
||||
if (value != 1) {
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI "
|
||||
"or disable UART\n", __func__);
|
||||
}
|
||||
break;
|
||||
|
||||
case AUX_MU_IO_REG:
|
||||
/* "DLAB bit set means access baudrate register" is NYI */
|
||||
ch = value;
|
||||
if (s->chr) {
|
||||
qemu_chr_fe_write(s->chr, &ch, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case AUX_MU_IER_REG:
|
||||
/* "DLAB bit set means access baudrate register" is NYI */
|
||||
s->ier = value & (TX_INT | RX_INT);
|
||||
bcm2835_aux_update(s);
|
||||
break;
|
||||
|
||||
case AUX_MU_IIR_REG:
|
||||
if (value & 0x2) {
|
||||
s->read_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case AUX_MU_LCR_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__);
|
||||
break;
|
||||
|
||||
case AUX_MU_MCR_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__);
|
||||
break;
|
||||
|
||||
case AUX_MU_SCRATCH:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__);
|
||||
break;
|
||||
|
||||
case AUX_MU_CNTL_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__);
|
||||
break;
|
||||
|
||||
case AUX_MU_BAUD_REG:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
|
||||
bcm2835_aux_update(s);
|
||||
}
|
||||
|
||||
static int bcm2835_aux_can_receive(void *opaque)
|
||||
{
|
||||
BCM2835AuxState *s = opaque;
|
||||
|
||||
return s->read_count < BCM2835_AUX_RX_FIFO_LEN;
|
||||
}
|
||||
|
||||
static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
|
||||
{
|
||||
BCM2835AuxState *s = opaque;
|
||||
int slot;
|
||||
|
||||
slot = s->read_pos + s->read_count;
|
||||
if (slot >= BCM2835_AUX_RX_FIFO_LEN) {
|
||||
slot -= BCM2835_AUX_RX_FIFO_LEN;
|
||||
}
|
||||
s->read_fifo[slot] = value;
|
||||
s->read_count++;
|
||||
if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) {
|
||||
/* buffer full */
|
||||
}
|
||||
bcm2835_aux_update(s);
|
||||
}
|
||||
|
||||
static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
bcm2835_aux_put_fifo(opaque, *buf);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bcm2835_aux_ops = {
|
||||
.read = bcm2835_aux_read,
|
||||
.write = bcm2835_aux_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_bcm2835_aux = {
|
||||
.name = TYPE_BCM2835_AUX,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState,
|
||||
BCM2835_AUX_RX_FIFO_LEN),
|
||||
VMSTATE_UINT8(read_pos, BCM2835AuxState),
|
||||
VMSTATE_UINT8(read_count, BCM2835AuxState),
|
||||
VMSTATE_UINT8(ier, BCM2835AuxState),
|
||||
VMSTATE_UINT8(iir, BCM2835AuxState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void bcm2835_aux_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
BCM2835AuxState *s = BCM2835_AUX(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s,
|
||||
TYPE_BCM2835_AUX, 0x100);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
BCM2835AuxState *s = BCM2835_AUX(dev);
|
||||
|
||||
if (s->chr) {
|
||||
qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
|
||||
bcm2835_aux_receive, NULL, s);
|
||||
}
|
||||
}
|
||||
|
||||
static Property bcm2835_aux_props[] = {
|
||||
DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void bcm2835_aux_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = bcm2835_aux_realize;
|
||||
dc->vmsd = &vmstate_bcm2835_aux;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
dc->props = bcm2835_aux_props;
|
||||
}
|
||||
|
||||
static const TypeInfo bcm2835_aux_info = {
|
||||
.name = TYPE_BCM2835_AUX,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(BCM2835AuxState),
|
||||
.instance_init = bcm2835_aux_init,
|
||||
.class_init = bcm2835_aux_class_init,
|
||||
};
|
||||
|
||||
static void bcm2835_aux_register_types(void)
|
||||
{
|
||||
type_register_static(&bcm2835_aux_info);
|
||||
}
|
||||
|
||||
type_init(bcm2835_aux_register_types)
|
||||
@@ -27,6 +27,7 @@ endif
|
||||
obj-$(CONFIG_OMAP) += omap_dss.o
|
||||
obj-$(CONFIG_OMAP) += omap_lcdc.o
|
||||
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
|
||||
obj-$(CONFIG_RASPI) += bcm2835_fb.o
|
||||
obj-$(CONFIG_SM501) += sm501.o
|
||||
obj-$(CONFIG_TCX) += tcx.o
|
||||
obj-$(CONFIG_CG3) += cg3.o
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Raspberry Pi emulation (c) 2012 Gregory Estrade
|
||||
* Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
|
||||
* This code is licensed under the GNU GPLv2 and later.
|
||||
*
|
||||
* Heavily based on milkymist-vgafb.c, copyright terms below:
|
||||
* QEMU model of the Milkymist VGA framebuffer.
|
||||
*
|
||||
* Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/display/bcm2835_fb.h"
|
||||
#include "hw/display/framebuffer.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
#include "hw/misc/bcm2835_mbox_defs.h"
|
||||
|
||||
#define DEFAULT_VCRAM_SIZE 0x4000000
|
||||
#define BCM2835_FB_OFFSET 0x00100000
|
||||
|
||||
static void fb_invalidate_display(void *opaque)
|
||||
{
|
||||
BCM2835FBState *s = BCM2835_FB(opaque);
|
||||
|
||||
s->invalidate = true;
|
||||
}
|
||||
|
||||
static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
|
||||
int width, int deststep)
|
||||
{
|
||||
BCM2835FBState *s = opaque;
|
||||
uint16_t rgb565;
|
||||
uint32_t rgb888;
|
||||
uint8_t r, g, b;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int bpp = surface_bits_per_pixel(surface);
|
||||
|
||||
while (width--) {
|
||||
switch (s->bpp) {
|
||||
case 8:
|
||||
/* lookup palette starting at video ram base
|
||||
* TODO: cache translation, rather than doing this each time!
|
||||
*/
|
||||
rgb888 = ldl_le_phys(&s->dma_as, s->vcram_base + (*src << 2));
|
||||
r = (rgb888 >> 0) & 0xff;
|
||||
g = (rgb888 >> 8) & 0xff;
|
||||
b = (rgb888 >> 16) & 0xff;
|
||||
src++;
|
||||
break;
|
||||
case 16:
|
||||
rgb565 = lduw_le_p(src);
|
||||
r = ((rgb565 >> 11) & 0x1f) << 3;
|
||||
g = ((rgb565 >> 5) & 0x3f) << 2;
|
||||
b = ((rgb565 >> 0) & 0x1f) << 3;
|
||||
src += 2;
|
||||
break;
|
||||
case 24:
|
||||
rgb888 = ldl_le_p(src);
|
||||
r = (rgb888 >> 0) & 0xff;
|
||||
g = (rgb888 >> 8) & 0xff;
|
||||
b = (rgb888 >> 16) & 0xff;
|
||||
src += 3;
|
||||
break;
|
||||
case 32:
|
||||
rgb888 = ldl_le_p(src);
|
||||
r = (rgb888 >> 0) & 0xff;
|
||||
g = (rgb888 >> 8) & 0xff;
|
||||
b = (rgb888 >> 16) & 0xff;
|
||||
src += 4;
|
||||
break;
|
||||
default:
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->pixo == 0) {
|
||||
/* swap to BGR pixel format */
|
||||
uint8_t tmp = r;
|
||||
r = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
*dst++ = rgb_to_pixel8(r, g, b);
|
||||
break;
|
||||
case 15:
|
||||
*(uint16_t *)dst = rgb_to_pixel15(r, g, b);
|
||||
dst += 2;
|
||||
break;
|
||||
case 16:
|
||||
*(uint16_t *)dst = rgb_to_pixel16(r, g, b);
|
||||
dst += 2;
|
||||
break;
|
||||
case 24:
|
||||
rgb888 = rgb_to_pixel24(r, g, b);
|
||||
*dst++ = rgb888 & 0xff;
|
||||
*dst++ = (rgb888 >> 8) & 0xff;
|
||||
*dst++ = (rgb888 >> 16) & 0xff;
|
||||
break;
|
||||
case 32:
|
||||
*(uint32_t *)dst = rgb_to_pixel32(r, g, b);
|
||||
dst += 4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_update_display(void *opaque)
|
||||
{
|
||||
BCM2835FBState *s = opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int first = 0;
|
||||
int last = 0;
|
||||
int src_width = 0;
|
||||
int dest_width = 0;
|
||||
|
||||
if (s->lock || !s->xres) {
|
||||
return;
|
||||
}
|
||||
|
||||
src_width = s->xres * (s->bpp >> 3);
|
||||
dest_width = s->xres;
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
case 0:
|
||||
return;
|
||||
case 8:
|
||||
break;
|
||||
case 15:
|
||||
dest_width *= 2;
|
||||
break;
|
||||
case 16:
|
||||
dest_width *= 2;
|
||||
break;
|
||||
case 24:
|
||||
dest_width *= 3;
|
||||
break;
|
||||
case 32:
|
||||
dest_width *= 4;
|
||||
break;
|
||||
default:
|
||||
hw_error("bcm2835_fb: bad color depth\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->invalidate) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
|
||||
s->yres, src_width);
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, dest_width, 0, s->invalidate,
|
||||
draw_line_src16, s, &first, &last);
|
||||
|
||||
if (first >= 0) {
|
||||
dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
|
||||
}
|
||||
|
||||
s->invalidate = false;
|
||||
}
|
||||
|
||||
static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
|
||||
{
|
||||
value &= ~0xf;
|
||||
|
||||
s->lock = true;
|
||||
|
||||
s->xres = ldl_le_phys(&s->dma_as, value);
|
||||
s->yres = ldl_le_phys(&s->dma_as, value + 4);
|
||||
s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
|
||||
s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
|
||||
s->bpp = ldl_le_phys(&s->dma_as, value + 20);
|
||||
s->xoffset = ldl_le_phys(&s->dma_as, value + 24);
|
||||
s->yoffset = ldl_le_phys(&s->dma_as, value + 28);
|
||||
|
||||
s->base = s->vcram_base | (value & 0xc0000000);
|
||||
s->base += BCM2835_FB_OFFSET;
|
||||
|
||||
/* TODO - Manage properly virtual resolution */
|
||||
|
||||
s->pitch = s->xres * (s->bpp >> 3);
|
||||
s->size = s->yres * s->pitch;
|
||||
|
||||
stl_le_phys(&s->dma_as, value + 16, s->pitch);
|
||||
stl_le_phys(&s->dma_as, value + 32, s->base);
|
||||
stl_le_phys(&s->dma_as, value + 36, s->size);
|
||||
|
||||
s->invalidate = true;
|
||||
qemu_console_resize(s->con, s->xres, s->yres);
|
||||
s->lock = false;
|
||||
}
|
||||
|
||||
void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
|
||||
uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
|
||||
uint32_t *pixo, uint32_t *alpha)
|
||||
{
|
||||
s->lock = true;
|
||||
|
||||
/* TODO: input validation! */
|
||||
if (xres) {
|
||||
s->xres = *xres;
|
||||
}
|
||||
if (yres) {
|
||||
s->yres = *yres;
|
||||
}
|
||||
if (xoffset) {
|
||||
s->xoffset = *xoffset;
|
||||
}
|
||||
if (yoffset) {
|
||||
s->yoffset = *yoffset;
|
||||
}
|
||||
if (bpp) {
|
||||
s->bpp = *bpp;
|
||||
}
|
||||
if (pixo) {
|
||||
s->pixo = *pixo;
|
||||
}
|
||||
if (alpha) {
|
||||
s->alpha = *alpha;
|
||||
}
|
||||
|
||||
/* TODO - Manage properly virtual resolution */
|
||||
|
||||
s->pitch = s->xres * (s->bpp >> 3);
|
||||
s->size = s->yres * s->pitch;
|
||||
|
||||
s->invalidate = true;
|
||||
qemu_console_resize(s->con, s->xres, s->yres);
|
||||
s->lock = false;
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
BCM2835FBState *s = opaque;
|
||||
uint32_t res = 0;
|
||||
|
||||
switch (offset) {
|
||||
case MBOX_AS_DATA:
|
||||
res = MBOX_CHAN_FB;
|
||||
s->pending = false;
|
||||
qemu_set_irq(s->mbox_irq, 0);
|
||||
break;
|
||||
|
||||
case MBOX_AS_PENDING:
|
||||
res = s->pending;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void bcm2835_fb_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
BCM2835FBState *s = opaque;
|
||||
|
||||
switch (offset) {
|
||||
case MBOX_AS_DATA:
|
||||
/* bcm2835_mbox should check our pending status before pushing */
|
||||
assert(!s->pending);
|
||||
s->pending = true;
|
||||
bcm2835_fb_mbox_push(s, value);
|
||||
qemu_set_irq(s->mbox_irq, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bcm2835_fb_ops = {
|
||||
.read = bcm2835_fb_read,
|
||||
.write = bcm2835_fb_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_bcm2835_fb = {
|
||||
.name = TYPE_BCM2835_FB,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(lock, BCM2835FBState),
|
||||
VMSTATE_BOOL(invalidate, BCM2835FBState),
|
||||
VMSTATE_BOOL(pending, BCM2835FBState),
|
||||
VMSTATE_UINT32(xres, BCM2835FBState),
|
||||
VMSTATE_UINT32(yres, BCM2835FBState),
|
||||
VMSTATE_UINT32(xres_virtual, BCM2835FBState),
|
||||
VMSTATE_UINT32(yres_virtual, BCM2835FBState),
|
||||
VMSTATE_UINT32(xoffset, BCM2835FBState),
|
||||
VMSTATE_UINT32(yoffset, BCM2835FBState),
|
||||
VMSTATE_UINT32(bpp, BCM2835FBState),
|
||||
VMSTATE_UINT32(base, BCM2835FBState),
|
||||
VMSTATE_UINT32(pitch, BCM2835FBState),
|
||||
VMSTATE_UINT32(size, BCM2835FBState),
|
||||
VMSTATE_UINT32(pixo, BCM2835FBState),
|
||||
VMSTATE_UINT32(alpha, BCM2835FBState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const GraphicHwOps vgafb_ops = {
|
||||
.invalidate = fb_invalidate_display,
|
||||
.gfx_update = fb_update_display,
|
||||
};
|
||||
|
||||
static void bcm2835_fb_init(Object *obj)
|
||||
{
|
||||
BCM2835FBState *s = BCM2835_FB(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &bcm2835_fb_ops, s, TYPE_BCM2835_FB,
|
||||
0x10);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
|
||||
}
|
||||
|
||||
static void bcm2835_fb_reset(DeviceState *dev)
|
||||
{
|
||||
BCM2835FBState *s = BCM2835_FB(dev);
|
||||
|
||||
s->pending = false;
|
||||
|
||||
s->xres_virtual = s->xres;
|
||||
s->yres_virtual = s->yres;
|
||||
s->xoffset = 0;
|
||||
s->yoffset = 0;
|
||||
s->base = s->vcram_base + BCM2835_FB_OFFSET;
|
||||
s->pitch = s->xres * (s->bpp >> 3);
|
||||
s->size = s->yres * s->pitch;
|
||||
|
||||
s->invalidate = true;
|
||||
s->lock = false;
|
||||
}
|
||||
|
||||
static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
BCM2835FBState *s = BCM2835_FB(dev);
|
||||
Error *err = NULL;
|
||||
Object *obj;
|
||||
|
||||
if (s->vcram_base == 0) {
|
||||
error_setg(errp, "%s: required vcram-base property not set", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
|
||||
if (obj == NULL) {
|
||||
error_setg(errp, "%s: required dma-mr link not found: %s",
|
||||
__func__, error_get_pretty(err));
|
||||
return;
|
||||
}
|
||||
|
||||
s->dma_mr = MEMORY_REGION(obj);
|
||||
address_space_init(&s->dma_as, s->dma_mr, NULL);
|
||||
|
||||
bcm2835_fb_reset(dev);
|
||||
|
||||
s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
|
||||
qemu_console_resize(s->con, s->xres, s->yres);
|
||||
}
|
||||
|
||||
static Property bcm2835_fb_props[] = {
|
||||
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
|
||||
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
|
||||
DEFAULT_VCRAM_SIZE),
|
||||
DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
|
||||
DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
|
||||
DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
|
||||
DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
|
||||
DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = bcm2835_fb_props;
|
||||
dc->realize = bcm2835_fb_realize;
|
||||
dc->reset = bcm2835_fb_reset;
|
||||
dc->vmsd = &vmstate_bcm2835_fb;
|
||||
}
|
||||
|
||||
static TypeInfo bcm2835_fb_info = {
|
||||
.name = TYPE_BCM2835_FB,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(BCM2835FBState),
|
||||
.class_init = bcm2835_fb_class_init,
|
||||
.instance_init = bcm2835_fb_init,
|
||||
};
|
||||
|
||||
static void bcm2835_fb_register_types(void)
|
||||
{
|
||||
type_register_static(&bcm2835_fb_info);
|
||||
}
|
||||
|
||||
type_init(bcm2835_fb_register_types)
|
||||
@@ -11,3 +11,4 @@ common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
|
||||
obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o
|
||||
obj-$(CONFIG_RASPI) += bcm2835_dma.o
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Raspberry Pi emulation (c) 2012 Gregory Estrade
|
||||
* This code is licensed under the GNU GPLv2 and later.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/dma/bcm2835_dma.h"
|
||||
|
||||
/* DMA CS Control and Status bits */
|
||||
#define BCM2708_DMA_ACTIVE (1 << 0)
|
||||
#define BCM2708_DMA_END (1 << 1) /* GE */
|
||||
#define BCM2708_DMA_INT (1 << 2)
|
||||
#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
|
||||
#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
|
||||
#define BCM2708_DMA_ERR (1 << 8)
|
||||
#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
|
||||
#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
|
||||
|
||||
/* DMA control block "info" field bits */
|
||||
#define BCM2708_DMA_INT_EN (1 << 0)
|
||||
#define BCM2708_DMA_TDMODE (1 << 1)
|
||||
#define BCM2708_DMA_WAIT_RESP (1 << 3)
|
||||
#define BCM2708_DMA_D_INC (1 << 4)
|
||||
#define BCM2708_DMA_D_WIDTH (1 << 5)
|
||||
#define BCM2708_DMA_D_DREQ (1 << 6)
|
||||
#define BCM2708_DMA_D_IGNORE (1 << 7)
|
||||
#define BCM2708_DMA_S_INC (1 << 8)
|
||||
#define BCM2708_DMA_S_WIDTH (1 << 9)
|
||||
#define BCM2708_DMA_S_DREQ (1 << 10)
|
||||
#define BCM2708_DMA_S_IGNORE (1 << 11)
|
||||
|
||||
/* Register offsets */
|
||||
#define BCM2708_DMA_CS 0x00 /* Control and Status */
|
||||
#define BCM2708_DMA_ADDR 0x04 /* Control block address */
|
||||
/* the current control block appears in the following registers - read only */
|
||||
#define BCM2708_DMA_INFO 0x08
|
||||
#define BCM2708_DMA_SOURCE_AD 0x0c
|
||||
#define BCM2708_DMA_DEST_AD 0x10
|
||||
#define BCM2708_DMA_TXFR_LEN 0x14
|
||||
#define BCM2708_DMA_STRIDE 0x18
|
||||
#define BCM2708_DMA_NEXTCB 0x1C
|
||||
#define BCM2708_DMA_DEBUG 0x20
|
||||
|
||||
#define BCM2708_DMA_INT_STATUS 0xfe0 /* Interrupt status of each channel */
|
||||
#define BCM2708_DMA_ENABLE 0xff0 /* Global enable bits for each channel */
|
||||
|
||||
#define BCM2708_DMA_CS_RW_MASK 0x30ff0001 /* All RW bits in DMA_CS */
|
||||
|
||||
static void bcm2835_dma_update(BCM2835DMAState *s, unsigned c)
|
||||
{
|
||||
BCM2835DMAChan *ch = &s->chan[c];
|
||||
uint32_t data, xlen, ylen;
|
||||
int16_t dst_stride, src_stride;
|
||||
|
||||
if (!(s->enable & (1 << c))) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((s->enable & (1 << c)) && (ch->conblk_ad != 0)) {
|
||||
/* CB fetch */
|
||||
ch->ti = ldl_le_phys(&s->dma_as, ch->conblk_ad);
|
||||
ch->source_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 4);
|
||||
ch->dest_ad = ldl_le_phys(&s->dma_as, ch->conblk_ad + 8);
|
||||
ch->txfr_len = ldl_le_phys(&s->dma_as, ch->conblk_ad + 12);
|
||||
ch->stride = ldl_le_phys(&s->dma_as, ch->conblk_ad + 16);
|
||||
ch->nextconbk = ldl_le_phys(&s->dma_as, ch->conblk_ad + 20);
|
||||
|
||||
if (ch->ti & BCM2708_DMA_TDMODE) {
|
||||
/* 2D transfer mode */
|
||||
ylen = (ch->txfr_len >> 16) & 0x3fff;
|
||||
xlen = ch->txfr_len & 0xffff;
|
||||
dst_stride = ch->stride >> 16;
|
||||
src_stride = ch->stride & 0xffff;
|
||||
} else {
|
||||
ylen = 1;
|
||||
xlen = ch->txfr_len;
|
||||
dst_stride = 0;
|
||||
src_stride = 0;
|
||||
}
|
||||
|
||||
while (ylen != 0) {
|
||||
/* Normal transfer mode */
|
||||
while (xlen != 0) {
|
||||
if (ch->ti & BCM2708_DMA_S_IGNORE) {
|
||||
/* Ignore reads */
|
||||
data = 0;
|
||||
} else {
|
||||
data = ldl_le_phys(&s->dma_as, ch->source_ad);
|
||||
}
|
||||
if (ch->ti & BCM2708_DMA_S_INC) {
|
||||
ch->source_ad += 4;
|
||||
}
|
||||
|
||||
if (ch->ti & BCM2708_DMA_D_IGNORE) {
|
||||
/* Ignore writes */
|
||||
} else {
|
||||
stl_le_phys(&s->dma_as, ch->dest_ad, data);
|
||||
}
|
||||
if (ch->ti & BCM2708_DMA_D_INC) {
|
||||
ch->dest_ad += 4;
|
||||
}
|
||||
|
||||
/* update remaining transfer length */
|
||||
xlen -= 4;
|
||||
if (ch->ti & BCM2708_DMA_TDMODE) {
|
||||
ch->txfr_len = (ylen << 16) | xlen;
|
||||
} else {
|
||||
ch->txfr_len = xlen;
|
||||
}
|
||||
}
|
||||
|
||||
if (--ylen != 0) {
|
||||
ch->source_ad += src_stride;
|
||||
ch->dest_ad += dst_stride;
|
||||
}
|
||||
}
|
||||
ch->cs |= BCM2708_DMA_END;
|
||||
if (ch->ti & BCM2708_DMA_INT_EN) {
|
||||
ch->cs |= BCM2708_DMA_INT;
|
||||
s->int_status |= (1 << c);
|
||||
qemu_set_irq(ch->irq, 1);
|
||||
}
|
||||
|
||||
/* Process next CB */
|
||||
ch->conblk_ad = ch->nextconbk;
|
||||
}
|
||||
|
||||
ch->cs &= ~BCM2708_DMA_ACTIVE;
|
||||
ch->cs |= BCM2708_DMA_ISPAUSED;
|
||||
}
|
||||
|
||||
static void bcm2835_dma_chan_reset(BCM2835DMAChan *ch)
|
||||
{
|
||||
ch->cs = 0;
|
||||
ch->conblk_ad = 0;
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_dma_read(BCM2835DMAState *s, hwaddr offset,
|
||||
unsigned size, unsigned c)
|
||||
{
|
||||
BCM2835DMAChan *ch;
|
||||
uint32_t res = 0;
|
||||
|
||||
assert(size == 4);
|
||||
assert(c < BCM2835_DMA_NCHANS);
|
||||
|
||||
ch = &s->chan[c];
|
||||
|
||||
switch (offset) {
|
||||
case BCM2708_DMA_CS:
|
||||
res = ch->cs;
|
||||
break;
|
||||
case BCM2708_DMA_ADDR:
|
||||
res = ch->conblk_ad;
|
||||
break;
|
||||
case BCM2708_DMA_INFO:
|
||||
res = ch->ti;
|
||||
break;
|
||||
case BCM2708_DMA_SOURCE_AD:
|
||||
res = ch->source_ad;
|
||||
break;
|
||||
case BCM2708_DMA_DEST_AD:
|
||||
res = ch->dest_ad;
|
||||
break;
|
||||
case BCM2708_DMA_TXFR_LEN:
|
||||
res = ch->txfr_len;
|
||||
break;
|
||||
case BCM2708_DMA_STRIDE:
|
||||
res = ch->stride;
|
||||
break;
|
||||
case BCM2708_DMA_NEXTCB:
|
||||
res = ch->nextconbk;
|
||||
break;
|
||||
case BCM2708_DMA_DEBUG:
|
||||
res = ch->debug;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset,
|
||||
uint64_t value, unsigned size, unsigned c)
|
||||
{
|
||||
BCM2835DMAChan *ch;
|
||||
uint32_t oldcs;
|
||||
|
||||
assert(size == 4);
|
||||
assert(c < BCM2835_DMA_NCHANS);
|
||||
|
||||
ch = &s->chan[c];
|
||||
|
||||
switch (offset) {
|
||||
case BCM2708_DMA_CS:
|
||||
oldcs = ch->cs;
|
||||
if (value & BCM2708_DMA_RESET) {
|
||||
bcm2835_dma_chan_reset(ch);
|
||||
}
|
||||
if (value & BCM2708_DMA_ABORT) {
|
||||
/* abort is a no-op, since we always run to completion */
|
||||
}
|
||||
if (value & BCM2708_DMA_END) {
|
||||
ch->cs &= ~BCM2708_DMA_END;
|
||||
}
|
||||
if (value & BCM2708_DMA_INT) {
|
||||
ch->cs &= ~BCM2708_DMA_INT;
|
||||
s->int_status &= ~(1 << c);
|
||||
qemu_set_irq(ch->irq, 0);
|
||||
}
|
||||
ch->cs &= ~BCM2708_DMA_CS_RW_MASK;
|
||||
ch->cs |= (value & BCM2708_DMA_CS_RW_MASK);
|
||||
if (!(oldcs & BCM2708_DMA_ACTIVE) && (ch->cs & BCM2708_DMA_ACTIVE)) {
|
||||
bcm2835_dma_update(s, c);
|
||||
}
|
||||
break;
|
||||
case BCM2708_DMA_ADDR:
|
||||
ch->conblk_ad = value;
|
||||
break;
|
||||
case BCM2708_DMA_DEBUG:
|
||||
ch->debug = value;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_dma0_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
BCM2835DMAState *s = opaque;
|
||||
|
||||
if (offset < 0xf00) {
|
||||
return bcm2835_dma_read(s, (offset & 0xff), size, (offset >> 8) & 0xf);
|
||||
} else {
|
||||
switch (offset) {
|
||||
case BCM2708_DMA_INT_STATUS:
|
||||
return s->int_status;
|
||||
case BCM2708_DMA_ENABLE:
|
||||
return s->enable;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
return bcm2835_dma_read(opaque, (offset & 0xff), size, 15);
|
||||
}
|
||||
|
||||
static void bcm2835_dma0_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
BCM2835DMAState *s = opaque;
|
||||
|
||||
if (offset < 0xf00) {
|
||||
bcm2835_dma_write(s, (offset & 0xff), value, size, (offset >> 8) & 0xf);
|
||||
} else {
|
||||
switch (offset) {
|
||||
case BCM2708_DMA_INT_STATUS:
|
||||
break;
|
||||
case BCM2708_DMA_ENABLE:
|
||||
s->enable = (value & 0xffff);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void bcm2835_dma15_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
bcm2835_dma_write(opaque, (offset & 0xff), value, size, 15);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps bcm2835_dma0_ops = {
|
||||
.read = bcm2835_dma0_read,
|
||||
.write = bcm2835_dma0_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps bcm2835_dma15_ops = {
|
||||
.read = bcm2835_dma15_read,
|
||||
.write = bcm2835_dma15_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_bcm2835_dma_chan = {
|
||||
.name = TYPE_BCM2835_DMA "-chan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(cs, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(conblk_ad, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(ti, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(source_ad, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(dest_ad, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(txfr_len, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(stride, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(nextconbk, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(debug, BCM2835DMAChan),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_bcm2835_dma = {
|
||||
.name = TYPE_BCM2835_DMA,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(chan, BCM2835DMAState, BCM2835_DMA_NCHANS, 1,
|
||||
vmstate_bcm2835_dma_chan, BCM2835DMAChan),
|
||||
VMSTATE_UINT32(int_status, BCM2835DMAState),
|
||||
VMSTATE_UINT32(enable, BCM2835DMAState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void bcm2835_dma_init(Object *obj)
|
||||
{
|
||||
BCM2835DMAState *s = BCM2835_DMA(obj);
|
||||
int n;
|
||||
|
||||
/* DMA channels 0-14 occupy a contiguous block of IO memory, along
|
||||
* with the global enable and interrupt status bits. Channel 15
|
||||
* has the same register map, but is mapped at a discontiguous
|
||||
* address in a separate IO block.
|
||||
*/
|
||||
memory_region_init_io(&s->iomem0, OBJECT(s), &bcm2835_dma0_ops, s,
|
||||
TYPE_BCM2835_DMA, 0x1000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem0);
|
||||
|
||||
memory_region_init_io(&s->iomem15, OBJECT(s), &bcm2835_dma15_ops, s,
|
||||
TYPE_BCM2835_DMA "-chan15", 0x100);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem15);
|
||||
|
||||
for (n = 0; n < 16; n++) {
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->chan[n].irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm2835_dma_reset(DeviceState *dev)
|
||||
{
|
||||
BCM2835DMAState *s = BCM2835_DMA(dev);
|
||||
int n;
|
||||
|
||||
s->enable = 0xffff;
|
||||
s->int_status = 0;
|
||||
for (n = 0; n < BCM2835_DMA_NCHANS; n++) {
|
||||
bcm2835_dma_chan_reset(&s->chan[n]);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm2835_dma_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
BCM2835DMAState *s = BCM2835_DMA(dev);
|
||||
Error *err = NULL;
|
||||
Object *obj;
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
|
||||
if (obj == NULL) {
|
||||
error_setg(errp, "%s: required dma-mr link not found: %s",
|
||||
__func__, error_get_pretty(err));
|
||||
return;
|
||||
}
|
||||
|
||||
s->dma_mr = MEMORY_REGION(obj);
|
||||
address_space_init(&s->dma_as, s->dma_mr, NULL);
|
||||
|
||||
bcm2835_dma_reset(dev);
|
||||
}
|
||||
|
||||
static void bcm2835_dma_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = bcm2835_dma_realize;
|
||||
dc->reset = bcm2835_dma_reset;
|
||||
dc->vmsd = &vmstate_bcm2835_dma;
|
||||
}
|
||||
|
||||
static TypeInfo bcm2835_dma_info = {
|
||||
.name = TYPE_BCM2835_DMA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(BCM2835DMAState),
|
||||
.class_init = bcm2835_dma_class_init,
|
||||
.instance_init = bcm2835_dma_init,
|
||||
};
|
||||
|
||||
static void bcm2835_dma_register_types(void)
|
||||
{
|
||||
type_register_static(&bcm2835_dma_info);
|
||||
}
|
||||
|
||||
type_init(bcm2835_dma_register_types)
|
||||
@@ -319,6 +319,7 @@ static void imx_i2c_class_init(ObjectClass *klass, void *data)
|
||||
dc->vmsd = &imx_i2c_vmstate;
|
||||
dc->reset = imx_i2c_reset;
|
||||
dc->realize = imx_i2c_realize;
|
||||
dc->desc = "i.MX I2C Controller";
|
||||
}
|
||||
|
||||
static const TypeInfo imx_i2c_type_info = {
|
||||
|
||||
@@ -31,3 +31,4 @@ obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* ASPEED Interrupt Controller (New)
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* Copyright 2015, 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/* The hardware exposes two register sets, a legacy set and a 'new' set. The
|
||||
* model implements the 'new' register set, and logs warnings on accesses to
|
||||
* the legacy IO space.
|
||||
*
|
||||
* The hardware uses 32bit registers to manage 51 IRQs, with low and high
|
||||
* registers for each conceptual register. The device model's implementation
|
||||
* uses 64bit data types to store both low and high register values (in the one
|
||||
* member), but must cope with access offset values in multiples of 4 passed to
|
||||
* the callbacks. As such the read() and write() implementations process the
|
||||
* provided offset to understand whether the access is requesting the lower or
|
||||
* upper 32 bits of the 64bit member.
|
||||
*
|
||||
* Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt"
|
||||
* fields have separate "enable"/"status" and "clear" registers, where set bits
|
||||
* are written to one or the other to change state (avoiding a
|
||||
* read-modify-write sequence).
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <inttypes.h>
|
||||
#include "hw/intc/aspeed_vic.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define AVIC_NEW_BASE_OFFSET 0x80
|
||||
|
||||
#define AVIC_L_MASK 0xFFFFFFFFU
|
||||
#define AVIC_H_MASK 0x0007FFFFU
|
||||
#define AVIC_EVENT_W_MASK (0x78000ULL << 32)
|
||||
|
||||
static void aspeed_vic_update(AspeedVICState *s)
|
||||
{
|
||||
uint64_t new = (s->raw & s->enable);
|
||||
uint64_t flags;
|
||||
|
||||
flags = new & s->select;
|
||||
trace_aspeed_vic_update_fiq(!!flags);
|
||||
qemu_set_irq(s->fiq, !!flags);
|
||||
|
||||
flags = new & ~s->select;
|
||||
trace_aspeed_vic_update_irq(!!flags);
|
||||
qemu_set_irq(s->irq, !!flags);
|
||||
}
|
||||
|
||||
static void aspeed_vic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
uint64_t irq_mask;
|
||||
bool raise;
|
||||
AspeedVICState *s = (AspeedVICState *)opaque;
|
||||
|
||||
if (irq > ASPEED_VIC_NR_IRQS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
|
||||
__func__, irq);
|
||||
return;
|
||||
}
|
||||
|
||||
trace_aspeed_vic_set_irq(irq, level);
|
||||
|
||||
irq_mask = BIT(irq);
|
||||
if (s->sense & irq_mask) {
|
||||
/* level-triggered */
|
||||
if (s->event & irq_mask) {
|
||||
/* high-sensitive */
|
||||
raise = level;
|
||||
} else {
|
||||
/* low-sensitive */
|
||||
raise = !level;
|
||||
}
|
||||
s->raw = deposit64(s->raw, irq, 1, raise);
|
||||
} else {
|
||||
uint64_t old_level = s->level & irq_mask;
|
||||
|
||||
/* edge-triggered */
|
||||
if (s->dual_edge & irq_mask) {
|
||||
raise = (!!old_level) != (!!level);
|
||||
} else {
|
||||
if (s->event & irq_mask) {
|
||||
/* rising-sensitive */
|
||||
raise = !old_level && level;
|
||||
} else {
|
||||
/* falling-sensitive */
|
||||
raise = old_level && !level;
|
||||
}
|
||||
}
|
||||
if (raise) {
|
||||
s->raw = deposit64(s->raw, irq, 1, raise);
|
||||
}
|
||||
}
|
||||
s->level = deposit64(s->level, irq, 1, level);
|
||||
aspeed_vic_update(s);
|
||||
}
|
||||
|
||||
static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint64_t val;
|
||||
const bool high = !!(offset & 0x4);
|
||||
hwaddr n_offset = (offset & ~0x4);
|
||||
AspeedVICState *s = (AspeedVICState *)opaque;
|
||||
|
||||
if (offset < AVIC_NEW_BASE_OFFSET) {
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
|
||||
"at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n_offset -= AVIC_NEW_BASE_OFFSET;
|
||||
|
||||
switch (n_offset) {
|
||||
case 0x0: /* IRQ Status */
|
||||
val = s->raw & ~s->select & s->enable;
|
||||
break;
|
||||
case 0x08: /* FIQ Status */
|
||||
val = s->raw & s->select & s->enable;
|
||||
break;
|
||||
case 0x10: /* Raw Interrupt Status */
|
||||
val = s->raw;
|
||||
break;
|
||||
case 0x18: /* Interrupt Selection */
|
||||
val = s->select;
|
||||
break;
|
||||
case 0x20: /* Interrupt Enable */
|
||||
val = s->enable;
|
||||
break;
|
||||
case 0x30: /* Software Interrupt */
|
||||
val = s->trigger;
|
||||
break;
|
||||
case 0x40: /* Interrupt Sensitivity */
|
||||
val = s->sense;
|
||||
break;
|
||||
case 0x48: /* Interrupt Both Edge Trigger Control */
|
||||
val = s->dual_edge;
|
||||
break;
|
||||
case 0x50: /* Interrupt Event */
|
||||
val = s->event;
|
||||
break;
|
||||
case 0x60: /* Edge Triggered Interrupt Status */
|
||||
val = s->raw & ~s->sense;
|
||||
break;
|
||||
/* Illegal */
|
||||
case 0x28: /* Interrupt Enable Clear */
|
||||
case 0x38: /* Software Interrupt Clear */
|
||||
case 0x58: /* Edge Triggered Interrupt Clear */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Read of write-only register with offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
if (high) {
|
||||
val = extract64(val, 32, 19);
|
||||
}
|
||||
trace_aspeed_vic_read(offset, size, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
const bool high = !!(offset & 0x4);
|
||||
hwaddr n_offset = (offset & ~0x4);
|
||||
AspeedVICState *s = (AspeedVICState *)opaque;
|
||||
|
||||
if (offset < AVIC_NEW_BASE_OFFSET) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: Ignoring write to legacy registers at 0x%"
|
||||
HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
|
||||
size, data);
|
||||
return;
|
||||
}
|
||||
|
||||
n_offset -= AVIC_NEW_BASE_OFFSET;
|
||||
trace_aspeed_vic_write(offset, size, data);
|
||||
|
||||
/* Given we have members using separate enable/clear registers, deposit64()
|
||||
* isn't quite the tool for the job. Instead, relocate the incoming bits to
|
||||
* the required bit offset based on the provided access address
|
||||
*/
|
||||
if (high) {
|
||||
data &= AVIC_H_MASK;
|
||||
data <<= 32;
|
||||
} else {
|
||||
data &= AVIC_L_MASK;
|
||||
}
|
||||
|
||||
switch (n_offset) {
|
||||
case 0x18: /* Interrupt Selection */
|
||||
/* Register has deposit64() semantics - overwrite requested 32 bits */
|
||||
if (high) {
|
||||
s->select &= AVIC_L_MASK;
|
||||
} else {
|
||||
s->select &= ((uint64_t) AVIC_H_MASK) << 32;
|
||||
}
|
||||
s->select |= data;
|
||||
break;
|
||||
case 0x20: /* Interrupt Enable */
|
||||
s->enable |= data;
|
||||
break;
|
||||
case 0x28: /* Interrupt Enable Clear */
|
||||
s->enable &= ~data;
|
||||
break;
|
||||
case 0x30: /* Software Interrupt */
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
|
||||
"IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
|
||||
break;
|
||||
case 0x38: /* Software Interrupt Clear */
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
|
||||
"IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
|
||||
break;
|
||||
case 0x50: /* Interrupt Event */
|
||||
/* Register has deposit64() semantics - overwrite the top four valid
|
||||
* IRQ bits, as only the top four IRQs (GPIOs) can change their event
|
||||
* type */
|
||||
if (high) {
|
||||
s->event &= ~AVIC_EVENT_W_MASK;
|
||||
s->event |= (data & AVIC_EVENT_W_MASK);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Ignoring invalid write to interrupt event register");
|
||||
}
|
||||
break;
|
||||
case 0x58: /* Edge Triggered Interrupt Clear */
|
||||
s->raw &= ~(data & ~s->sense);
|
||||
break;
|
||||
case 0x00: /* IRQ Status */
|
||||
case 0x08: /* FIQ Status */
|
||||
case 0x10: /* Raw Interrupt Status */
|
||||
case 0x40: /* Interrupt Sensitivity */
|
||||
case 0x48: /* Interrupt Both Edge Trigger Control */
|
||||
case 0x60: /* Edge Triggered Interrupt Status */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Write of read-only register with offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
aspeed_vic_update(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps aspeed_vic_ops = {
|
||||
.read = aspeed_vic_read,
|
||||
.write = aspeed_vic_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.valid.unaligned = false,
|
||||
};
|
||||
|
||||
static void aspeed_vic_reset(DeviceState *dev)
|
||||
{
|
||||
AspeedVICState *s = ASPEED_VIC(dev);
|
||||
|
||||
s->level = 0;
|
||||
s->raw = 0;
|
||||
s->select = 0;
|
||||
s->enable = 0;
|
||||
s->trigger = 0;
|
||||
s->sense = 0x1F07FFF8FFFFULL;
|
||||
s->dual_edge = 0xF800070000ULL;
|
||||
s->event = 0x5F07FFF8FFFFULL;
|
||||
}
|
||||
|
||||
#define AVIC_IO_REGION_SIZE 0x20000
|
||||
|
||||
static void aspeed_vic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedVICState *s = ASPEED_VIC(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s,
|
||||
TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
sysbus_init_irq(sbd, &s->fiq);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_aspeed_vic = {
|
||||
.name = "aspeed.new-vic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(level, AspeedVICState),
|
||||
VMSTATE_UINT64(raw, AspeedVICState),
|
||||
VMSTATE_UINT64(select, AspeedVICState),
|
||||
VMSTATE_UINT64(enable, AspeedVICState),
|
||||
VMSTATE_UINT64(trigger, AspeedVICState),
|
||||
VMSTATE_UINT64(sense, AspeedVICState),
|
||||
VMSTATE_UINT64(dual_edge, AspeedVICState),
|
||||
VMSTATE_UINT64(event, AspeedVICState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void aspeed_vic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->realize = aspeed_vic_realize;
|
||||
dc->reset = aspeed_vic_reset;
|
||||
dc->desc = "ASPEED Interrupt Controller (New)";
|
||||
dc->vmsd = &vmstate_aspeed_vic;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_vic_info = {
|
||||
.name = TYPE_ASPEED_VIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AspeedVICState),
|
||||
.class_init = aspeed_vic_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_vic_register_types(void)
|
||||
{
|
||||
type_register_static(&aspeed_vic_info);
|
||||
}
|
||||
|
||||
type_init(aspeed_vic_register_types);
|
||||
@@ -28,6 +28,7 @@ obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
|
||||
obj-$(CONFIG_IMX) += imx_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx31_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx25_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx6_ccm.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
|
||||
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user