1*04f1ab15SAndrew Baumann /* 2*04f1ab15SAndrew Baumann * Raspberry Pi emulation (c) 2012 Gregory Estrade 3*04f1ab15SAndrew Baumann * This code is licensed under the GNU GPLv2 and later. 4*04f1ab15SAndrew Baumann */ 5*04f1ab15SAndrew Baumann 6*04f1ab15SAndrew Baumann #include "hw/misc/bcm2835_property.h" 7*04f1ab15SAndrew Baumann #include "hw/misc/bcm2835_mbox_defs.h" 8*04f1ab15SAndrew Baumann #include "sysemu/dma.h" 9*04f1ab15SAndrew Baumann 10*04f1ab15SAndrew Baumann /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ 11*04f1ab15SAndrew Baumann 12*04f1ab15SAndrew Baumann static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) 13*04f1ab15SAndrew Baumann { 14*04f1ab15SAndrew Baumann uint32_t tag; 15*04f1ab15SAndrew Baumann uint32_t bufsize; 16*04f1ab15SAndrew Baumann uint32_t tot_len; 17*04f1ab15SAndrew Baumann size_t resplen; 18*04f1ab15SAndrew Baumann uint32_t tmp; 19*04f1ab15SAndrew Baumann 20*04f1ab15SAndrew Baumann value &= ~0xf; 21*04f1ab15SAndrew Baumann 22*04f1ab15SAndrew Baumann s->addr = value; 23*04f1ab15SAndrew Baumann 24*04f1ab15SAndrew Baumann tot_len = ldl_phys(&s->dma_as, value); 25*04f1ab15SAndrew Baumann 26*04f1ab15SAndrew Baumann /* @(addr + 4) : Buffer response code */ 27*04f1ab15SAndrew Baumann value = s->addr + 8; 28*04f1ab15SAndrew Baumann while (value + 8 <= s->addr + tot_len) { 29*04f1ab15SAndrew Baumann tag = ldl_phys(&s->dma_as, value); 30*04f1ab15SAndrew Baumann bufsize = ldl_phys(&s->dma_as, value + 4); 31*04f1ab15SAndrew Baumann /* @(value + 8) : Request/response indicator */ 32*04f1ab15SAndrew Baumann resplen = 0; 33*04f1ab15SAndrew Baumann switch (tag) { 34*04f1ab15SAndrew Baumann case 0x00000000: /* End tag */ 35*04f1ab15SAndrew Baumann break; 36*04f1ab15SAndrew Baumann case 0x00000001: /* Get firmware revision */ 37*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 12, 346337); 38*04f1ab15SAndrew Baumann resplen = 4; 39*04f1ab15SAndrew Baumann break; 40*04f1ab15SAndrew Baumann case 0x00010001: /* Get board model */ 41*04f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 42*04f1ab15SAndrew Baumann "bcm2835_property: %x get board model NYI\n", tag); 43*04f1ab15SAndrew Baumann resplen = 4; 44*04f1ab15SAndrew Baumann break; 45*04f1ab15SAndrew Baumann case 0x00010002: /* Get board revision */ 46*04f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 47*04f1ab15SAndrew Baumann "bcm2835_property: %x get board revision NYI\n", tag); 48*04f1ab15SAndrew Baumann resplen = 4; 49*04f1ab15SAndrew Baumann break; 50*04f1ab15SAndrew Baumann case 0x00010003: /* Get board MAC address */ 51*04f1ab15SAndrew Baumann resplen = sizeof(s->macaddr.a); 52*04f1ab15SAndrew Baumann dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen); 53*04f1ab15SAndrew Baumann break; 54*04f1ab15SAndrew Baumann case 0x00010004: /* Get board serial */ 55*04f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 56*04f1ab15SAndrew Baumann "bcm2835_property: %x get board serial NYI\n", tag); 57*04f1ab15SAndrew Baumann resplen = 8; 58*04f1ab15SAndrew Baumann break; 59*04f1ab15SAndrew Baumann case 0x00010005: /* Get ARM memory */ 60*04f1ab15SAndrew Baumann /* base */ 61*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 12, 0); 62*04f1ab15SAndrew Baumann /* size */ 63*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, s->ram_size); 64*04f1ab15SAndrew Baumann resplen = 8; 65*04f1ab15SAndrew Baumann break; 66*04f1ab15SAndrew Baumann case 0x00028001: /* Set power state */ 67*04f1ab15SAndrew Baumann /* Assume that whatever device they asked for exists, 68*04f1ab15SAndrew Baumann * and we'll just claim we set it to the desired state 69*04f1ab15SAndrew Baumann */ 70*04f1ab15SAndrew Baumann tmp = ldl_phys(&s->dma_as, value + 16); 71*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, (tmp & 1)); 72*04f1ab15SAndrew Baumann resplen = 8; 73*04f1ab15SAndrew Baumann break; 74*04f1ab15SAndrew Baumann 75*04f1ab15SAndrew Baumann /* Clocks */ 76*04f1ab15SAndrew Baumann 77*04f1ab15SAndrew Baumann case 0x00030001: /* Get clock state */ 78*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 0x1); 79*04f1ab15SAndrew Baumann resplen = 8; 80*04f1ab15SAndrew Baumann break; 81*04f1ab15SAndrew Baumann 82*04f1ab15SAndrew Baumann case 0x00038001: /* Set clock state */ 83*04f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 84*04f1ab15SAndrew Baumann "bcm2835_property: %x set clock state NYI\n", tag); 85*04f1ab15SAndrew Baumann resplen = 8; 86*04f1ab15SAndrew Baumann break; 87*04f1ab15SAndrew Baumann 88*04f1ab15SAndrew Baumann case 0x00030002: /* Get clock rate */ 89*04f1ab15SAndrew Baumann case 0x00030004: /* Get max clock rate */ 90*04f1ab15SAndrew Baumann case 0x00030007: /* Get min clock rate */ 91*04f1ab15SAndrew Baumann switch (ldl_phys(&s->dma_as, value + 12)) { 92*04f1ab15SAndrew Baumann case 1: /* EMMC */ 93*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 50000000); 94*04f1ab15SAndrew Baumann break; 95*04f1ab15SAndrew Baumann case 2: /* UART */ 96*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 3000000); 97*04f1ab15SAndrew Baumann break; 98*04f1ab15SAndrew Baumann default: 99*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 700000000); 100*04f1ab15SAndrew Baumann break; 101*04f1ab15SAndrew Baumann } 102*04f1ab15SAndrew Baumann resplen = 8; 103*04f1ab15SAndrew Baumann break; 104*04f1ab15SAndrew Baumann 105*04f1ab15SAndrew Baumann case 0x00038002: /* Set clock rate */ 106*04f1ab15SAndrew Baumann case 0x00038004: /* Set max clock rate */ 107*04f1ab15SAndrew Baumann case 0x00038007: /* Set min clock rate */ 108*04f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 109*04f1ab15SAndrew Baumann "bcm2835_property: %x set clock rates NYI\n", tag); 110*04f1ab15SAndrew Baumann resplen = 8; 111*04f1ab15SAndrew Baumann break; 112*04f1ab15SAndrew Baumann 113*04f1ab15SAndrew Baumann /* Temperature */ 114*04f1ab15SAndrew Baumann 115*04f1ab15SAndrew Baumann case 0x00030006: /* Get temperature */ 116*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 25000); 117*04f1ab15SAndrew Baumann resplen = 8; 118*04f1ab15SAndrew Baumann break; 119*04f1ab15SAndrew Baumann 120*04f1ab15SAndrew Baumann case 0x0003000A: /* Get max temperature */ 121*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 16, 99000); 122*04f1ab15SAndrew Baumann resplen = 8; 123*04f1ab15SAndrew Baumann break; 124*04f1ab15SAndrew Baumann 125*04f1ab15SAndrew Baumann 126*04f1ab15SAndrew Baumann case 0x00060001: /* Get DMA channels */ 127*04f1ab15SAndrew Baumann /* channels 2-5 */ 128*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 12, 0x003C); 129*04f1ab15SAndrew Baumann resplen = 4; 130*04f1ab15SAndrew Baumann break; 131*04f1ab15SAndrew Baumann 132*04f1ab15SAndrew Baumann case 0x00050001: /* Get command line */ 133*04f1ab15SAndrew Baumann resplen = 0; 134*04f1ab15SAndrew Baumann break; 135*04f1ab15SAndrew Baumann 136*04f1ab15SAndrew Baumann default: 137*04f1ab15SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, 138*04f1ab15SAndrew Baumann "bcm2835_property: unhandled tag %08x\n", tag); 139*04f1ab15SAndrew Baumann break; 140*04f1ab15SAndrew Baumann } 141*04f1ab15SAndrew Baumann 142*04f1ab15SAndrew Baumann if (tag == 0) { 143*04f1ab15SAndrew Baumann break; 144*04f1ab15SAndrew Baumann } 145*04f1ab15SAndrew Baumann 146*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen); 147*04f1ab15SAndrew Baumann value += bufsize + 12; 148*04f1ab15SAndrew Baumann } 149*04f1ab15SAndrew Baumann 150*04f1ab15SAndrew Baumann /* Buffer response code */ 151*04f1ab15SAndrew Baumann stl_phys(&s->dma_as, s->addr + 4, (1 << 31)); 152*04f1ab15SAndrew Baumann } 153*04f1ab15SAndrew Baumann 154*04f1ab15SAndrew Baumann static uint64_t bcm2835_property_read(void *opaque, hwaddr offset, 155*04f1ab15SAndrew Baumann unsigned size) 156*04f1ab15SAndrew Baumann { 157*04f1ab15SAndrew Baumann BCM2835PropertyState *s = opaque; 158*04f1ab15SAndrew Baumann uint32_t res = 0; 159*04f1ab15SAndrew Baumann 160*04f1ab15SAndrew Baumann switch (offset) { 161*04f1ab15SAndrew Baumann case MBOX_AS_DATA: 162*04f1ab15SAndrew Baumann res = MBOX_CHAN_PROPERTY | s->addr; 163*04f1ab15SAndrew Baumann s->pending = false; 164*04f1ab15SAndrew Baumann qemu_set_irq(s->mbox_irq, 0); 165*04f1ab15SAndrew Baumann break; 166*04f1ab15SAndrew Baumann 167*04f1ab15SAndrew Baumann case MBOX_AS_PENDING: 168*04f1ab15SAndrew Baumann res = s->pending; 169*04f1ab15SAndrew Baumann break; 170*04f1ab15SAndrew Baumann 171*04f1ab15SAndrew Baumann default: 172*04f1ab15SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 173*04f1ab15SAndrew Baumann __func__, offset); 174*04f1ab15SAndrew Baumann return 0; 175*04f1ab15SAndrew Baumann } 176*04f1ab15SAndrew Baumann 177*04f1ab15SAndrew Baumann return res; 178*04f1ab15SAndrew Baumann } 179*04f1ab15SAndrew Baumann 180*04f1ab15SAndrew Baumann static void bcm2835_property_write(void *opaque, hwaddr offset, 181*04f1ab15SAndrew Baumann uint64_t value, unsigned size) 182*04f1ab15SAndrew Baumann { 183*04f1ab15SAndrew Baumann BCM2835PropertyState *s = opaque; 184*04f1ab15SAndrew Baumann 185*04f1ab15SAndrew Baumann switch (offset) { 186*04f1ab15SAndrew Baumann case MBOX_AS_DATA: 187*04f1ab15SAndrew Baumann /* bcm2835_mbox should check our pending status before pushing */ 188*04f1ab15SAndrew Baumann assert(!s->pending); 189*04f1ab15SAndrew Baumann s->pending = true; 190*04f1ab15SAndrew Baumann bcm2835_property_mbox_push(s, value); 191*04f1ab15SAndrew Baumann qemu_set_irq(s->mbox_irq, 1); 192*04f1ab15SAndrew Baumann break; 193*04f1ab15SAndrew Baumann 194*04f1ab15SAndrew Baumann default: 195*04f1ab15SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 196*04f1ab15SAndrew Baumann __func__, offset); 197*04f1ab15SAndrew Baumann return; 198*04f1ab15SAndrew Baumann } 199*04f1ab15SAndrew Baumann } 200*04f1ab15SAndrew Baumann 201*04f1ab15SAndrew Baumann static const MemoryRegionOps bcm2835_property_ops = { 202*04f1ab15SAndrew Baumann .read = bcm2835_property_read, 203*04f1ab15SAndrew Baumann .write = bcm2835_property_write, 204*04f1ab15SAndrew Baumann .endianness = DEVICE_NATIVE_ENDIAN, 205*04f1ab15SAndrew Baumann .valid.min_access_size = 4, 206*04f1ab15SAndrew Baumann .valid.max_access_size = 4, 207*04f1ab15SAndrew Baumann }; 208*04f1ab15SAndrew Baumann 209*04f1ab15SAndrew Baumann static const VMStateDescription vmstate_bcm2835_property = { 210*04f1ab15SAndrew Baumann .name = TYPE_BCM2835_PROPERTY, 211*04f1ab15SAndrew Baumann .version_id = 1, 212*04f1ab15SAndrew Baumann .minimum_version_id = 1, 213*04f1ab15SAndrew Baumann .fields = (VMStateField[]) { 214*04f1ab15SAndrew Baumann VMSTATE_MACADDR(macaddr, BCM2835PropertyState), 215*04f1ab15SAndrew Baumann VMSTATE_UINT32(addr, BCM2835PropertyState), 216*04f1ab15SAndrew Baumann VMSTATE_BOOL(pending, BCM2835PropertyState), 217*04f1ab15SAndrew Baumann VMSTATE_END_OF_LIST() 218*04f1ab15SAndrew Baumann } 219*04f1ab15SAndrew Baumann }; 220*04f1ab15SAndrew Baumann 221*04f1ab15SAndrew Baumann static void bcm2835_property_init(Object *obj) 222*04f1ab15SAndrew Baumann { 223*04f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(obj); 224*04f1ab15SAndrew Baumann 225*04f1ab15SAndrew Baumann memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, 226*04f1ab15SAndrew Baumann TYPE_BCM2835_PROPERTY, 0x10); 227*04f1ab15SAndrew Baumann sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 228*04f1ab15SAndrew Baumann sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); 229*04f1ab15SAndrew Baumann } 230*04f1ab15SAndrew Baumann 231*04f1ab15SAndrew Baumann static void bcm2835_property_reset(DeviceState *dev) 232*04f1ab15SAndrew Baumann { 233*04f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 234*04f1ab15SAndrew Baumann 235*04f1ab15SAndrew Baumann s->pending = false; 236*04f1ab15SAndrew Baumann } 237*04f1ab15SAndrew Baumann 238*04f1ab15SAndrew Baumann static void bcm2835_property_realize(DeviceState *dev, Error **errp) 239*04f1ab15SAndrew Baumann { 240*04f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 241*04f1ab15SAndrew Baumann Object *obj; 242*04f1ab15SAndrew Baumann Error *err = NULL; 243*04f1ab15SAndrew Baumann 244*04f1ab15SAndrew Baumann obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); 245*04f1ab15SAndrew Baumann if (obj == NULL) { 246*04f1ab15SAndrew Baumann error_setg(errp, "%s: required dma-mr link not found: %s", 247*04f1ab15SAndrew Baumann __func__, error_get_pretty(err)); 248*04f1ab15SAndrew Baumann return; 249*04f1ab15SAndrew Baumann } 250*04f1ab15SAndrew Baumann 251*04f1ab15SAndrew Baumann s->dma_mr = MEMORY_REGION(obj); 252*04f1ab15SAndrew Baumann address_space_init(&s->dma_as, s->dma_mr, NULL); 253*04f1ab15SAndrew Baumann 254*04f1ab15SAndrew Baumann /* TODO: connect to MAC address of USB NIC device, once we emulate it */ 255*04f1ab15SAndrew Baumann qemu_macaddr_default_if_unset(&s->macaddr); 256*04f1ab15SAndrew Baumann 257*04f1ab15SAndrew Baumann bcm2835_property_reset(dev); 258*04f1ab15SAndrew Baumann } 259*04f1ab15SAndrew Baumann 260*04f1ab15SAndrew Baumann static Property bcm2835_property_props[] = { 261*04f1ab15SAndrew Baumann DEFINE_PROP_UINT32("ram-size", BCM2835PropertyState, ram_size, 0), 262*04f1ab15SAndrew Baumann DEFINE_PROP_END_OF_LIST() 263*04f1ab15SAndrew Baumann }; 264*04f1ab15SAndrew Baumann 265*04f1ab15SAndrew Baumann static void bcm2835_property_class_init(ObjectClass *klass, void *data) 266*04f1ab15SAndrew Baumann { 267*04f1ab15SAndrew Baumann DeviceClass *dc = DEVICE_CLASS(klass); 268*04f1ab15SAndrew Baumann 269*04f1ab15SAndrew Baumann dc->props = bcm2835_property_props; 270*04f1ab15SAndrew Baumann dc->realize = bcm2835_property_realize; 271*04f1ab15SAndrew Baumann dc->vmsd = &vmstate_bcm2835_property; 272*04f1ab15SAndrew Baumann } 273*04f1ab15SAndrew Baumann 274*04f1ab15SAndrew Baumann static TypeInfo bcm2835_property_info = { 275*04f1ab15SAndrew Baumann .name = TYPE_BCM2835_PROPERTY, 276*04f1ab15SAndrew Baumann .parent = TYPE_SYS_BUS_DEVICE, 277*04f1ab15SAndrew Baumann .instance_size = sizeof(BCM2835PropertyState), 278*04f1ab15SAndrew Baumann .class_init = bcm2835_property_class_init, 279*04f1ab15SAndrew Baumann .instance_init = bcm2835_property_init, 280*04f1ab15SAndrew Baumann }; 281*04f1ab15SAndrew Baumann 282*04f1ab15SAndrew Baumann static void bcm2835_property_register_types(void) 283*04f1ab15SAndrew Baumann { 284*04f1ab15SAndrew Baumann type_register_static(&bcm2835_property_info); 285*04f1ab15SAndrew Baumann } 286*04f1ab15SAndrew Baumann 287*04f1ab15SAndrew Baumann type_init(bcm2835_property_register_types) 288