Files
QEMU-S5L8950X/hw/arm/s5l8950x.c
T

198 lines
6.9 KiB
C

#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)