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