#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "qemu/log.h"
#include "cpu.h"
#include "hw/cpu/a9mpcore.h"
+#include "hw/irq.h"
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
-#include "hw/arm/arm.h"
+#include "hw/arm/boot.h"
#include "hw/loader.h"
+#include "hw/qdev-properties.h"
#include "hw/arm/exynos4210.h"
-#include "hw/sd/sd.h"
+#include "hw/sd/sdhci.h"
#include "hw/usb/hcd-ehci.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
/* EHCI */
#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000
+/* DMA */
+#define EXYNOS4210_PL330_BASE0_ADDR 0x12680000
+#define EXYNOS4210_PL330_BASE1_ADDR 0x12690000
+#define EXYNOS4210_PL330_BASE2_ADDR 0x12850000
+
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
0x09, 0x00, 0x00, 0x00 };
static uint64_t exynos4210_calc_affinity(int cpu)
{
- uint64_t mp_affinity;
-
/* Exynos4210 has 0x9 as cluster ID */
- mp_affinity = (0x9 << ARM_AFF1_SHIFT) | cpu;
+ return (0x9 << ARM_AFF1_SHIFT) | cpu;
+}
- return mp_affinity;
+static void pl330_create(uint32_t base, qemu_irq irq, int nreq)
+{
+ SysBusDevice *busdev;
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "pl330");
+ qdev_prop_set_uint8(dev, "num_periph_req", nreq);
+ qdev_init_nofail(dev);
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, base);
+ sysbus_connect_irq(busdev, 0, irq);
}
-Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
+static void exynos4210_realize(DeviceState *socdev, Error **errp)
{
- Exynos4210State *s = g_new(Exynos4210State, 1);
+ Exynos4210State *s = EXYNOS4210_SOC(socdev);
+ MemoryRegion *system_mem = get_system_memory();
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
SysBusDevice *busdev;
- ObjectClass *cpu_oc;
DeviceState *dev;
int i, n;
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
- assert(cpu_oc);
-
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- Object *cpuobj = object_new(object_class_get_name(cpu_oc));
+ Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
/* By default A9 CPUs have EL3 enabled. This board does not currently
* support EL3 so the CPU EL3 property is disabled before realization.
/*** UARTs ***/
exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
- EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
+ EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
- EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
+ EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
- EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
+ EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
- EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
+ EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
/*** SD/MMC host controllers ***/
BlockBackend *blk;
DriveInfo *di;
- dev = qdev_create(NULL, "generic-sdhci");
- qdev_prop_set_uint32(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
+ /* Compatible with:
+ * - SD Host Controller Specification Version 2.0
+ * - SDIO Specification Version 2.0
+ * - MMC Specification Version 4.3
+ * - SDMA
+ * - ADMA2
+ *
+ * As this part of the Exynos4210 is not publically available,
+ * we used the "HS-MMC Controller S3C2416X RISC Microprocessor"
+ * public datasheet which is very similar (implementing
+ * MMC Specification Version 4.0 being the only difference noted)
+ */
+ dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI);
+ qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
s->irq_table[exynos4210_get_irq(28, 3)]);
- return s;
+ /*** DMA controllers ***/
+ pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
+ qemu_irq_invert(s->irq_table[exynos4210_get_irq(35, 1)]), 32);
+ pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
+ qemu_irq_invert(s->irq_table[exynos4210_get_irq(36, 1)]), 32);
+ pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
+ qemu_irq_invert(s->irq_table[exynos4210_get_irq(34, 1)]), 1);
}
+
+static void exynos4210_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = exynos4210_realize;
+}
+
+static const TypeInfo exynos4210_info = {
+ .name = TYPE_EXYNOS4210_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Exynos4210State),
+ .class_init = exynos4210_class_init,
+};
+
+static void exynos4210_register_types(void)
+{
+ type_register_static(&exynos4210_info);
+}
+
+type_init(exynos4210_register_types)