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 1083c9f4caSPaolo Bonzini #include "hw/sysbus.h" 11bd2be150SPeter Maydell #include "hw/devices.h" 1283c9f4caSPaolo Bonzini #include "hw/boards.h" 13bd2be150SPeter Maydell #include "hw/arm/arm.h" 14b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h" 151422e32dSPaolo Bonzini #include "net/net.h" 16022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 179c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 18223a72f1SGreg Bellows #include "qemu/error-report.h" 19b5ff1b31Sbellard 20257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core" 21257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \ 22257ec289SAndreas Färber OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM) 23257ec289SAndreas Färber 24257ec289SAndreas Färber typedef struct IntegratorCMState { 25257ec289SAndreas Färber /*< private >*/ 26257ec289SAndreas Färber SysBusDevice parent_obj; 27257ec289SAndreas Färber /*< public >*/ 28257ec289SAndreas Färber 2971d9bc50SBenoît Canet MemoryRegion iomem; 30ee6847d1SGerd Hoffmann uint32_t memsz; 31211adf4dSAvi Kivity MemoryRegion flash; 32b5ff1b31Sbellard uint32_t cm_osc; 33b5ff1b31Sbellard uint32_t cm_ctrl; 34b5ff1b31Sbellard uint32_t cm_lock; 35b5ff1b31Sbellard uint32_t cm_auxosc; 36b5ff1b31Sbellard uint32_t cm_sdram; 37b5ff1b31Sbellard uint32_t cm_init; 38b5ff1b31Sbellard uint32_t cm_flags; 39b5ff1b31Sbellard uint32_t cm_nvflags; 40f53977f7SJan Petrous uint32_t cm_refcnt_offset; 41b5ff1b31Sbellard uint32_t int_level; 42b5ff1b31Sbellard uint32_t irq_enabled; 43b5ff1b31Sbellard uint32_t fiq_enabled; 44257ec289SAndreas Färber } IntegratorCMState; 45b5ff1b31Sbellard 46b5ff1b31Sbellard static uint8_t integrator_spd[128] = { 47b5ff1b31Sbellard 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, 48b5ff1b31Sbellard 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 49b5ff1b31Sbellard }; 50b5ff1b31Sbellard 51a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset, 5271d9bc50SBenoît Canet unsigned size) 53b5ff1b31Sbellard { 54257ec289SAndreas Färber IntegratorCMState *s = opaque; 55b5ff1b31Sbellard if (offset >= 0x100 && offset < 0x200) { 56b5ff1b31Sbellard /* CM_SPD */ 57b5ff1b31Sbellard if (offset >= 0x180) 58b5ff1b31Sbellard return 0; 59b5ff1b31Sbellard return integrator_spd[offset >> 2]; 60b5ff1b31Sbellard } 61b5ff1b31Sbellard switch (offset >> 2) { 62b5ff1b31Sbellard case 0: /* CM_ID */ 63b5ff1b31Sbellard return 0x411a3001; 64b5ff1b31Sbellard case 1: /* CM_PROC */ 65b5ff1b31Sbellard return 0; 66b5ff1b31Sbellard case 2: /* CM_OSC */ 67b5ff1b31Sbellard return s->cm_osc; 68b5ff1b31Sbellard case 3: /* CM_CTRL */ 69b5ff1b31Sbellard return s->cm_ctrl; 70b5ff1b31Sbellard case 4: /* CM_STAT */ 71b5ff1b31Sbellard return 0x00100000; 72b5ff1b31Sbellard case 5: /* CM_LOCK */ 73b5ff1b31Sbellard if (s->cm_lock == 0xa05f) { 74b5ff1b31Sbellard return 0x1a05f; 75b5ff1b31Sbellard } else { 76b5ff1b31Sbellard return s->cm_lock; 77b5ff1b31Sbellard } 78b5ff1b31Sbellard case 6: /* CM_LMBUSCNT */ 79b5ff1b31Sbellard /* ??? High frequency timer. */ 802ac71179SPaul Brook hw_error("integratorcm_read: CM_LMBUSCNT"); 81b5ff1b31Sbellard case 7: /* CM_AUXOSC */ 82b5ff1b31Sbellard return s->cm_auxosc; 83b5ff1b31Sbellard case 8: /* CM_SDRAM */ 84b5ff1b31Sbellard return s->cm_sdram; 85b5ff1b31Sbellard case 9: /* CM_INIT */ 86b5ff1b31Sbellard return s->cm_init; 87f53977f7SJan Petrous case 10: /* CM_REFCNT */ 88f53977f7SJan Petrous /* This register, CM_REFCNT, provides a 32-bit count value. 89f53977f7SJan Petrous * The count increments at the fixed reference clock frequency of 24MHz 90f53977f7SJan Petrous * and can be used as a real-time counter. 91f53977f7SJan Petrous */ 92f53977f7SJan Petrous return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 93f53977f7SJan Petrous 1000) - s->cm_refcnt_offset; 94b5ff1b31Sbellard case 12: /* CM_FLAGS */ 95b5ff1b31Sbellard return s->cm_flags; 96b5ff1b31Sbellard case 14: /* CM_NVFLAGS */ 97b5ff1b31Sbellard return s->cm_nvflags; 98b5ff1b31Sbellard case 16: /* CM_IRQ_STAT */ 99b5ff1b31Sbellard return s->int_level & s->irq_enabled; 100b5ff1b31Sbellard case 17: /* CM_IRQ_RSTAT */ 101b5ff1b31Sbellard return s->int_level; 102b5ff1b31Sbellard case 18: /* CM_IRQ_ENSET */ 103b5ff1b31Sbellard return s->irq_enabled; 104b5ff1b31Sbellard case 20: /* CM_SOFT_INTSET */ 105b5ff1b31Sbellard return s->int_level & 1; 106b5ff1b31Sbellard case 24: /* CM_FIQ_STAT */ 107b5ff1b31Sbellard return s->int_level & s->fiq_enabled; 108b5ff1b31Sbellard case 25: /* CM_FIQ_RSTAT */ 109b5ff1b31Sbellard return s->int_level; 110b5ff1b31Sbellard case 26: /* CM_FIQ_ENSET */ 111b5ff1b31Sbellard return s->fiq_enabled; 112b5ff1b31Sbellard case 32: /* CM_VOLTAGE_CTL0 */ 113b5ff1b31Sbellard case 33: /* CM_VOLTAGE_CTL1 */ 114b5ff1b31Sbellard case 34: /* CM_VOLTAGE_CTL2 */ 115b5ff1b31Sbellard case 35: /* CM_VOLTAGE_CTL3 */ 116b5ff1b31Sbellard /* ??? Voltage control unimplemented. */ 117b5ff1b31Sbellard return 0; 118b5ff1b31Sbellard default: 1192ac71179SPaul Brook hw_error("integratorcm_read: Unimplemented offset 0x%x\n", 1202ac71179SPaul Brook (int)offset); 121b5ff1b31Sbellard return 0; 122b5ff1b31Sbellard } 123b5ff1b31Sbellard } 124b5ff1b31Sbellard 125257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s) 126b5ff1b31Sbellard { 127563c2bf3SPeter Maydell /* Sync memory region state with CM_CTRL REMAP bit: 128563c2bf3SPeter Maydell * bit 0 => flash at address 0; bit 1 => RAM 129563c2bf3SPeter Maydell */ 130563c2bf3SPeter Maydell memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4)); 131b5ff1b31Sbellard } 132b5ff1b31Sbellard 133257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value) 134b5ff1b31Sbellard { 135b5ff1b31Sbellard if (value & 8) { 136df3f457bSPeter Maydell qemu_system_reset_request(); 137b5ff1b31Sbellard } 138df3f457bSPeter Maydell if ((s->cm_ctrl ^ value) & 1) { 139df3f457bSPeter Maydell /* (value & 1) != 0 means the green "MISC LED" is lit. 140df3f457bSPeter Maydell * We don't have any nice place to display LEDs. printf is a bad 141df3f457bSPeter Maydell * idea because Linux uses the LED as a heartbeat and the output 142df3f457bSPeter Maydell * will swamp anything else on the terminal. 143df3f457bSPeter Maydell */ 144b5ff1b31Sbellard } 145df3f457bSPeter Maydell /* Note that the RESET bit [3] always reads as zero */ 146df3f457bSPeter Maydell s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5); 147563c2bf3SPeter Maydell integratorcm_do_remap(s); 148b5ff1b31Sbellard } 149b5ff1b31Sbellard 150257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s) 151b5ff1b31Sbellard { 152b5ff1b31Sbellard /* ??? The CPU irq/fiq is raised when either the core module or base PIC 153b5ff1b31Sbellard are active. */ 154b5ff1b31Sbellard if (s->int_level & (s->irq_enabled | s->fiq_enabled)) 1552ac71179SPaul Brook hw_error("Core module interrupt\n"); 156b5ff1b31Sbellard } 157b5ff1b31Sbellard 158a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset, 15971d9bc50SBenoît Canet uint64_t value, unsigned size) 160b5ff1b31Sbellard { 161257ec289SAndreas Färber IntegratorCMState *s = opaque; 162b5ff1b31Sbellard switch (offset >> 2) { 163b5ff1b31Sbellard case 2: /* CM_OSC */ 164b5ff1b31Sbellard if (s->cm_lock == 0xa05f) 165b5ff1b31Sbellard s->cm_osc = value; 166b5ff1b31Sbellard break; 167b5ff1b31Sbellard case 3: /* CM_CTRL */ 168b5ff1b31Sbellard integratorcm_set_ctrl(s, value); 169b5ff1b31Sbellard break; 170b5ff1b31Sbellard case 5: /* CM_LOCK */ 171b5ff1b31Sbellard s->cm_lock = value & 0xffff; 172b5ff1b31Sbellard break; 173b5ff1b31Sbellard case 7: /* CM_AUXOSC */ 174b5ff1b31Sbellard if (s->cm_lock == 0xa05f) 175b5ff1b31Sbellard s->cm_auxosc = value; 176b5ff1b31Sbellard break; 177b5ff1b31Sbellard case 8: /* CM_SDRAM */ 178b5ff1b31Sbellard s->cm_sdram = value; 179b5ff1b31Sbellard break; 180b5ff1b31Sbellard case 9: /* CM_INIT */ 181b5ff1b31Sbellard /* ??? This can change the memory bus frequency. */ 182b5ff1b31Sbellard s->cm_init = value; 183b5ff1b31Sbellard break; 184b5ff1b31Sbellard case 12: /* CM_FLAGSS */ 185b5ff1b31Sbellard s->cm_flags |= value; 186b5ff1b31Sbellard break; 187b5ff1b31Sbellard case 13: /* CM_FLAGSC */ 188b5ff1b31Sbellard s->cm_flags &= ~value; 189b5ff1b31Sbellard break; 190b5ff1b31Sbellard case 14: /* CM_NVFLAGSS */ 191b5ff1b31Sbellard s->cm_nvflags |= value; 192b5ff1b31Sbellard break; 193b5ff1b31Sbellard case 15: /* CM_NVFLAGSS */ 194b5ff1b31Sbellard s->cm_nvflags &= ~value; 195b5ff1b31Sbellard break; 196b5ff1b31Sbellard case 18: /* CM_IRQ_ENSET */ 197b5ff1b31Sbellard s->irq_enabled |= value; 198b5ff1b31Sbellard integratorcm_update(s); 199b5ff1b31Sbellard break; 200b5ff1b31Sbellard case 19: /* CM_IRQ_ENCLR */ 201b5ff1b31Sbellard s->irq_enabled &= ~value; 202b5ff1b31Sbellard integratorcm_update(s); 203b5ff1b31Sbellard break; 204b5ff1b31Sbellard case 20: /* CM_SOFT_INTSET */ 205b5ff1b31Sbellard s->int_level |= (value & 1); 206b5ff1b31Sbellard integratorcm_update(s); 207b5ff1b31Sbellard break; 208b5ff1b31Sbellard case 21: /* CM_SOFT_INTCLR */ 209b5ff1b31Sbellard s->int_level &= ~(value & 1); 210b5ff1b31Sbellard integratorcm_update(s); 211b5ff1b31Sbellard break; 212b5ff1b31Sbellard case 26: /* CM_FIQ_ENSET */ 213b5ff1b31Sbellard s->fiq_enabled |= value; 214b5ff1b31Sbellard integratorcm_update(s); 215b5ff1b31Sbellard break; 216b5ff1b31Sbellard case 27: /* CM_FIQ_ENCLR */ 217b5ff1b31Sbellard s->fiq_enabled &= ~value; 218b5ff1b31Sbellard integratorcm_update(s); 219b5ff1b31Sbellard break; 220b5ff1b31Sbellard case 32: /* CM_VOLTAGE_CTL0 */ 221b5ff1b31Sbellard case 33: /* CM_VOLTAGE_CTL1 */ 222b5ff1b31Sbellard case 34: /* CM_VOLTAGE_CTL2 */ 223b5ff1b31Sbellard case 35: /* CM_VOLTAGE_CTL3 */ 224b5ff1b31Sbellard /* ??? Voltage control unimplemented. */ 225b5ff1b31Sbellard break; 226b5ff1b31Sbellard default: 2272ac71179SPaul Brook hw_error("integratorcm_write: Unimplemented offset 0x%x\n", 2282ac71179SPaul Brook (int)offset); 229b5ff1b31Sbellard break; 230b5ff1b31Sbellard } 231b5ff1b31Sbellard } 232b5ff1b31Sbellard 233b5ff1b31Sbellard /* Integrator/CM control registers. */ 234b5ff1b31Sbellard 23571d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = { 23671d9bc50SBenoît Canet .read = integratorcm_read, 23771d9bc50SBenoît Canet .write = integratorcm_write, 23871d9bc50SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 239b5ff1b31Sbellard }; 240b5ff1b31Sbellard 24181a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev) 242b5ff1b31Sbellard { 243257ec289SAndreas Färber IntegratorCMState *s = INTEGRATOR_CM(dev); 244b5ff1b31Sbellard 245b5ff1b31Sbellard s->cm_osc = 0x01000048; 246b5ff1b31Sbellard /* ??? What should the high bits of this value be? */ 247b5ff1b31Sbellard s->cm_auxosc = 0x0007feff; 248b5ff1b31Sbellard s->cm_sdram = 0x00011122; 249ee6847d1SGerd Hoffmann if (s->memsz >= 256) { 250b5ff1b31Sbellard integrator_spd[31] = 64; 251b5ff1b31Sbellard s->cm_sdram |= 0x10; 252ee6847d1SGerd Hoffmann } else if (s->memsz >= 128) { 253b5ff1b31Sbellard integrator_spd[31] = 32; 254b5ff1b31Sbellard s->cm_sdram |= 0x0c; 255ee6847d1SGerd Hoffmann } else if (s->memsz >= 64) { 256b5ff1b31Sbellard integrator_spd[31] = 16; 257b5ff1b31Sbellard s->cm_sdram |= 0x08; 258ee6847d1SGerd Hoffmann } else if (s->memsz >= 32) { 259b5ff1b31Sbellard integrator_spd[31] = 4; 260b5ff1b31Sbellard s->cm_sdram |= 0x04; 261b5ff1b31Sbellard } else { 262b5ff1b31Sbellard integrator_spd[31] = 2; 263b5ff1b31Sbellard } 264b5ff1b31Sbellard memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); 265b5ff1b31Sbellard s->cm_init = 0x00000112; 266f53977f7SJan Petrous s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 267f53977f7SJan Petrous 1000); 26849946538SHu Tao memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000, 26949946538SHu Tao &error_abort); 270c5705a77SAvi Kivity vmstate_register_ram_global(&s->flash); 271b5ff1b31Sbellard 27264bde0f3SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s, 27371d9bc50SBenoît Canet "integratorcm", 0x00800000); 274750ecd44SAvi Kivity sysbus_init_mmio(dev, &s->iomem); 27571d9bc50SBenoît Canet 276563c2bf3SPeter Maydell integratorcm_do_remap(s); 277b5ff1b31Sbellard /* ??? Save/restore. */ 27881a322d4SGerd Hoffmann return 0; 279b5ff1b31Sbellard } 280b5ff1b31Sbellard 281b5ff1b31Sbellard /* Integrator/CP hardware emulation. */ 282b5ff1b31Sbellard /* Primary interrupt controller. */ 283b5ff1b31Sbellard 28491b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic" 28591b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \ 28691b64626SAndreas Färber OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC) 28791b64626SAndreas Färber 28891b64626SAndreas Färber typedef struct icp_pic_state { 28991b64626SAndreas Färber /*< private >*/ 29091b64626SAndreas Färber SysBusDevice parent_obj; 29191b64626SAndreas Färber /*< public >*/ 29291b64626SAndreas Färber 29361074e46SBenoît Canet MemoryRegion iomem; 294b5ff1b31Sbellard uint32_t level; 295b5ff1b31Sbellard uint32_t irq_enabled; 296b5ff1b31Sbellard uint32_t fiq_enabled; 297d537cf6cSpbrook qemu_irq parent_irq; 298d537cf6cSpbrook qemu_irq parent_fiq; 299b5ff1b31Sbellard } icp_pic_state; 300b5ff1b31Sbellard 301b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s) 302b5ff1b31Sbellard { 303b5ff1b31Sbellard uint32_t flags; 304b5ff1b31Sbellard 305b5ff1b31Sbellard flags = (s->level & s->irq_enabled); 306d537cf6cSpbrook qemu_set_irq(s->parent_irq, flags != 0); 307cdbdb648Spbrook flags = (s->level & s->fiq_enabled); 308d537cf6cSpbrook qemu_set_irq(s->parent_fiq, flags != 0); 309b5ff1b31Sbellard } 310b5ff1b31Sbellard 311cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level) 312b5ff1b31Sbellard { 31380337b66Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 314b5ff1b31Sbellard if (level) 31580337b66Sbellard s->level |= 1 << irq; 316b5ff1b31Sbellard else 31780337b66Sbellard s->level &= ~(1 << irq); 318b5ff1b31Sbellard icp_pic_update(s); 319b5ff1b31Sbellard } 320b5ff1b31Sbellard 321a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset, 32261074e46SBenoît Canet unsigned size) 323b5ff1b31Sbellard { 324b5ff1b31Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 325b5ff1b31Sbellard 326b5ff1b31Sbellard switch (offset >> 2) { 327b5ff1b31Sbellard case 0: /* IRQ_STATUS */ 328b5ff1b31Sbellard return s->level & s->irq_enabled; 329b5ff1b31Sbellard case 1: /* IRQ_RAWSTAT */ 330b5ff1b31Sbellard return s->level; 331b5ff1b31Sbellard case 2: /* IRQ_ENABLESET */ 332b5ff1b31Sbellard return s->irq_enabled; 333b5ff1b31Sbellard case 4: /* INT_SOFTSET */ 334b5ff1b31Sbellard return s->level & 1; 335b5ff1b31Sbellard case 8: /* FRQ_STATUS */ 336b5ff1b31Sbellard return s->level & s->fiq_enabled; 337b5ff1b31Sbellard case 9: /* FRQ_RAWSTAT */ 338b5ff1b31Sbellard return s->level; 339b5ff1b31Sbellard case 10: /* FRQ_ENABLESET */ 340b5ff1b31Sbellard return s->fiq_enabled; 341b5ff1b31Sbellard case 3: /* IRQ_ENABLECLR */ 342b5ff1b31Sbellard case 5: /* INT_SOFTCLR */ 343b5ff1b31Sbellard case 11: /* FRQ_ENABLECLR */ 344b5ff1b31Sbellard default: 34529bfb117Spbrook printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); 346b5ff1b31Sbellard return 0; 347b5ff1b31Sbellard } 348b5ff1b31Sbellard } 349b5ff1b31Sbellard 350a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset, 35161074e46SBenoît Canet uint64_t value, unsigned size) 352b5ff1b31Sbellard { 353b5ff1b31Sbellard icp_pic_state *s = (icp_pic_state *)opaque; 354b5ff1b31Sbellard 355b5ff1b31Sbellard switch (offset >> 2) { 356b5ff1b31Sbellard case 2: /* IRQ_ENABLESET */ 357b5ff1b31Sbellard s->irq_enabled |= value; 358b5ff1b31Sbellard break; 359b5ff1b31Sbellard case 3: /* IRQ_ENABLECLR */ 360b5ff1b31Sbellard s->irq_enabled &= ~value; 361b5ff1b31Sbellard break; 362b5ff1b31Sbellard case 4: /* INT_SOFTSET */ 363b5ff1b31Sbellard if (value & 1) 364d537cf6cSpbrook icp_pic_set_irq(s, 0, 1); 365b5ff1b31Sbellard break; 366b5ff1b31Sbellard case 5: /* INT_SOFTCLR */ 367b5ff1b31Sbellard if (value & 1) 368d537cf6cSpbrook icp_pic_set_irq(s, 0, 0); 369b5ff1b31Sbellard break; 370b5ff1b31Sbellard case 10: /* FRQ_ENABLESET */ 371b5ff1b31Sbellard s->fiq_enabled |= value; 372b5ff1b31Sbellard break; 373b5ff1b31Sbellard case 11: /* FRQ_ENABLECLR */ 374b5ff1b31Sbellard s->fiq_enabled &= ~value; 375b5ff1b31Sbellard break; 376b5ff1b31Sbellard case 0: /* IRQ_STATUS */ 377b5ff1b31Sbellard case 1: /* IRQ_RAWSTAT */ 378b5ff1b31Sbellard case 8: /* FRQ_STATUS */ 379b5ff1b31Sbellard case 9: /* FRQ_RAWSTAT */ 380b5ff1b31Sbellard default: 38129bfb117Spbrook printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); 382b5ff1b31Sbellard return; 383b5ff1b31Sbellard } 384b5ff1b31Sbellard icp_pic_update(s); 385b5ff1b31Sbellard } 386b5ff1b31Sbellard 38761074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = { 38861074e46SBenoît Canet .read = icp_pic_read, 38961074e46SBenoît Canet .write = icp_pic_write, 39061074e46SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 391b5ff1b31Sbellard }; 392b5ff1b31Sbellard 39391b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd) 394b5ff1b31Sbellard { 39591b64626SAndreas Färber DeviceState *dev = DEVICE(sbd); 39691b64626SAndreas Färber icp_pic_state *s = INTEGRATOR_PIC(dev); 397b5ff1b31Sbellard 39891b64626SAndreas Färber qdev_init_gpio_in(dev, icp_pic_set_irq, 32); 39991b64626SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq); 40091b64626SAndreas Färber sysbus_init_irq(sbd, &s->parent_fiq); 40164bde0f3SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s, 40264bde0f3SPaolo Bonzini "icp-pic", 0x00800000); 40391b64626SAndreas Färber sysbus_init_mmio(sbd, &s->iomem); 40481a322d4SGerd Hoffmann return 0; 405b5ff1b31Sbellard } 406b5ff1b31Sbellard 407b5ff1b31Sbellard /* CP control registers. */ 4080c36493eSBenoît Canet 409*ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs" 410*ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \ 411*ffc8542aSJan Kiszka OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS) 412*ffc8542aSJan Kiszka 413*ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState { 414*ffc8542aSJan Kiszka /*< private >*/ 415*ffc8542aSJan Kiszka SysBusDevice parent_obj; 416*ffc8542aSJan Kiszka /*< public >*/ 417*ffc8542aSJan Kiszka 418*ffc8542aSJan Kiszka MemoryRegion iomem; 419*ffc8542aSJan Kiszka } ICPCtrlRegsState; 420*ffc8542aSJan Kiszka 421a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset, 4220c36493eSBenoît Canet unsigned size) 423b5ff1b31Sbellard { 424b5ff1b31Sbellard switch (offset >> 2) { 425b5ff1b31Sbellard case 0: /* CP_IDFIELD */ 426b5ff1b31Sbellard return 0x41034003; 427b5ff1b31Sbellard case 1: /* CP_FLASHPROG */ 428b5ff1b31Sbellard return 0; 429b5ff1b31Sbellard case 2: /* CP_INTREG */ 430b5ff1b31Sbellard return 0; 431b5ff1b31Sbellard case 3: /* CP_DECODE */ 432b5ff1b31Sbellard return 0x11; 433b5ff1b31Sbellard default: 4342ac71179SPaul Brook hw_error("icp_control_read: Bad offset %x\n", (int)offset); 435b5ff1b31Sbellard return 0; 436b5ff1b31Sbellard } 437b5ff1b31Sbellard } 438b5ff1b31Sbellard 439a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset, 4400c36493eSBenoît Canet uint64_t value, unsigned size) 441b5ff1b31Sbellard { 442b5ff1b31Sbellard switch (offset >> 2) { 443b5ff1b31Sbellard case 1: /* CP_FLASHPROG */ 444b5ff1b31Sbellard case 2: /* CP_INTREG */ 445b5ff1b31Sbellard case 3: /* CP_DECODE */ 446b5ff1b31Sbellard /* Nothing interesting implemented yet. */ 447b5ff1b31Sbellard break; 448b5ff1b31Sbellard default: 4492ac71179SPaul Brook hw_error("icp_control_write: Bad offset %x\n", (int)offset); 450b5ff1b31Sbellard } 451b5ff1b31Sbellard } 4520c36493eSBenoît Canet 4530c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = { 4540c36493eSBenoît Canet .read = icp_control_read, 4550c36493eSBenoît Canet .write = icp_control_write, 4560c36493eSBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 457b5ff1b31Sbellard }; 458b5ff1b31Sbellard 459*ffc8542aSJan Kiszka static void icp_control_init(Object *obj) 460b5ff1b31Sbellard { 461*ffc8542aSJan Kiszka SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 462*ffc8542aSJan Kiszka ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj); 463b5ff1b31Sbellard 464*ffc8542aSJan Kiszka memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s, 465*ffc8542aSJan Kiszka "icp_ctrl_regs", 0x00800000); 466*ffc8542aSJan Kiszka sysbus_init_mmio(sbd, &s->iomem); 467b5ff1b31Sbellard } 468b5ff1b31Sbellard 469b5ff1b31Sbellard 470b5ff1b31Sbellard /* Board init. */ 471b5ff1b31Sbellard 472f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = { 473f93eb9ffSbalrog .loader_start = 0x0, 474f93eb9ffSbalrog .board_id = 0x113, 475f93eb9ffSbalrog }; 476f93eb9ffSbalrog 4773ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine) 478b5ff1b31Sbellard { 4793ef96221SMarcel Apfelbaum ram_addr_t ram_size = machine->ram_size; 4803ef96221SMarcel Apfelbaum const char *cpu_model = machine->cpu_model; 4813ef96221SMarcel Apfelbaum const char *kernel_filename = machine->kernel_filename; 4823ef96221SMarcel Apfelbaum const char *kernel_cmdline = machine->kernel_cmdline; 4833ef96221SMarcel Apfelbaum const char *initrd_filename = machine->initrd_filename; 484223a72f1SGreg Bellows ObjectClass *cpu_oc; 485223a72f1SGreg Bellows Object *cpuobj; 486393a9eabSAndreas Färber ARMCPU *cpu; 487211adf4dSAvi Kivity MemoryRegion *address_space_mem = get_system_memory(); 488211adf4dSAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 489211adf4dSAvi Kivity MemoryRegion *ram_alias = g_new(MemoryRegion, 1); 490a7086888SPaul Brook qemu_irq pic[32]; 491a7086888SPaul Brook DeviceState *dev; 492a7086888SPaul Brook int i; 493223a72f1SGreg Bellows Error *err = NULL; 494b5ff1b31Sbellard 495393a9eabSAndreas Färber if (!cpu_model) { 4963371d272Spbrook cpu_model = "arm926"; 497393a9eabSAndreas Färber } 498223a72f1SGreg Bellows 499223a72f1SGreg Bellows cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); 500223a72f1SGreg Bellows if (!cpu_oc) { 501aaed909aSbellard fprintf(stderr, "Unable to find CPU definition\n"); 502aaed909aSbellard exit(1); 503aaed909aSbellard } 504393a9eabSAndreas Färber 505223a72f1SGreg Bellows cpuobj = object_new(object_class_get_name(cpu_oc)); 506223a72f1SGreg Bellows 50761e2f352SGreg Bellows /* By default ARM1176 CPUs have EL3 enabled. This board does not 50861e2f352SGreg Bellows * currently support EL3 so the CPU EL3 property is disabled before 50961e2f352SGreg Bellows * realization. 51061e2f352SGreg Bellows */ 51161e2f352SGreg Bellows if (object_property_find(cpuobj, "has_el3", NULL)) { 51261e2f352SGreg Bellows object_property_set_bool(cpuobj, false, "has_el3", &err); 51361e2f352SGreg Bellows if (err) { 514565f65d2SMarkus Armbruster error_report_err(err); 51561e2f352SGreg Bellows exit(1); 51661e2f352SGreg Bellows } 51761e2f352SGreg Bellows } 51861e2f352SGreg Bellows 519223a72f1SGreg Bellows object_property_set_bool(cpuobj, true, "realized", &err); 520223a72f1SGreg Bellows if (err) { 521565f65d2SMarkus Armbruster error_report_err(err); 522223a72f1SGreg Bellows exit(1); 523223a72f1SGreg Bellows } 524223a72f1SGreg Bellows 525223a72f1SGreg Bellows cpu = ARM_CPU(cpuobj); 526223a72f1SGreg Bellows 52749946538SHu Tao memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort); 528c5705a77SAvi Kivity vmstate_register_ram_global(ram); 529b5ff1b31Sbellard /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ 5301235fc06Sths /* ??? RAM should repeat to fill physical memory space. */ 531b5ff1b31Sbellard /* SDRAM at address zero*/ 532211adf4dSAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 533b5ff1b31Sbellard /* And again at address 0x80000000 */ 5342c9b15caSPaolo Bonzini memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size); 535211adf4dSAvi Kivity memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias); 536b5ff1b31Sbellard 537257ec289SAndreas Färber dev = qdev_create(NULL, TYPE_INTEGRATOR_CM); 538ee6847d1SGerd Hoffmann qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); 539e23a1b33SMarkus Armbruster qdev_init_nofail(dev); 540a7086888SPaul Brook sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); 541a7086888SPaul Brook 54291b64626SAndreas Färber dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000, 54399d228d6SPeter Maydell qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), 54499d228d6SPeter Maydell qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), 54599d228d6SPeter Maydell NULL); 546a7086888SPaul Brook for (i = 0; i < 32; i++) { 547067a3ddcSPaul Brook pic[i] = qdev_get_gpio_in(dev, i); 548a7086888SPaul Brook } 54991b64626SAndreas Färber sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]); 5506a824ec3SPaul Brook sysbus_create_varargs("integrator_pit", 0x13000000, 5516a824ec3SPaul Brook pic[5], pic[6], pic[7], NULL); 552a63bdb31SPaul Brook sysbus_create_simple("pl031", 0x15000000, pic[8]); 553a7d518a6SPaul Brook sysbus_create_simple("pl011", 0x16000000, pic[1]); 554a7d518a6SPaul Brook sysbus_create_simple("pl011", 0x17000000, pic[2]); 555*ffc8542aSJan Kiszka sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, NULL); 55686394e96SPaul Brook sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); 55786394e96SPaul Brook sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); 558b8616055SAlex Bennée sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0); 559aa9311d8SPaul Brook sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); 560a005d073SStefan Hajnoczi if (nd_table[0].used) 561d537cf6cSpbrook smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); 5622e9bdce5SPaul Brook 5632e9bdce5SPaul Brook sysbus_create_simple("pl110", 0xc0000000, pic[22]); 564b5ff1b31Sbellard 565f93eb9ffSbalrog integrator_binfo.ram_size = ram_size; 566f93eb9ffSbalrog integrator_binfo.kernel_filename = kernel_filename; 567f93eb9ffSbalrog integrator_binfo.kernel_cmdline = kernel_cmdline; 568f93eb9ffSbalrog integrator_binfo.initrd_filename = initrd_filename; 5693aaa8dfaSAndreas Färber arm_load_kernel(cpu, &integrator_binfo); 570b5ff1b31Sbellard } 571b5ff1b31Sbellard 572f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = { 5734b32e168Saliguori .name = "integratorcp", 5744b32e168Saliguori .desc = "ARM Integrator/CP (ARM926EJ-S)", 5754b32e168Saliguori .init = integratorcp_init, 576b5ff1b31Sbellard }; 577a7086888SPaul Brook 578f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void) 579f80f9ec9SAnthony Liguori { 580f80f9ec9SAnthony Liguori qemu_register_machine(&integratorcp_machine); 581f80f9ec9SAnthony Liguori } 582f80f9ec9SAnthony Liguori 583f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init); 584f80f9ec9SAnthony Liguori 585999e12bbSAnthony Liguori static Property core_properties[] = { 586257ec289SAndreas Färber DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), 587bb36f66aSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 588999e12bbSAnthony Liguori }; 589999e12bbSAnthony Liguori 590999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data) 591999e12bbSAnthony Liguori { 59239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 593999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 594999e12bbSAnthony Liguori 595999e12bbSAnthony Liguori k->init = integratorcm_init; 59639bffca2SAnthony Liguori dc->props = core_properties; 597ee6847d1SGerd Hoffmann } 598999e12bbSAnthony Liguori 5998c43a6f0SAndreas Färber static const TypeInfo core_info = { 600257ec289SAndreas Färber .name = TYPE_INTEGRATOR_CM, 60139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 602257ec289SAndreas Färber .instance_size = sizeof(IntegratorCMState), 603999e12bbSAnthony Liguori .class_init = core_class_init, 604999e12bbSAnthony Liguori }; 605999e12bbSAnthony Liguori 606999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data) 607999e12bbSAnthony Liguori { 608999e12bbSAnthony Liguori SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); 609999e12bbSAnthony Liguori 610999e12bbSAnthony Liguori sdc->init = icp_pic_init; 611999e12bbSAnthony Liguori } 612999e12bbSAnthony Liguori 6138c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = { 61491b64626SAndreas Färber .name = TYPE_INTEGRATOR_PIC, 61539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 61639bffca2SAnthony Liguori .instance_size = sizeof(icp_pic_state), 617999e12bbSAnthony Liguori .class_init = icp_pic_class_init, 618ee6847d1SGerd Hoffmann }; 619ee6847d1SGerd Hoffmann 620*ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = { 621*ffc8542aSJan Kiszka .name = TYPE_ICP_CONTROL_REGS, 622*ffc8542aSJan Kiszka .parent = TYPE_SYS_BUS_DEVICE, 623*ffc8542aSJan Kiszka .instance_size = sizeof(ICPCtrlRegsState), 624*ffc8542aSJan Kiszka .instance_init = icp_control_init, 625*ffc8542aSJan Kiszka }; 626*ffc8542aSJan Kiszka 62783f7d43aSAndreas Färber static void integratorcp_register_types(void) 628a7086888SPaul Brook { 62939bffca2SAnthony Liguori type_register_static(&icp_pic_info); 63039bffca2SAnthony Liguori type_register_static(&core_info); 631*ffc8542aSJan Kiszka type_register_static(&icp_ctrl_regs_info); 632a7086888SPaul Brook } 633a7086888SPaul Brook 63483f7d43aSAndreas Färber type_init(integratorcp_register_types) 635