1cdf63440SPeter Maydell /* 2cdf63440SPeter Maydell * ARM SSE-200 Message Handling Unit (MHU) 3cdf63440SPeter Maydell * 4cdf63440SPeter Maydell * Copyright (c) 2019 Linaro Limited 5cdf63440SPeter Maydell * Written by Peter Maydell 6cdf63440SPeter Maydell * 7cdf63440SPeter Maydell * This program is free software; you can redistribute it and/or modify 8cdf63440SPeter Maydell * it under the terms of the GNU General Public License version 2 or 9cdf63440SPeter Maydell * (at your option) any later version. 10cdf63440SPeter Maydell */ 11cdf63440SPeter Maydell 12cdf63440SPeter Maydell /* 13cdf63440SPeter Maydell * This is a model of the Message Handling Unit (MHU) which is part of the 14cdf63440SPeter Maydell * Arm SSE-200 and documented in 15cdf63440SPeter Maydell * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf 16cdf63440SPeter Maydell */ 17cdf63440SPeter Maydell 18cdf63440SPeter Maydell #include "qemu/osdep.h" 19cdf63440SPeter Maydell #include "qemu/log.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 21cdf63440SPeter Maydell #include "trace.h" 22cdf63440SPeter Maydell #include "qapi/error.h" 23cdf63440SPeter Maydell #include "sysemu/sysemu.h" 24cdf63440SPeter Maydell #include "hw/sysbus.h" 25*d6454270SMarkus Armbruster #include "migration/vmstate.h" 26cdf63440SPeter Maydell #include "hw/registerfields.h" 2764552b6bSMarkus Armbruster #include "hw/irq.h" 28cdf63440SPeter Maydell #include "hw/misc/armsse-mhu.h" 29cdf63440SPeter Maydell 30cdf63440SPeter Maydell REG32(CPU0INTR_STAT, 0x0) 31cdf63440SPeter Maydell REG32(CPU0INTR_SET, 0x4) 32cdf63440SPeter Maydell REG32(CPU0INTR_CLR, 0x8) 33cdf63440SPeter Maydell REG32(CPU1INTR_STAT, 0x10) 34cdf63440SPeter Maydell REG32(CPU1INTR_SET, 0x14) 35cdf63440SPeter Maydell REG32(CPU1INTR_CLR, 0x18) 36cdf63440SPeter Maydell REG32(PID4, 0xfd0) 37cdf63440SPeter Maydell REG32(PID5, 0xfd4) 38cdf63440SPeter Maydell REG32(PID6, 0xfd8) 39cdf63440SPeter Maydell REG32(PID7, 0xfdc) 40cdf63440SPeter Maydell REG32(PID0, 0xfe0) 41cdf63440SPeter Maydell REG32(PID1, 0xfe4) 42cdf63440SPeter Maydell REG32(PID2, 0xfe8) 43cdf63440SPeter Maydell REG32(PID3, 0xfec) 44cdf63440SPeter Maydell REG32(CID0, 0xff0) 45cdf63440SPeter Maydell REG32(CID1, 0xff4) 46cdf63440SPeter Maydell REG32(CID2, 0xff8) 47cdf63440SPeter Maydell REG32(CID3, 0xffc) 48cdf63440SPeter Maydell 49cdf63440SPeter Maydell /* Valid bits in the interrupt registers. If any are set the IRQ is raised */ 50cdf63440SPeter Maydell #define INTR_MASK 0xf 51cdf63440SPeter Maydell 52cdf63440SPeter Maydell /* PID/CID values */ 53cdf63440SPeter Maydell static const int armsse_mhu_id[] = { 54cdf63440SPeter Maydell 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ 55cdf63440SPeter Maydell 0x56, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ 56cdf63440SPeter Maydell 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ 57cdf63440SPeter Maydell }; 58cdf63440SPeter Maydell 59cdf63440SPeter Maydell static void armsse_mhu_update(ARMSSEMHU *s) 60cdf63440SPeter Maydell { 61cdf63440SPeter Maydell qemu_set_irq(s->cpu0irq, s->cpu0intr != 0); 62cdf63440SPeter Maydell qemu_set_irq(s->cpu1irq, s->cpu1intr != 0); 63cdf63440SPeter Maydell } 64cdf63440SPeter Maydell 65cdf63440SPeter Maydell static uint64_t armsse_mhu_read(void *opaque, hwaddr offset, unsigned size) 66cdf63440SPeter Maydell { 67cdf63440SPeter Maydell ARMSSEMHU *s = ARMSSE_MHU(opaque); 68cdf63440SPeter Maydell uint64_t r; 69cdf63440SPeter Maydell 70cdf63440SPeter Maydell switch (offset) { 71cdf63440SPeter Maydell case A_CPU0INTR_STAT: 72cdf63440SPeter Maydell r = s->cpu0intr; 73cdf63440SPeter Maydell break; 74cdf63440SPeter Maydell 75cdf63440SPeter Maydell case A_CPU1INTR_STAT: 76cdf63440SPeter Maydell r = s->cpu1intr; 77cdf63440SPeter Maydell break; 78cdf63440SPeter Maydell 79cdf63440SPeter Maydell case A_PID4 ... A_CID3: 80cdf63440SPeter Maydell r = armsse_mhu_id[(offset - A_PID4) / 4]; 81cdf63440SPeter Maydell break; 82cdf63440SPeter Maydell 83cdf63440SPeter Maydell case A_CPU0INTR_SET: 84cdf63440SPeter Maydell case A_CPU0INTR_CLR: 85cdf63440SPeter Maydell case A_CPU1INTR_SET: 86cdf63440SPeter Maydell case A_CPU1INTR_CLR: 87cdf63440SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 88cdf63440SPeter Maydell "SSE MHU: read of write-only register at offset 0x%x\n", 89cdf63440SPeter Maydell (int)offset); 90cdf63440SPeter Maydell r = 0; 91cdf63440SPeter Maydell break; 92cdf63440SPeter Maydell 93cdf63440SPeter Maydell default: 94cdf63440SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 95cdf63440SPeter Maydell "SSE MHU read: bad offset 0x%x\n", (int)offset); 96cdf63440SPeter Maydell r = 0; 97cdf63440SPeter Maydell break; 98cdf63440SPeter Maydell } 99cdf63440SPeter Maydell trace_armsse_mhu_read(offset, r, size); 100cdf63440SPeter Maydell return r; 101cdf63440SPeter Maydell } 102cdf63440SPeter Maydell 103cdf63440SPeter Maydell static void armsse_mhu_write(void *opaque, hwaddr offset, 104cdf63440SPeter Maydell uint64_t value, unsigned size) 105cdf63440SPeter Maydell { 106cdf63440SPeter Maydell ARMSSEMHU *s = ARMSSE_MHU(opaque); 107cdf63440SPeter Maydell 108cdf63440SPeter Maydell trace_armsse_mhu_write(offset, value, size); 109cdf63440SPeter Maydell 110cdf63440SPeter Maydell switch (offset) { 111cdf63440SPeter Maydell case A_CPU0INTR_SET: 112cdf63440SPeter Maydell s->cpu0intr |= (value & INTR_MASK); 113cdf63440SPeter Maydell break; 114cdf63440SPeter Maydell case A_CPU0INTR_CLR: 115cdf63440SPeter Maydell s->cpu0intr &= ~(value & INTR_MASK); 116cdf63440SPeter Maydell break; 117cdf63440SPeter Maydell case A_CPU1INTR_SET: 118cdf63440SPeter Maydell s->cpu1intr |= (value & INTR_MASK); 119cdf63440SPeter Maydell break; 120cdf63440SPeter Maydell case A_CPU1INTR_CLR: 121cdf63440SPeter Maydell s->cpu1intr &= ~(value & INTR_MASK); 122cdf63440SPeter Maydell break; 123cdf63440SPeter Maydell 124cdf63440SPeter Maydell case A_CPU0INTR_STAT: 125cdf63440SPeter Maydell case A_CPU1INTR_STAT: 126cdf63440SPeter Maydell case A_PID4 ... A_CID3: 127cdf63440SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 128cdf63440SPeter Maydell "SSE MHU: write to read-only register at offset 0x%x\n", 129cdf63440SPeter Maydell (int)offset); 130cdf63440SPeter Maydell break; 131cdf63440SPeter Maydell 132cdf63440SPeter Maydell default: 133cdf63440SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 134cdf63440SPeter Maydell "SSE MHU write: bad offset 0x%x\n", (int)offset); 135cdf63440SPeter Maydell break; 136cdf63440SPeter Maydell } 137cdf63440SPeter Maydell 138cdf63440SPeter Maydell armsse_mhu_update(s); 139cdf63440SPeter Maydell } 140cdf63440SPeter Maydell 141cdf63440SPeter Maydell static const MemoryRegionOps armsse_mhu_ops = { 142cdf63440SPeter Maydell .read = armsse_mhu_read, 143cdf63440SPeter Maydell .write = armsse_mhu_write, 144cdf63440SPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 145cdf63440SPeter Maydell .valid.min_access_size = 4, 146cdf63440SPeter Maydell .valid.max_access_size = 4, 147cdf63440SPeter Maydell }; 148cdf63440SPeter Maydell 149cdf63440SPeter Maydell static void armsse_mhu_reset(DeviceState *dev) 150cdf63440SPeter Maydell { 151cdf63440SPeter Maydell ARMSSEMHU *s = ARMSSE_MHU(dev); 152cdf63440SPeter Maydell 153cdf63440SPeter Maydell s->cpu0intr = 0; 154cdf63440SPeter Maydell s->cpu1intr = 0; 155cdf63440SPeter Maydell } 156cdf63440SPeter Maydell 157cdf63440SPeter Maydell static const VMStateDescription armsse_mhu_vmstate = { 158cdf63440SPeter Maydell .name = "armsse-mhu", 159cdf63440SPeter Maydell .version_id = 1, 160cdf63440SPeter Maydell .minimum_version_id = 1, 161cdf63440SPeter Maydell .fields = (VMStateField[]) { 162cdf63440SPeter Maydell VMSTATE_UINT32(cpu0intr, ARMSSEMHU), 163cdf63440SPeter Maydell VMSTATE_UINT32(cpu1intr, ARMSSEMHU), 164cdf63440SPeter Maydell VMSTATE_END_OF_LIST() 165cdf63440SPeter Maydell }, 166cdf63440SPeter Maydell }; 167cdf63440SPeter Maydell 168cdf63440SPeter Maydell static void armsse_mhu_init(Object *obj) 169cdf63440SPeter Maydell { 170cdf63440SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 171cdf63440SPeter Maydell ARMSSEMHU *s = ARMSSE_MHU(obj); 172cdf63440SPeter Maydell 173cdf63440SPeter Maydell memory_region_init_io(&s->iomem, obj, &armsse_mhu_ops, 174cdf63440SPeter Maydell s, "armsse-mhu", 0x1000); 175cdf63440SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 176cdf63440SPeter Maydell sysbus_init_irq(sbd, &s->cpu0irq); 177cdf63440SPeter Maydell sysbus_init_irq(sbd, &s->cpu1irq); 178cdf63440SPeter Maydell } 179cdf63440SPeter Maydell 180cdf63440SPeter Maydell static void armsse_mhu_class_init(ObjectClass *klass, void *data) 181cdf63440SPeter Maydell { 182cdf63440SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 183cdf63440SPeter Maydell 184cdf63440SPeter Maydell dc->reset = armsse_mhu_reset; 185cdf63440SPeter Maydell dc->vmsd = &armsse_mhu_vmstate; 186cdf63440SPeter Maydell } 187cdf63440SPeter Maydell 188cdf63440SPeter Maydell static const TypeInfo armsse_mhu_info = { 189cdf63440SPeter Maydell .name = TYPE_ARMSSE_MHU, 190cdf63440SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 191cdf63440SPeter Maydell .instance_size = sizeof(ARMSSEMHU), 192cdf63440SPeter Maydell .instance_init = armsse_mhu_init, 193cdf63440SPeter Maydell .class_init = armsse_mhu_class_init, 194cdf63440SPeter Maydell }; 195cdf63440SPeter Maydell 196cdf63440SPeter Maydell static void armsse_mhu_register_types(void) 197cdf63440SPeter Maydell { 198cdf63440SPeter Maydell type_register_static(&armsse_mhu_info); 199cdf63440SPeter Maydell } 200cdf63440SPeter Maydell 201cdf63440SPeter Maydell type_init(armsse_mhu_register_types); 202