hw/arm: add experimental iPhone 5 A6 platform
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/arm/s5l8950x.h"
|
||||
#include "hw/arm/machines-qom.h"
|
||||
#include "hw/core/boards.h"
|
||||
#include "hw/core/loader.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/core/sysbus.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "target/arm/cpu.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "system/system.h"
|
||||
#include "target/arm/cpregs.h"
|
||||
|
||||
/*
|
||||
* Swift has implementation-defined CP15 controls which the SecureROM uses
|
||||
* while bringing caches and the memory system up. QEMU does not model
|
||||
* those microarchitectural details, so the matching control is write-ignore.
|
||||
*/
|
||||
static const ARMCPRegInfo s5l8950x_cp_reginfo[] = {
|
||||
{
|
||||
.name = "APPLE_SWIFT_CFG",
|
||||
.cp = 15,
|
||||
.opc1 = 1,
|
||||
.crn = 15,
|
||||
.crm = 2,
|
||||
.opc2 = 0,
|
||||
.access = PL1_W,
|
||||
.type = ARM_CP_NOP,
|
||||
},
|
||||
};
|
||||
|
||||
/* Addresses */
|
||||
#define S5L8950X_SECUREROM_BASE 0x00000000
|
||||
#define S5L8950X_SECUREROM_SIZE 0x10000
|
||||
#define S5L8950X_SRAM_BASE 0x10000000
|
||||
#define S5L8950X_SRAM_SIZE 0x80000
|
||||
#define S5L8950X_SDIO_BASE 0x20000000
|
||||
#define S5L8950X_USB_PHY_BASE 0x36000000
|
||||
#define S5L8950X_USB_BASE 0x36100000
|
||||
#define S5L8950X_SHA1_BASE 0x3C500000
|
||||
#define S5L8950X_SPI_BASE 0x3D200000
|
||||
#define S5L8950X_AES_BASE 0x3E000000
|
||||
#define S5L8950X_IIC_BASE 0x3E100000
|
||||
#define S5L8950X_PKE_BASE 0x3E200000
|
||||
#define S5L8950X_WDT_BASE 0x3E300000
|
||||
#define S5L8950X_CHIPID_BASE 0x3F500000
|
||||
#define S5L8950X_TIMER_BASE 0x3F200000
|
||||
#define S5L8950X_PMGR_BASE 0x3F100000
|
||||
#define S5L8950X_AMC_BASE 0x40000000
|
||||
#define S5L8950X_AIC_BASE 0x3F200000
|
||||
#define S5L8950X_UART_BASE 0x44300000
|
||||
#define S5L8950X_GPIO_BASE 0x3FA00000
|
||||
#define S5L8950X_DRAM_BASE 0x80000000
|
||||
|
||||
static void s5l8950x_init(Object *obj)
|
||||
{
|
||||
S5L8950XState *s = S5L8950X(obj);
|
||||
|
||||
object_initialize_child(obj, "cpu", &s->cpu, ARM_CPU_TYPE_NAME("cortex-a9"));
|
||||
define_arm_cp_regs(&s->cpu, s5l8950x_cp_reginfo);
|
||||
}
|
||||
|
||||
static void s5l8950x_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
S5L8950XState *s = S5L8950X(dev);
|
||||
Error *err = NULL;
|
||||
|
||||
/* Realize CPU */
|
||||
if (!qdev_realize(DEVICE(&s->cpu), NULL, &err)) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
memory_region_init_ram(&s->sram, OBJECT(s), "s5l8950x.sram", S5L8950X_SRAM_SIZE, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), S5L8950X_SRAM_BASE, &s->sram);
|
||||
|
||||
/* SecureROM */
|
||||
memory_region_init_rom(&s->securerom, OBJECT(s), "s5l8950x.securerom", S5L8950X_SECUREROM_SIZE, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), S5L8950X_SECUREROM_BASE, &s->securerom);
|
||||
|
||||
/* Create unimplemented devices */
|
||||
create_unimplemented_device("s5l8950x.sdio", S5L8950X_SDIO_BASE, 0x10000);
|
||||
create_unimplemented_device("s5l8950x.sha1", S5L8950X_SHA1_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.spi", S5L8950X_SPI_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.aes", S5L8950X_AES_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.iic", S5L8950X_IIC_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.pke", S5L8950X_PKE_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.wdt", S5L8950X_WDT_BASE, 0x1000);
|
||||
create_unimplemented_device("s5l8950x.amc", S5L8950X_AMC_BASE, 0x1000);
|
||||
|
||||
/* Realize custom devices (assumes stubs will be created) */
|
||||
DeviceState *dev_chipid = qdev_new(TYPE_S5L8950X_CHIPID);
|
||||
s->chipid = SYS_BUS_DEVICE(dev_chipid);
|
||||
sysbus_realize_and_unref(s->chipid, &error_fatal);
|
||||
sysbus_mmio_map(s->chipid, 0, S5L8950X_CHIPID_BASE);
|
||||
|
||||
DeviceState *dev_aic = qdev_new(TYPE_S5L8950X_AIC);
|
||||
s->aic = SYS_BUS_DEVICE(dev_aic);
|
||||
sysbus_realize_and_unref(s->aic, &error_fatal);
|
||||
sysbus_mmio_map(s->aic, 0, S5L8950X_AIC_BASE);
|
||||
sysbus_connect_irq(s->aic, 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(s->aic, 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
|
||||
|
||||
DeviceState *dev_uart = qdev_new(TYPE_S5L8950X_UART);
|
||||
qdev_prop_set_chr(dev_uart, "chardev", serial_hd(0));
|
||||
s->uart = SYS_BUS_DEVICE(dev_uart);
|
||||
sysbus_realize_and_unref(s->uart, &error_fatal);
|
||||
sysbus_mmio_map(s->uart, 0, S5L8950X_UART_BASE);
|
||||
|
||||
DeviceState *dev_pmgr = qdev_new(TYPE_S5L8950X_PMGR);
|
||||
s->pmgr = SYS_BUS_DEVICE(dev_pmgr);
|
||||
sysbus_realize_and_unref(s->pmgr, &error_fatal);
|
||||
sysbus_mmio_map(s->pmgr, 0, S5L8950X_PMGR_BASE);
|
||||
|
||||
DeviceState *dev_gpio = qdev_new(TYPE_S5L8950X_GPIO);
|
||||
qdev_prop_set_bit(dev_gpio, "force-dfu", true);
|
||||
s->gpio = SYS_BUS_DEVICE(dev_gpio);
|
||||
sysbus_realize_and_unref(s->gpio, &error_fatal);
|
||||
sysbus_mmio_map(s->gpio, 0, S5L8950X_GPIO_BASE);
|
||||
|
||||
DeviceState *dev_usb_phy = qdev_new(TYPE_S5L8950X_USB_PHY);
|
||||
qdev_prop_set_bit(dev_usb_phy, "cable-connected", true);
|
||||
s->usb_phy = SYS_BUS_DEVICE(dev_usb_phy);
|
||||
sysbus_realize_and_unref(s->usb_phy, &error_fatal);
|
||||
sysbus_mmio_map(s->usb_phy, 0, S5L8950X_USB_PHY_BASE);
|
||||
|
||||
DeviceState *dev_usb_otg = qdev_new(TYPE_S5L8950X_USB_OTG);
|
||||
s->usb_otg = SYS_BUS_DEVICE(dev_usb_otg);
|
||||
sysbus_realize_and_unref(s->usb_otg, &error_fatal);
|
||||
sysbus_mmio_map(s->usb_otg, 0, S5L8950X_USB_BASE);
|
||||
sysbus_connect_irq(s->usb_otg, 0,
|
||||
qdev_get_gpio_in(dev_aic, 11));
|
||||
}
|
||||
|
||||
static void s5l8950x_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
dc->realize = s5l8950x_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo s5l8950x_type_info = {
|
||||
.name = TYPE_S5L8950X,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(S5L8950XState),
|
||||
.instance_init = s5l8950x_init,
|
||||
.class_init = s5l8950x_class_init,
|
||||
};
|
||||
|
||||
static void iphone5_machine_init(MachineState *machine)
|
||||
{
|
||||
S5L8950XState *s;
|
||||
|
||||
s = S5L8950X(object_new(TYPE_S5L8950X));
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
|
||||
qdev_realize(DEVICE(s), NULL, &error_fatal);
|
||||
|
||||
/* Map DRAM */
|
||||
memory_region_add_subregion(get_system_memory(), S5L8950X_DRAM_BASE, machine->ram);
|
||||
|
||||
/* Load BIOS (SecureROM) */
|
||||
if (machine->firmware) {
|
||||
load_image_targphys(machine->firmware, S5L8950X_SECUREROM_BASE,
|
||||
S5L8950X_SECUREROM_SIZE, &error_fatal);
|
||||
}
|
||||
}
|
||||
|
||||
static void iphone5_machine_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Apple iPhone 5 (S5L8950X / A6)";
|
||||
mc->init = iphone5_machine_init;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
mc->default_ram_id = "dram";
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
}
|
||||
|
||||
static const TypeInfo iphone5_machine_type_info = {
|
||||
.name = MACHINE_TYPE_NAME("iphone5"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = iphone5_machine_class_init,
|
||||
.interfaces = arm_machine_interfaces,
|
||||
};
|
||||
|
||||
static void s5l8950x_register_types(void)
|
||||
{
|
||||
type_register_static(&s5l8950x_type_info);
|
||||
type_register_static(&iphone5_machine_type_info);
|
||||
}
|
||||
|
||||
type_init(s5l8950x_register_types)
|
||||
Reference in New Issue
Block a user