1b5ff1b31Sbellard /* 2b5ff1b31Sbellard * ARM Integrator CP System emulation. 3b5ff1b31Sbellard * 4a1bb27b1Spbrook * Copyright (c) 2005-2007 CodeSourcery. 5b5ff1b31Sbellard * Written by Paul Brook 6b5ff1b31Sbellard * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL 8b5ff1b31Sbellard */ 9b5ff1b31Sbellard 1012b16722SPeter Maydell #include "qemu/osdep.h" 11da34e65cSMarkus Armbruster #include "qapi/error.h" 124771d756SPaolo Bonzini #include "qemu-common.h" 134771d756SPaolo Bonzini #include "cpu.h" 1483c9f4caSPaolo Bonzini #include "hw/sysbus.h" 15bd2be150SPeter Maydell #include "hw/devices.h" 1683c9f4caSPaolo Bonzini #include "hw/boards.h" 17bd2be150SPeter Maydell #include "hw/arm/arm.h" 18b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h" 191422e32dSPaolo Bonzini #include "net/net.h" 20022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 219c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 22223a72f1SGreg Bellows #include "qemu/error-report.h" 23f0d1d2c1Sxiaoqiang zhao #include "hw/char/pl011.h" 24b5ff1b31Sbellard 25257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core" 26257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \ 27257ec289SAndreas Färber OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM) 28257ec289SAndreas Färber 29257ec289SAndreas Färber typedef struct IntegratorCMState { 30257ec289SAndreas Färber /*< private >*/ 31257ec289SAndreas Färber SysBusDevice parent_obj; 32257ec289SAndreas Färber /*< public >*/ 33257ec289SAndreas Färber 3471d9bc50SBenoît Canet MemoryRegion iomem; 35ee6847d1SGerd Hoffmann uint32_t memsz; 36211adf4dSAvi Kivity MemoryRegion flash; 37b5ff1b31Sbellard uint32_t cm_osc; 38b5ff1b31Sbellard uint32_t cm_ctrl; 39b5ff1b31Sbellard uint32_t cm_lock; 40b5ff1b31Sbellard uint32_t cm_auxosc; 41b5ff1b31Sbellard uint32_t cm_sdram; 42b5ff1b31Sbellard uint32_t cm_init; 43b5ff1b31Sbellard uint32_t cm_flags; 44b5ff1b31Sbellard uint32_t cm_nvflags; 45f53977f7SJan Petrous uint32_t cm_refcnt_offset; 46b5ff1b31Sbellard uint32_t int_level; 47b5ff1b31Sbellard uint32_t irq_enabled; 48b5ff1b31Sbellard uint32_t fiq_enabled; 49257ec289SAndreas Färber } IntegratorCMState; 50b5ff1b31Sbellard 51b5ff1b31Sbellard static uint8_t integrator_spd[128] = { 52b5ff1b31Sbellard 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, 53b5ff1b31Sbellard 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 54b5ff1b31Sbellard }; 55b5ff1b31Sbellard 56a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset, 5771d9bc50SBenoît Canet unsigned size) 58b5ff1b31Sbellard { 59257ec289SAndreas Färber IntegratorCMState *s = opaque; 60b5ff1b31Sbellard if (offset >= 0x100 && offset < 0x200) { 61b5ff1b31Sbellard /* CM_SPD */ 62b5ff1b31Sbellard if (offset >= 0x180) 63b5ff1b31Sbellard return 0; 64b5ff1b31Sbellard return integrator_spd[offset >> 2]; 65b5ff1b31Sbellard } 66b5ff1b31Sbellard switch (offset >> 2) { 67b5ff1b31Sbellard case 0: /* CM_ID */ 68b5ff1b31Sbellard return 0x411a3001; 69b5ff1b31Sbellard case 1: /* CM_PROC */ 70b5ff1b31Sbellard return 0; 71b5ff1b31Sbellard case 2: /* CM_OSC */ 72b5ff1b31Sbellard return s->cm_osc; 73b5ff1b31Sbellard case 3: /* CM_CTRL */ 74b5ff1b31Sbellard return s->cm_ctrl; 75b5ff1b31Sbellard case 4: /* CM_STAT */ 76b5ff1b31Sbellard return 0x00100000; 77b5ff1b31Sbellard case 5: /* CM_LOCK */ 78b5ff1b31Sbellard if (s->cm_lock == 0xa05f) { 79b5ff1b31Sbellard return 0x1a05f; 80b5ff1b31Sbellard } else { 81b5ff1b31Sbellard return s->cm_lock; 82b5ff1b31Sbellard } 83b5ff1b31Sbellard case 6: /* CM_LMBUSCNT */ 84b5ff1b31Sbellard /* ??? High frequency timer. */ 852ac71179SPaul Brook hw_error("integratorcm_read: CM_LMBUSCNT"); 86b5ff1b31Sbellard case 7: /* CM_AUXOSC */ 87b5ff1b31Sbellard return s->cm_auxosc; 88b5ff1b31Sbellard case 8: /* CM_SDRAM */ 89b5ff1b31Sbellard return s->cm_sdram; 90b5ff1b31Sbellard case 9: /* CM_INIT */ 91b5ff1b31Sbellard return s->cm_init; 92f53977f7SJan Petrous case 10: /* CM_REFCNT */ 93f53977f7SJan Petrous /* This register, CM_REFCNT, provides a 32-bit count value. 94f53977f7SJan Petrous * The count increments at the fixed reference clock frequency of 24MHz 95f53977f7SJan Petrous * and can be used as a real-time counter. 96f53977f7SJan Petrous */ 97f53977f7SJan Petrous return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 98f53977f7SJan Petrous 1000) - s->cm_refcnt_offset; 99b5ff1b31Sbellard case 12: /* CM_FLAGS */ 100b5ff1b31Sbellard return s->cm_flags; 101b5ff1b31Sbellard case 14: /* CM_NVFLAGS */ 102b5ff1b31Sbellard return s->cm_nvflags; 103b5ff1b31Sbellard case 16: /* CM_IRQ_STAT */ 104b5ff1b31Sbellard return s->int_level & s->irq_enabled; 105b5ff1b31Sbellard case 17: /* CM_IRQ_RSTAT */ 106b5ff1b31Sbellard return s->int_level; 107b5ff1b31Sbellard case 18: /* CM_IRQ_ENSET */ 108b5ff1b31Sbellard return s->irq_enabled; 109b5ff1b31Sbellard case 20: /* CM_SOFT_INTSET */ 110b5ff1b31Sbellard return s->int_level & 1; 111b5ff1b31Sbellard case 24: /* CM_FIQ_STAT */ 112b5ff1b31Sbellard return s->int_level & s->fiq_enabled; 113b5ff1b31Sbellard case 25: /* CM_FIQ_RSTAT */ 114b5ff1b31Sbellard return s->int_level; 115b5ff1b31Sbellard case 26: /* CM_FIQ_ENSET */ 116b5ff1b31Sbellard return s->fiq_enabled; 117b5ff1b31Sbellard case 32: /* CM_VOLTAGE_CTL0 */ 118b5ff1b31Sbellard case 33: /* CM_VOLTAGE_CTL1 */ 119b5ff1b31Sbellard case 34: /* CM_VOLTAGE_CTL2 */ 120b5ff1b31Sbellard case 35: /* CM_VOLTAGE_CTL3 */ 121b5ff1b31Sbellard /* ??? Voltage control unimplemented. */ 122b5ff1b31Sbellard return 0; 123b5ff1b31Sbellard default: 1242ac71179SPaul Brook hw_error("integratorcm_read: Unimplemented offset 0x%x\n", 1252ac71179SPaul Brook (int)offset); 126b5ff1b31Sbellard return 0; 127b5ff1b31Sbellard } 128b5ff1b31Sbellard } 129b5ff1b31Sbellard 130257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s) 131b5ff1b31Sbellard { 132563c2bf3SPeter Maydell /* Sync memory region state with CM_CTRL REMAP bit: 133563c2bf3SPeter Maydell * bit 0 => flash at address 0; bit 1 => RAM 134563c2bf3SPeter Maydell */ 135563c2bf3SPeter Maydell memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); 136b5ff1b31Sbellard } 137b5ff1b31Sbellard 138257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value) 139b5ff1b31Sbellard { 140b5ff1b31Sbellard if (value & 8) { 141df3f457bSPeter Maydell qemu_system_reset_request(); 142b5ff1b31Sbellard } 143df3f457bSPeter Maydell if ((s->cm_ctrl ^ value) & 1) { 144df3f457bSPeter Maydell /* (value & 1) != 0 means the green "MISC LED" is lit. 145df3f457bSPeter Maydell * We don't have any nice place to display LEDs. printf is a bad 146df3f457bSPeter Maydell * idea because Linux uses the LED as a heartbeat and the output 147df3f457bSPeter Maydell * will swamp anything else on the terminal. 148df3f457bSPeter Maydell */ 149b5ff1b31Sbellard } 150df3f457bSPeter Maydell /* Note that the RESET bit [3] always reads as zero */ 151df3f457bSPeter Maydell s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); 152563c2bf3SPeter Maydell integratorcm_do_remap(s); 153b5ff1b31Sbellard } 154b5ff1b31Sbellard 155257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s) 156b5ff1b31Sbellard { 157b5ff1b31Sbellard /* ??? The CPU irq/fiq is raised when either the core module or base PIC 158b5ff1b31Sbellard are active. */ 159b5ff1b31Sbellard if (s->int_level & (s->irq_enabled | s->fiq_enabled)) 1602ac71179SPaul Brook hw_error("Core module interrupt\n"); 161b5ff1b31Sbellard } 162b5ff1b31Sbellard 163a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset, 16471d9bc50SBenoît Canet uint64_t value, unsigned size) 165b5ff1b31Sbellard { 166257ec289SAndreas Färber IntegratorCMState *s = opaque; 167b5ff1b31Sbellard switch (offset >> 2) { 168b5ff1b31Sbellard case 2: /* CM_OSC */ 169b5ff1b31Sbellard if (s->cm_lock == 0xa05f) 170b5ff1b31Sbellard s->cm_osc = value; 171b5ff1b31Sbellard break; 172b5ff1b31Sbellard case 3: /* CM_CTRL */ 173b5ff1b31Sbellard integratorcm_set_ctrl(s, value); 174b5ff1b31Sbellard break; 175b5ff1b31Sbellard case 5: /* CM_LOCK */ 176b5ff1b31Sbellard s->cm_lock = value & 0xffff; 177b5ff1b31Sbellard break; 178b5ff1b31Sbellard case 7: /* CM_AUXOSC */ 179b5ff1b31Sbellard if (s->cm_lock == 0xa05f) 180b5ff1b31Sbellard s->cm_auxosc = value; 181b5ff1b31Sbellard break; 182b5ff1b31Sbellard case 8: /* CM_SDRAM */ 183b5ff1b31Sbellard s->cm_sdram = value; 184b5ff1b31Sbellard break; 185b5ff1b31Sbellard case 9: /* CM_INIT */ 186b5ff1b31Sbellard /* ??? This can change the memory bus frequency. */ 187b5ff1b31Sbellard s->cm_init = value; 188b5ff1b31Sbellard break; 189b5ff1b31Sbellard case 12: /* CM_FLAGSS */ 190b5ff1b31Sbellard s->cm_flags |= value; 191b5ff1b31Sbellard break; 192b5ff1b31Sbellard case 13: /* CM_FLAGSC */ 193b5ff1b31Sbellard s->cm_flags &= ~value; 194b5ff1b31Sbellard break; 195b5ff1b31Sbellard case 14: /* CM_NVFLAGSS */ 196b5ff1b31Sbellard s->cm_nvflags |= value; 197b5ff1b31Sbellard break; 198b5ff1b31Sbellard case 15: /* CM_NVFLAGSS */ 199b5ff1b31Sbellard s->cm_nvflags &= ~value; 200b5ff1b31Sbellard break; 201b5ff1b31Sbellard case 18: /* CM_IRQ_ENSET */ 202b5ff1b31Sbellard s->irq_enabled |= value; 203b5ff1b31Sbellard integratorcm_update(s); 204b5ff1b31Sbellard break; 205b5ff1b31Sbellard case 19: /* CM_IRQ_ENCLR */ 206b5ff1b31Sbellard s->irq_enabled &= ~value; 207b5ff1b31Sbellard integratorcm_update(s); 208b5ff1b31Sbellard break; 209b5ff1b31Sbellard case 20: /* CM_SOFT_INTSET */ 210b5ff1b31Sbellard s->int_level |= (value & 1); 211b5ff1b31Sbellard integratorcm_update(s); 212b5ff1b31Sbellard break; 213b5ff1b31Sbellard case 21: /* CM_SOFT_INTCLR */ 214b5ff1b31Sbellard s->int_level &= ~(value & 1); 215b5ff1b31Sbellard integratorcm_update(s); 216b5ff1b31Sbellard break; 217b5ff1b31Sbellard case 26: /* CM_FIQ_ENSET */ 218b5ff1b31Sbellard s->fiq_enabled |= value; 219b5ff1b31Sbellard integratorcm_update(s); 220b5ff1b31Sbellard break; 221b5ff1b31Sbellard case 27: /* CM_FIQ_ENCLR */ 222b5ff1b31Sbellard s->fiq_enabled &= ~value; 223b5ff1b31Sbellard integratorcm_update(s); 224b5ff1b31Sbellard break; 225b5ff1b31Sbellard case 32: /* CM_VOLTAGE_CTL0 */ 226b5ff1b31Sbellard case 33: /* CM_VOLTAGE_CTL1 */ 227b5ff1b31Sbellard case 34: /* CM_VOLTAGE_CTL2 */ 228b5ff1b31Sbellard case 35: /* CM_VOLTAGE_CTL3 */ 229b5ff1b31Sbellard /* ??? Voltage control unimplemented. */ 230b5ff1b31Sbellard break; 231b5ff1b31Sbellard default: 2322ac71179SPaul Brook hw_error("integratorcm_write: Unimplemented offset 0x%x\n", 2332ac71179SPaul Brook (int)offset); 234b5ff1b31Sbellard break; 235b5ff1b31Sbellard } 236b5ff1b31Sbellard } 237b5ff1b31Sbellard 238b5ff1b31Sbellard /* Integrator/CM control registers. */ 239b5ff1b31Sbellard 24071d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = { 24171d9bc50SBenoît Canet .read = integratorcm_read, 24271d9bc50SBenoît Canet .write = integratorcm_write, 24371d9bc50SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 244b5ff1b31Sbellard }; 245b5ff1b31Sbellard 246a1f42e0cSxiaoqiang.zhao static void integratorcm_init(Object *obj) 247b5ff1b31Sbellard { 248a1f42e0cSxiaoqiang.zhao IntegratorCMState *s = INTEGRATOR_CM(obj); 249a1f42e0cSxiaoqiang.zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj); 250b5ff1b31Sbellard 251b5ff1b31Sbellard s->cm_osc = 0x01000048; 252b5ff1b31Sbellard /* ??? What should the high bits of this value be? */ 253b5ff1b31Sbellard s->cm_auxosc = 0x0007feff; 254b5ff1b31Sbellard s->cm_sdram = 0x00011122; 255*e9d9ee23SJakub Jermar memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); 256*e9d9ee23SJakub Jermar s->cm_init = 0x00000112; 257*e9d9ee23SJakub Jermar s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 258*e9d9ee23SJakub Jermar 1000); 259*e9d9ee23SJakub Jermar memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000, 260*e9d9ee23SJakub Jermar &error_fatal); 261*e9d9ee23SJakub Jermar vmstate_register_ram_global(&s->flash); 262*e9d9ee23SJakub Jermar 263*e9d9ee23SJakub Jermar memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s, 264*e9d9ee23SJakub Jermar "integratorcm", 0x00800000); 265*e9d9ee23SJakub Jermar sysbus_init_mmio(dev, &s->iomem); 266*e9d9ee23SJakub Jermar 267*e9d9ee23SJakub Jermar integratorcm_do_remap(s); 268*e9d9ee23SJakub Jermar /* ??? Save/restore. */ 269*e9d9ee23SJakub Jermar } 270*e9d9ee23SJakub Jermar 271*e9d9ee23SJakub Jermar static void integratorcm_realize(DeviceState *d, Error **errp) 272*e9d9ee23SJakub Jermar { 273*e9d9ee23SJakub Jermar IntegratorCMState *s = INTEGRATOR_CM(d); 274*e9d9ee23SJakub Jermar 275ee6847d1SGerd Hoffmann if (s->memsz >= 256) { 276b5ff1b31Sbellard integrator_spd[31] = 64; 277b5ff1b31Sbellard s->cm_sdram |= 0x10; 278ee6847d1SGerd Hoffmann } else if (s->memsz >= 128) { 279b5ff1b31Sbellard integrator_spd[31] = 32; 280b5ff1b31Sbellard s->cm_sdram |= 0x0c; 281ee6847d1SGerd Hoffmann } else if (s->memsz >= 64) { 282b5ff1b31Sbellard integrator_spd[31] = 16; 283b5ff1b31Sbellard s->cm_sdram |= 0x08; 284ee6847d1SGerd Hoffmann } else if (s->memsz >= 32) { 285b5ff1b31Sbellard integrator_spd[31] = 4; 286b5ff1b31Sbellard s->cm_sdram |= 0x04; 287b5ff1b31Sbellard } else { 288b5ff1b31Sbellard integrator_spd[31] = 2; 289b5ff1b31Sbellard } 290b5ff1b31Sbellard } 291b5ff1b31Sbellard 292b5ff1b31Sbellard /* Integrator/CP hardware emulation. */ 293b5ff1b31Sbellard /* Primary interrupt controller. */ 294b5ff1b31Sbellard 29591b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic" 29691b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \ 29791b64626SAndreas Färber OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC) 29891b64626SAndreas Färber 29991b64626SAndreas Färber typedef struct icp_pic_state { 30091b64626SAndreas Färber /*< private >*/ 30191b64626SAndreas Färber SysBusDevice parent_obj; 30291b64626SAndreas Färber /*< public >*/ 30391b64626SAndreas Färber 30461074e46SBenoît Canet MemoryRegion iomem; 305b5ff1b31Sbellard uint32_t level; 306b5ff1b31Sbellard uint32_t irq_enabled; 307b5ff1b31Sbellard uint32_t fiq_enabled; 308d537cf6cSpbrook qemu_irq parent_irq; 309d537cf6cSpbrook qemu_irq parent_fiq; 310b5ff1b31Sbellard } icp_pic_state; 311b5ff1b31Sbellard 312b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s) 313b5ff1b31Sbellard { 314b5ff1b31Sbellard uint32_t flags; 315b5ff1b31Sbellard 316b5ff1b31Sbellard flags = (s->level & s->irq_enabled); 317d537cf6cSpbrook qemu_set_irq(s->parent_irq, flags != 0); 318cdbdb648Spbrook flags = (s->level & s->fiq_enabled); 319d537cf6cSpbrook qemu_set_irq(s->parent_fiq, flags != 0); 320b5ff1b31Sbellard } 321b5ff1b31Sbellard 322cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level) 323b5ff1b31Sbellard { 32480337b66Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 325b5ff1b31Sbellard if (level) 32680337b66Sbellard s->level |= 1 << irq; 327b5ff1b31Sbellard else 32880337b66Sbellard s->level &= ~(1 << irq); 329b5ff1b31Sbellard icp_pic_update(s); 330b5ff1b31Sbellard } 331b5ff1b31Sbellard 332a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset, 33361074e46SBenoît Canet unsigned size) 334b5ff1b31Sbellard { 335b5ff1b31Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 336b5ff1b31Sbellard 337b5ff1b31Sbellard switch (offset >> 2) { 338b5ff1b31Sbellard case 0: /* IRQ_STATUS */ 339b5ff1b31Sbellard return s->level & s->irq_enabled; 340b5ff1b31Sbellard case 1: /* IRQ_RAWSTAT */ 341b5ff1b31Sbellard return s->level; 342b5ff1b31Sbellard case 2: /* IRQ_ENABLESET */ 343b5ff1b31Sbellard return s->irq_enabled; 344b5ff1b31Sbellard case 4: /* INT_SOFTSET */ 345b5ff1b31Sbellard return s->level & 1; 346b5ff1b31Sbellard case 8: /* FRQ_STATUS */ 347b5ff1b31Sbellard return s->level & s->fiq_enabled; 348b5ff1b31Sbellard case 9: /* FRQ_RAWSTAT */ 349b5ff1b31Sbellard return s->level; 350b5ff1b31Sbellard case 10: /* FRQ_ENABLESET */ 351b5ff1b31Sbellard return s->fiq_enabled; 352b5ff1b31Sbellard case 3: /* IRQ_ENABLECLR */ 353b5ff1b31Sbellard case 5: /* INT_SOFTCLR */ 354b5ff1b31Sbellard case 11: /* FRQ_ENABLECLR */ 355b5ff1b31Sbellard default: 35629bfb117Spbrook printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); 357b5ff1b31Sbellard return 0; 358b5ff1b31Sbellard } 359b5ff1b31Sbellard } 360b5ff1b31Sbellard 361a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset, 36261074e46SBenoît Canet uint64_t value, unsigned size) 363b5ff1b31Sbellard { 364b5ff1b31Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 365b5ff1b31Sbellard 366b5ff1b31Sbellard switch (offset >> 2) { 367b5ff1b31Sbellard case 2: /* IRQ_ENABLESET */ 368b5ff1b31Sbellard s->irq_enabled |= value; 369b5ff1b31Sbellard break; 370b5ff1b31Sbellard case 3: /* IRQ_ENABLECLR */ 371b5ff1b31Sbellard s->irq_enabled &= ~value; 372b5ff1b31Sbellard break; 373b5ff1b31Sbellard case 4: /* INT_SOFTSET */ 374b5ff1b31Sbellard if (value & 1) 375d537cf6cSpbrook icp_pic_set_irq(s, 0, 1); 376b5ff1b31Sbellard break; 377b5ff1b31Sbellard case 5: /* INT_SOFTCLR */ 378b5ff1b31Sbellard if (value & 1) 379d537cf6cSpbrook icp_pic_set_irq(s, 0, 0); 380b5ff1b31Sbellard break; 381b5ff1b31Sbellard case 10: /* FRQ_ENABLESET */ 382b5ff1b31Sbellard s->fiq_enabled |= value; 383b5ff1b31Sbellard break; 384b5ff1b31Sbellard case 11: /* FRQ_ENABLECLR */ 385b5ff1b31Sbellard s->fiq_enabled &= ~value; 386b5ff1b31Sbellard break; 387b5ff1b31Sbellard case 0: /* IRQ_STATUS */ 388b5ff1b31Sbellard case 1: /* IRQ_RAWSTAT */ 389b5ff1b31Sbellard case 8: /* FRQ_STATUS */ 390b5ff1b31Sbellard case 9: /* FRQ_RAWSTAT */ 391b5ff1b31Sbellard default: 39229bfb117Spbrook printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); 393b5ff1b31Sbellard return; 394b5ff1b31Sbellard } 395b5ff1b31Sbellard icp_pic_update(s); 396b5ff1b31Sbellard } 397b5ff1b31Sbellard 39861074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = { 39961074e46SBenoît Canet .read = icp_pic_read, 40061074e46SBenoît Canet .write = icp_pic_write, 40161074e46SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 402b5ff1b31Sbellard }; 403b5ff1b31Sbellard 404a1f42e0cSxiaoqiang.zhao static void icp_pic_init(Object *obj) 405b5ff1b31Sbellard { 406a1f42e0cSxiaoqiang.zhao DeviceState *dev = DEVICE(obj); 407a1f42e0cSxiaoqiang.zhao icp_pic_state *s = INTEGRATOR_PIC(obj); 408a1f42e0cSxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 409b5ff1b31Sbellard 41091b64626SAndreas Färber qdev_init_gpio_in(dev, icp_pic_set_irq, 32); 41191b64626SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq); 41291b64626SAndreas Färber sysbus_init_irq(sbd, &s->parent_fiq); 413a1f42e0cSxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &icp_pic_ops, s, 41464bde0f3SPaolo Bonzini "icp-pic", 0x00800000); 41591b64626SAndreas Färber sysbus_init_mmio(sbd, &s->iomem); 416b5ff1b31Sbellard } 417b5ff1b31Sbellard 418b5ff1b31Sbellard /* CP control registers. */ 4190c36493eSBenoît Canet 420ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs" 421ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \ 422ffc8542aSJan Kiszka OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS) 423ffc8542aSJan Kiszka 424ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState { 425ffc8542aSJan Kiszka /*< private >*/ 426ffc8542aSJan Kiszka SysBusDevice parent_obj; 427ffc8542aSJan Kiszka /*< public >*/ 428ffc8542aSJan Kiszka 429ffc8542aSJan Kiszka MemoryRegion iomem; 43083d0cf89SJan Kiszka 43183d0cf89SJan Kiszka qemu_irq mmc_irq; 43283d0cf89SJan Kiszka uint32_t intreg_state; 433ffc8542aSJan Kiszka } ICPCtrlRegsState; 434ffc8542aSJan Kiszka 43583d0cf89SJan Kiszka #define ICP_GPIO_MMC_WPROT "mmc-wprot" 43683d0cf89SJan Kiszka #define ICP_GPIO_MMC_CARDIN "mmc-cardin" 43783d0cf89SJan Kiszka 43883d0cf89SJan Kiszka #define ICP_INTREG_WPROT (1 << 0) 43983d0cf89SJan Kiszka #define ICP_INTREG_CARDIN (1 << 3) 44083d0cf89SJan Kiszka 441a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset, 4420c36493eSBenoît Canet unsigned size) 443b5ff1b31Sbellard { 44483d0cf89SJan Kiszka ICPCtrlRegsState *s = opaque; 44583d0cf89SJan Kiszka 446b5ff1b31Sbellard switch (offset >> 2) { 447b5ff1b31Sbellard case 0: /* CP_IDFIELD */ 448b5ff1b31Sbellard return 0x41034003; 449b5ff1b31Sbellard case 1: /* CP_FLASHPROG */ 450b5ff1b31Sbellard return 0; 451b5ff1b31Sbellard case 2: /* CP_INTREG */ 45283d0cf89SJan Kiszka return s->intreg_state; 453b5ff1b31Sbellard case 3: /* CP_DECODE */ 454b5ff1b31Sbellard return 0x11; 455b5ff1b31Sbellard default: 4562ac71179SPaul Brook hw_error("icp_control_read: Bad offset %x\n", (int)offset); 457b5ff1b31Sbellard return 0; 458b5ff1b31Sbellard } 459b5ff1b31Sbellard } 460b5ff1b31Sbellard 461a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset, 4620c36493eSBenoît Canet uint64_t value, unsigned size) 463b5ff1b31Sbellard { 46483d0cf89SJan Kiszka ICPCtrlRegsState *s = opaque; 46583d0cf89SJan Kiszka 466b5ff1b31Sbellard switch (offset >> 2) { 467b5ff1b31Sbellard case 2: /* CP_INTREG */ 46883d0cf89SJan Kiszka s->intreg_state &= ~(value & ICP_INTREG_CARDIN); 46983d0cf89SJan Kiszka qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN)); 47083d0cf89SJan Kiszka break; 47183d0cf89SJan Kiszka case 1: /* CP_FLASHPROG */ 472b5ff1b31Sbellard case 3: /* CP_DECODE */ 473b5ff1b31Sbellard /* Nothing interesting implemented yet. */ 474b5ff1b31Sbellard break; 475b5ff1b31Sbellard default: 4762ac71179SPaul Brook hw_error("icp_control_write: Bad offset %x\n", (int)offset); 477b5ff1b31Sbellard } 478b5ff1b31Sbellard } 4790c36493eSBenoît Canet 4800c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = { 4810c36493eSBenoît Canet .read = icp_control_read, 4820c36493eSBenoît Canet .write = icp_control_write, 4830c36493eSBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 484b5ff1b31Sbellard }; 485b5ff1b31Sbellard 48683d0cf89SJan Kiszka static void icp_control_mmc_wprot(void *opaque, int line, int level) 48783d0cf89SJan Kiszka { 48883d0cf89SJan Kiszka ICPCtrlRegsState *s = opaque; 48983d0cf89SJan Kiszka 49083d0cf89SJan Kiszka s->intreg_state &= ~ICP_INTREG_WPROT; 49183d0cf89SJan Kiszka if (level) { 49283d0cf89SJan Kiszka s->intreg_state |= ICP_INTREG_WPROT; 49383d0cf89SJan Kiszka } 49483d0cf89SJan Kiszka } 49583d0cf89SJan Kiszka 49683d0cf89SJan Kiszka static void icp_control_mmc_cardin(void *opaque, int line, int level) 49783d0cf89SJan Kiszka { 49883d0cf89SJan Kiszka ICPCtrlRegsState *s = opaque; 49983d0cf89SJan Kiszka 50083d0cf89SJan Kiszka /* line is released by writing to CP_INTREG */ 50183d0cf89SJan Kiszka if (level) { 50283d0cf89SJan Kiszka s->intreg_state |= ICP_INTREG_CARDIN; 50383d0cf89SJan Kiszka qemu_set_irq(s->mmc_irq, 1); 50483d0cf89SJan Kiszka } 50583d0cf89SJan Kiszka } 50683d0cf89SJan Kiszka 507ffc8542aSJan Kiszka static void icp_control_init(Object *obj) 508b5ff1b31Sbellard { 509ffc8542aSJan Kiszka SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 510ffc8542aSJan Kiszka ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj); 51183d0cf89SJan Kiszka DeviceState *dev = DEVICE(obj); 512b5ff1b31Sbellard 513ffc8542aSJan Kiszka memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s, 514ffc8542aSJan Kiszka "icp_ctrl_regs", 0x00800000); 515ffc8542aSJan Kiszka sysbus_init_mmio(sbd, &s->iomem); 51683d0cf89SJan Kiszka 51783d0cf89SJan Kiszka qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1); 51883d0cf89SJan Kiszka qdev_init_gpio_in_named(dev, icp_control_mmc_cardin, 51983d0cf89SJan Kiszka ICP_GPIO_MMC_CARDIN, 1); 52083d0cf89SJan Kiszka sysbus_init_irq(sbd, &s->mmc_irq); 521b5ff1b31Sbellard } 522b5ff1b31Sbellard 523b5ff1b31Sbellard 524b5ff1b31Sbellard /* Board init. */ 525b5ff1b31Sbellard 526f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = { 527f93eb9ffSbalrog .loader_start = 0x0, 528f93eb9ffSbalrog .board_id = 0x113, 529f93eb9ffSbalrog }; 530f93eb9ffSbalrog 5313ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine) 532b5ff1b31Sbellard { 5333ef96221SMarcel Apfelbaum ram_addr_t ram_size = machine->ram_size; 5343ef96221SMarcel Apfelbaum const char *cpu_model = machine->cpu_model; 5353ef96221SMarcel Apfelbaum const char *kernel_filename = machine->kernel_filename; 5363ef96221SMarcel Apfelbaum const char *kernel_cmdline = machine->kernel_cmdline; 5373ef96221SMarcel Apfelbaum const char *initrd_filename = machine->initrd_filename; 538223a72f1SGreg Bellows ObjectClass *cpu_oc; 539223a72f1SGreg Bellows Object *cpuobj; 540393a9eabSAndreas Färber ARMCPU *cpu; 541211adf4dSAvi Kivity MemoryRegion *address_space_mem = get_system_memory(); 542211adf4dSAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 543211adf4dSAvi Kivity MemoryRegion *ram_alias = g_new(MemoryRegion, 1); 544a7086888SPaul Brook qemu_irq pic[32]; 54583d0cf89SJan Kiszka DeviceState *dev, *sic, *icp; 546a7086888SPaul Brook int i; 547b5ff1b31Sbellard 548393a9eabSAndreas Färber if (!cpu_model) { 5493371d272Spbrook cpu_model = "arm926"; 550393a9eabSAndreas Färber } 551223a72f1SGreg Bellows 552223a72f1SGreg Bellows cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); 553223a72f1SGreg Bellows if (!cpu_oc) { 554aaed909aSbellard fprintf(stderr, "Unable to find CPU definition\n"); 555aaed909aSbellard exit(1); 556aaed909aSbellard } 557393a9eabSAndreas Färber 558223a72f1SGreg Bellows cpuobj = object_new(object_class_get_name(cpu_oc)); 559223a72f1SGreg Bellows 56061e2f352SGreg Bellows /* By default ARM1176 CPUs have EL3 enabled. This board does not 56161e2f352SGreg Bellows * currently support EL3 so the CPU EL3 property is disabled before 56261e2f352SGreg Bellows * realization. 56361e2f352SGreg Bellows */ 56461e2f352SGreg Bellows if (object_property_find(cpuobj, "has_el3", NULL)) { 565007b0657SMarkus Armbruster object_property_set_bool(cpuobj, false, "has_el3", &error_fatal); 56661e2f352SGreg Bellows } 56761e2f352SGreg Bellows 568007b0657SMarkus Armbruster object_property_set_bool(cpuobj, true, "realized", &error_fatal); 569223a72f1SGreg Bellows 570223a72f1SGreg Bellows cpu = ARM_CPU(cpuobj); 571223a72f1SGreg Bellows 572c8623c02SDirk Müller memory_region_allocate_system_memory(ram, NULL, "integrator.ram", 573c8623c02SDirk Müller ram_size); 574b5ff1b31Sbellard /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ 5751235fc06Sths /* ??? RAM should repeat to fill physical memory space. */ 576b5ff1b31Sbellard /* SDRAM at address zero*/ 577211adf4dSAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 578b5ff1b31Sbellard /* And again at address 0x80000000 */ 5792c9b15caSPaolo Bonzini memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size); 580211adf4dSAvi Kivity memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); 581b5ff1b31Sbellard 582257ec289SAndreas Färber dev = qdev_create(NULL, TYPE_INTEGRATOR_CM); 583ee6847d1SGerd Hoffmann qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); 584e23a1b33SMarkus Armbruster qdev_init_nofail(dev); 585a7086888SPaul Brook sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); 586a7086888SPaul Brook 58791b64626SAndreas Färber dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, 58899d228d6SPeter Maydell qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), 58999d228d6SPeter Maydell qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), 59099d228d6SPeter Maydell NULL); 591a7086888SPaul Brook for (i = 0; i < 32; i++) { 592067a3ddcSPaul Brook pic[i] = qdev_get_gpio_in(dev, i); 593a7086888SPaul Brook } 59483d0cf89SJan Kiszka sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]); 5956a824ec3SPaul Brook sysbus_create_varargs("integrator_pit", 0x13000000, 5966a824ec3SPaul Brook pic[5], pic[6], pic[7], NULL); 597a63bdb31SPaul Brook sysbus_create_simple("pl031", 0x15000000, pic[8]); 598f0d1d2c1Sxiaoqiang zhao pl011_create(0x16000000, pic[1], serial_hds[0]); 599f0d1d2c1Sxiaoqiang zhao pl011_create(0x17000000, pic[2], serial_hds[1]); 60083d0cf89SJan Kiszka icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, 60183d0cf89SJan Kiszka qdev_get_gpio_in(sic, 3)); 60286394e96SPaul Brook sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); 60386394e96SPaul Brook sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); 604b8616055SAlex Bennée sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0); 60583d0cf89SJan Kiszka 60683d0cf89SJan Kiszka dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); 60783d0cf89SJan Kiszka qdev_connect_gpio_out(dev, 0, 60883d0cf89SJan Kiszka qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0)); 60983d0cf89SJan Kiszka qdev_connect_gpio_out(dev, 1, 61083d0cf89SJan Kiszka qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0)); 61183d0cf89SJan Kiszka 612a005d073SStefan Hajnoczi if (nd_table[0].used) 613d537cf6cSpbrook smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); 6142e9bdce5SPaul Brook 6152e9bdce5SPaul Brook sysbus_create_simple("pl110", 0xc0000000, pic[22]); 616b5ff1b31Sbellard 617f93eb9ffSbalrog integrator_binfo.ram_size = ram_size; 618f93eb9ffSbalrog integrator_binfo.kernel_filename = kernel_filename; 619f93eb9ffSbalrog integrator_binfo.kernel_cmdline = kernel_cmdline; 620f93eb9ffSbalrog integrator_binfo.initrd_filename = initrd_filename; 6213aaa8dfaSAndreas Färber arm_load_kernel(cpu, &integrator_binfo); 622b5ff1b31Sbellard } 623b5ff1b31Sbellard 624e264d29dSEduardo Habkost static void integratorcp_machine_init(MachineClass *mc) 625f80f9ec9SAnthony Liguori { 626e264d29dSEduardo Habkost mc->desc = "ARM Integrator/CP (ARM926EJ-S)"; 627e264d29dSEduardo Habkost mc->init = integratorcp_init; 628f80f9ec9SAnthony Liguori } 629f80f9ec9SAnthony Liguori 630e264d29dSEduardo Habkost DEFINE_MACHINE("integratorcp", integratorcp_machine_init) 631f80f9ec9SAnthony Liguori 632999e12bbSAnthony Liguori static Property core_properties[] = { 633257ec289SAndreas Färber DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), 634bb36f66aSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 635999e12bbSAnthony Liguori }; 636999e12bbSAnthony Liguori 637999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data) 638999e12bbSAnthony Liguori { 63939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 640999e12bbSAnthony Liguori 64139bffca2SAnthony Liguori dc->props = core_properties; 642*e9d9ee23SJakub Jermar dc->realize = integratorcm_realize; 643ee6847d1SGerd Hoffmann } 644999e12bbSAnthony Liguori 6458c43a6f0SAndreas Färber static const TypeInfo core_info = { 646257ec289SAndreas Färber .name = TYPE_INTEGRATOR_CM, 64739bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 648257ec289SAndreas Färber .instance_size = sizeof(IntegratorCMState), 649a1f42e0cSxiaoqiang.zhao .instance_init = integratorcm_init, 650999e12bbSAnthony Liguori .class_init = core_class_init, 651999e12bbSAnthony Liguori }; 652999e12bbSAnthony Liguori 6538c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = { 65491b64626SAndreas Färber .name = TYPE_INTEGRATOR_PIC, 65539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 65639bffca2SAnthony Liguori .instance_size = sizeof(icp_pic_state), 657a1f42e0cSxiaoqiang.zhao .instance_init = icp_pic_init, 658ee6847d1SGerd Hoffmann }; 659ee6847d1SGerd Hoffmann 660ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = { 661ffc8542aSJan Kiszka .name = TYPE_ICP_CONTROL_REGS, 662ffc8542aSJan Kiszka .parent = TYPE_SYS_BUS_DEVICE, 663ffc8542aSJan Kiszka .instance_size = sizeof(ICPCtrlRegsState), 664ffc8542aSJan Kiszka .instance_init = icp_control_init, 665ffc8542aSJan Kiszka }; 666ffc8542aSJan Kiszka 66783f7d43aSAndreas Färber static void integratorcp_register_types(void) 668a7086888SPaul Brook { 66939bffca2SAnthony Liguori type_register_static(&icp_pic_info); 67039bffca2SAnthony Liguori type_register_static(&core_info); 671ffc8542aSJan Kiszka type_register_static(&icp_ctrl_regs_info); 672a7086888SPaul Brook } 673a7086888SPaul Brook 67483f7d43aSAndreas Färber type_init(integratorcp_register_types) 675