qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

versatilepb.c (14675B)


      1 /*
      2  * ARM Versatile Platform/Application Baseboard System emulation.
      3  *
      4  * Copyright (c) 2005-2007 CodeSourcery.
      5  * Written by Paul Brook
      6  *
      7  * This code is licensed under the GPL.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "qapi/error.h"
     12 #include "cpu.h"
     13 #include "hw/sysbus.h"
     14 #include "migration/vmstate.h"
     15 #include "hw/arm/boot.h"
     16 #include "hw/net/smc91c111.h"
     17 #include "net/net.h"
     18 #include "sysemu/sysemu.h"
     19 #include "hw/pci/pci.h"
     20 #include "hw/i2c/i2c.h"
     21 #include "hw/i2c/arm_sbcon_i2c.h"
     22 #include "hw/irq.h"
     23 #include "hw/boards.h"
     24 #include "hw/block/flash.h"
     25 #include "qemu/error-report.h"
     26 #include "hw/char/pl011.h"
     27 #include "hw/sd/sd.h"
     28 #include "qom/object.h"
     29 
     30 #define VERSATILE_FLASH_ADDR 0x34000000
     31 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
     32 #define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
     33 
     34 /* Primary interrupt controller.  */
     35 
     36 #define TYPE_VERSATILE_PB_SIC "versatilepb_sic"
     37 OBJECT_DECLARE_SIMPLE_TYPE(vpb_sic_state, VERSATILE_PB_SIC)
     38 
     39 struct vpb_sic_state {
     40     SysBusDevice parent_obj;
     41 
     42     MemoryRegion iomem;
     43     uint32_t level;
     44     uint32_t mask;
     45     uint32_t pic_enable;
     46     qemu_irq parent[32];
     47     int irq;
     48 };
     49 
     50 static const VMStateDescription vmstate_vpb_sic = {
     51     .name = "versatilepb_sic",
     52     .version_id = 1,
     53     .minimum_version_id = 1,
     54     .fields = (VMStateField[]) {
     55         VMSTATE_UINT32(level, vpb_sic_state),
     56         VMSTATE_UINT32(mask, vpb_sic_state),
     57         VMSTATE_UINT32(pic_enable, vpb_sic_state),
     58         VMSTATE_END_OF_LIST()
     59     }
     60 };
     61 
     62 static void vpb_sic_update(vpb_sic_state *s)
     63 {
     64     uint32_t flags;
     65 
     66     flags = s->level & s->mask;
     67     qemu_set_irq(s->parent[s->irq], flags != 0);
     68 }
     69 
     70 static void vpb_sic_update_pic(vpb_sic_state *s)
     71 {
     72     int i;
     73     uint32_t mask;
     74 
     75     for (i = 21; i <= 30; i++) {
     76         mask = 1u << i;
     77         if (!(s->pic_enable & mask))
     78             continue;
     79         qemu_set_irq(s->parent[i], (s->level & mask) != 0);
     80     }
     81 }
     82 
     83 static void vpb_sic_set_irq(void *opaque, int irq, int level)
     84 {
     85     vpb_sic_state *s = (vpb_sic_state *)opaque;
     86     if (level)
     87         s->level |= 1u << irq;
     88     else
     89         s->level &= ~(1u << irq);
     90     if (s->pic_enable & (1u << irq))
     91         qemu_set_irq(s->parent[irq], level);
     92     vpb_sic_update(s);
     93 }
     94 
     95 static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
     96                              unsigned size)
     97 {
     98     vpb_sic_state *s = (vpb_sic_state *)opaque;
     99 
    100     switch (offset >> 2) {
    101     case 0: /* STATUS */
    102         return s->level & s->mask;
    103     case 1: /* RAWSTAT */
    104         return s->level;
    105     case 2: /* ENABLE */
    106         return s->mask;
    107     case 4: /* SOFTINT */
    108         return s->level & 1;
    109     case 8: /* PICENABLE */
    110         return s->pic_enable;
    111     default:
    112         printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
    113         return 0;
    114     }
    115 }
    116 
    117 static void vpb_sic_write(void *opaque, hwaddr offset,
    118                           uint64_t value, unsigned size)
    119 {
    120     vpb_sic_state *s = (vpb_sic_state *)opaque;
    121 
    122     switch (offset >> 2) {
    123     case 2: /* ENSET */
    124         s->mask |= value;
    125         break;
    126     case 3: /* ENCLR */
    127         s->mask &= ~value;
    128         break;
    129     case 4: /* SOFTINTSET */
    130         if (value)
    131             s->mask |= 1;
    132         break;
    133     case 5: /* SOFTINTCLR */
    134         if (value)
    135             s->mask &= ~1u;
    136         break;
    137     case 8: /* PICENSET */
    138         s->pic_enable |= (value & 0x7fe00000);
    139         vpb_sic_update_pic(s);
    140         break;
    141     case 9: /* PICENCLR */
    142         s->pic_enable &= ~value;
    143         vpb_sic_update_pic(s);
    144         break;
    145     default:
    146         printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
    147         return;
    148     }
    149     vpb_sic_update(s);
    150 }
    151 
    152 static const MemoryRegionOps vpb_sic_ops = {
    153     .read = vpb_sic_read,
    154     .write = vpb_sic_write,
    155     .endianness = DEVICE_NATIVE_ENDIAN,
    156 };
    157 
    158 static void vpb_sic_init(Object *obj)
    159 {
    160     DeviceState *dev = DEVICE(obj);
    161     vpb_sic_state *s = VERSATILE_PB_SIC(obj);
    162     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    163     int i;
    164 
    165     qdev_init_gpio_in(dev, vpb_sic_set_irq, 32);
    166     for (i = 0; i < 32; i++) {
    167         sysbus_init_irq(sbd, &s->parent[i]);
    168     }
    169     s->irq = 31;
    170     memory_region_init_io(&s->iomem, obj, &vpb_sic_ops, s,
    171                           "vpb-sic", 0x1000);
    172     sysbus_init_mmio(sbd, &s->iomem);
    173 }
    174 
    175 /* Board init.  */
    176 
    177 /* The AB and PB boards both use the same core, just with different
    178    peripherals and expansion busses.  For now we emulate a subset of the
    179    PB peripherals and just change the board ID.  */
    180 
    181 static struct arm_boot_info versatile_binfo;
    182 
    183 static void versatile_init(MachineState *machine, int board_id)
    184 {
    185     Object *cpuobj;
    186     ARMCPU *cpu;
    187     MemoryRegion *sysmem = get_system_memory();
    188     qemu_irq pic[32];
    189     qemu_irq sic[32];
    190     DeviceState *dev, *sysctl;
    191     SysBusDevice *busdev;
    192     DeviceState *pl041;
    193     PCIBus *pci_bus;
    194     NICInfo *nd;
    195     I2CBus *i2c;
    196     int n;
    197     int done_smc = 0;
    198     DriveInfo *dinfo;
    199 
    200     if (machine->ram_size > 0x10000000) {
    201         /* Device starting at address 0x10000000,
    202          * and memory cannot overlap with devices.
    203          * Refuse to run rather than behaving very confusingly.
    204          */
    205         error_report("versatilepb: memory size must not exceed 256MB");
    206         exit(1);
    207     }
    208 
    209     cpuobj = object_new(machine->cpu_type);
    210 
    211     /* By default ARM1176 CPUs have EL3 enabled.  This board does not
    212      * currently support EL3 so the CPU EL3 property is disabled before
    213      * realization.
    214      */
    215     if (object_property_find(cpuobj, "has_el3")) {
    216         object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
    217     }
    218 
    219     qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
    220 
    221     cpu = ARM_CPU(cpuobj);
    222 
    223     /* ??? RAM should repeat to fill physical memory space.  */
    224     /* SDRAM at address zero.  */
    225     memory_region_add_subregion(sysmem, 0, machine->ram);
    226 
    227     sysctl = qdev_new("realview_sysctl");
    228     qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
    229     qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
    230     sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal);
    231     sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
    232 
    233     dev = sysbus_create_varargs("pl190", 0x10140000,
    234                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
    235                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
    236                                 NULL);
    237     for (n = 0; n < 32; n++) {
    238         pic[n] = qdev_get_gpio_in(dev, n);
    239     }
    240     dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL);
    241     for (n = 0; n < 32; n++) {
    242         sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
    243         sic[n] = qdev_get_gpio_in(dev, n);
    244     }
    245 
    246     sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
    247     sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
    248 
    249     dev = qdev_new("versatile_pci");
    250     busdev = SYS_BUS_DEVICE(dev);
    251     sysbus_realize_and_unref(busdev, &error_fatal);
    252     sysbus_mmio_map(busdev, 0, 0x10001000); /* PCI controller regs */
    253     sysbus_mmio_map(busdev, 1, 0x41000000); /* PCI self-config */
    254     sysbus_mmio_map(busdev, 2, 0x42000000); /* PCI config */
    255     sysbus_mmio_map(busdev, 3, 0x43000000); /* PCI I/O */
    256     sysbus_mmio_map(busdev, 4, 0x44000000); /* PCI memory window 1 */
    257     sysbus_mmio_map(busdev, 5, 0x50000000); /* PCI memory window 2 */
    258     sysbus_mmio_map(busdev, 6, 0x60000000); /* PCI memory window 3 */
    259     sysbus_connect_irq(busdev, 0, sic[27]);
    260     sysbus_connect_irq(busdev, 1, sic[28]);
    261     sysbus_connect_irq(busdev, 2, sic[29]);
    262     sysbus_connect_irq(busdev, 3, sic[30]);
    263     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
    264 
    265     for(n = 0; n < nb_nics; n++) {
    266         nd = &nd_table[n];
    267 
    268         if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
    269             smc91c111_init(nd, 0x10010000, sic[25]);
    270             done_smc = 1;
    271         } else {
    272             pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
    273         }
    274     }
    275     if (machine_usb(machine)) {
    276         pci_create_simple(pci_bus, -1, "pci-ohci");
    277     }
    278     n = drive_get_max_bus(IF_SCSI);
    279     while (n >= 0) {
    280         dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a"));
    281         lsi53c8xx_handle_legacy_cmdline(dev);
    282         n--;
    283     }
    284 
    285     pl011_create(0x101f1000, pic[12], serial_hd(0));
    286     pl011_create(0x101f2000, pic[13], serial_hd(1));
    287     pl011_create(0x101f3000, pic[14], serial_hd(2));
    288     pl011_create(0x10009000, sic[6], serial_hd(3));
    289 
    290     dev = qdev_new("pl080");
    291     object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem),
    292                              &error_fatal);
    293     busdev = SYS_BUS_DEVICE(dev);
    294     sysbus_realize_and_unref(busdev, &error_fatal);
    295     sysbus_mmio_map(busdev, 0, 0x10130000);
    296     sysbus_connect_irq(busdev, 0, pic[17]);
    297 
    298     sysbus_create_simple("sp804", 0x101e2000, pic[4]);
    299     sysbus_create_simple("sp804", 0x101e3000, pic[5]);
    300 
    301     sysbus_create_simple("pl061", 0x101e4000, pic[6]);
    302     sysbus_create_simple("pl061", 0x101e5000, pic[7]);
    303     sysbus_create_simple("pl061", 0x101e6000, pic[8]);
    304     sysbus_create_simple("pl061", 0x101e7000, pic[9]);
    305 
    306     /* The versatile/PB actually has a modified Color LCD controller
    307        that includes hardware cursor support from the PL111.  */
    308     dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
    309     /* Wire up the mux control signals from the SYS_CLCD register */
    310     qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
    311 
    312     dev = sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
    313     dinfo = drive_get(IF_SD, 0, 0);
    314     if (dinfo) {
    315         DeviceState *card;
    316 
    317         card = qdev_new(TYPE_SD_CARD);
    318         qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
    319                                 &error_fatal);
    320         qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
    321                                &error_fatal);
    322     }
    323 
    324     dev = sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
    325     dinfo = drive_get(IF_SD, 0, 1);
    326     if (dinfo) {
    327         DeviceState *card;
    328 
    329         card = qdev_new(TYPE_SD_CARD);
    330         qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
    331                                 &error_fatal);
    332         qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
    333                                &error_fatal);
    334     }
    335 
    336     /* Add PL031 Real Time Clock. */
    337     sysbus_create_simple("pl031", 0x101e8000, pic[10]);
    338 
    339     dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL);
    340     i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
    341     i2c_slave_create_simple(i2c, "ds1338", 0x68);
    342 
    343     /* Add PL041 AACI Interface to the LM4549 codec */
    344     pl041 = qdev_new("pl041");
    345     qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
    346     sysbus_realize_and_unref(SYS_BUS_DEVICE(pl041), &error_fatal);
    347     sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
    348     sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
    349 
    350     /* Memory map for Versatile/PB:  */
    351     /* 0x10000000 System registers.  */
    352     /* 0x10001000 PCI controller config registers.  */
    353     /* 0x10002000 Serial bus interface.  */
    354     /*  0x10003000 Secondary interrupt controller.  */
    355     /* 0x10004000 AACI (audio).  */
    356     /*  0x10005000 MMCI0.  */
    357     /*  0x10006000 KMI0 (keyboard).  */
    358     /*  0x10007000 KMI1 (mouse).  */
    359     /* 0x10008000 Character LCD Interface.  */
    360     /*  0x10009000 UART3.  */
    361     /* 0x1000a000 Smart card 1.  */
    362     /*  0x1000b000 MMCI1.  */
    363     /*  0x10010000 Ethernet.  */
    364     /* 0x10020000 USB.  */
    365     /* 0x10100000 SSMC.  */
    366     /* 0x10110000 MPMC.  */
    367     /*  0x10120000 CLCD Controller.  */
    368     /*  0x10130000 DMA Controller.  */
    369     /*  0x10140000 Vectored interrupt controller.  */
    370     /* 0x101d0000 AHB Monitor Interface.  */
    371     /* 0x101e0000 System Controller.  */
    372     /* 0x101e1000 Watchdog Interface.  */
    373     /* 0x101e2000 Timer 0/1.  */
    374     /* 0x101e3000 Timer 2/3.  */
    375     /* 0x101e4000 GPIO port 0.  */
    376     /* 0x101e5000 GPIO port 1.  */
    377     /* 0x101e6000 GPIO port 2.  */
    378     /* 0x101e7000 GPIO port 3.  */
    379     /* 0x101e8000 RTC.  */
    380     /* 0x101f0000 Smart card 0.  */
    381     /*  0x101f1000 UART0.  */
    382     /*  0x101f2000 UART1.  */
    383     /*  0x101f3000 UART2.  */
    384     /* 0x101f4000 SSPI.  */
    385     /* 0x34000000 NOR Flash */
    386 
    387     dinfo = drive_get(IF_PFLASH, 0, 0);
    388     if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, "versatile.flash",
    389                           VERSATILE_FLASH_SIZE,
    390                           dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
    391                           VERSATILE_FLASH_SECT_SIZE,
    392                           4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
    393         fprintf(stderr, "qemu: Error registering flash memory.\n");
    394     }
    395 
    396     versatile_binfo.ram_size = machine->ram_size;
    397     versatile_binfo.board_id = board_id;
    398     arm_load_kernel(cpu, machine, &versatile_binfo);
    399 }
    400 
    401 static void vpb_init(MachineState *machine)
    402 {
    403     versatile_init(machine, 0x183);
    404 }
    405 
    406 static void vab_init(MachineState *machine)
    407 {
    408     versatile_init(machine, 0x25e);
    409 }
    410 
    411 static void versatilepb_class_init(ObjectClass *oc, void *data)
    412 {
    413     MachineClass *mc = MACHINE_CLASS(oc);
    414 
    415     mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
    416     mc->init = vpb_init;
    417     mc->block_default_type = IF_SCSI;
    418     mc->ignore_memory_transaction_failures = true;
    419     mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
    420     mc->default_ram_id = "versatile.ram";
    421 }
    422 
    423 static const TypeInfo versatilepb_type = {
    424     .name = MACHINE_TYPE_NAME("versatilepb"),
    425     .parent = TYPE_MACHINE,
    426     .class_init = versatilepb_class_init,
    427 };
    428 
    429 static void versatileab_class_init(ObjectClass *oc, void *data)
    430 {
    431     MachineClass *mc = MACHINE_CLASS(oc);
    432 
    433     mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
    434     mc->init = vab_init;
    435     mc->block_default_type = IF_SCSI;
    436     mc->ignore_memory_transaction_failures = true;
    437     mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
    438     mc->default_ram_id = "versatile.ram";
    439 }
    440 
    441 static const TypeInfo versatileab_type = {
    442     .name = MACHINE_TYPE_NAME("versatileab"),
    443     .parent = TYPE_MACHINE,
    444     .class_init = versatileab_class_init,
    445 };
    446 
    447 static void versatile_machine_init(void)
    448 {
    449     type_register_static(&versatilepb_type);
    450     type_register_static(&versatileab_type);
    451 }
    452 
    453 type_init(versatile_machine_init)
    454 
    455 static void vpb_sic_class_init(ObjectClass *klass, void *data)
    456 {
    457     DeviceClass *dc = DEVICE_CLASS(klass);
    458 
    459     dc->vmsd = &vmstate_vpb_sic;
    460 }
    461 
    462 static const TypeInfo vpb_sic_info = {
    463     .name          = TYPE_VERSATILE_PB_SIC,
    464     .parent        = TYPE_SYS_BUS_DEVICE,
    465     .instance_size = sizeof(vpb_sic_state),
    466     .instance_init = vpb_sic_init,
    467     .class_init    = vpb_sic_class_init,
    468 };
    469 
    470 static void versatilepb_register_types(void)
    471 {
    472     type_register_static(&vpb_sic_info);
    473 }
    474 
    475 type_init(versatilepb_register_types)