1 /* 2 * Raspberry Pi emulation (c) 2012 Gregory Estrade 3 * This code is licensed under the GNU GPLv2 and later. 4 * 5 * This file models the system mailboxes, which are used for 6 * communication with low-bandwidth GPU peripherals. Refs: 7 * https://github.com/raspberrypi/firmware/wiki/Mailboxes 8 * https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes 9 */ 10 11 #include "qemu/osdep.h" 12 #include "qapi/error.h" 13 #include "hw/irq.h" 14 #include "hw/misc/bcm2835_mbox.h" 15 #include "qemu/log.h" 16 #include "qemu/module.h" 17 18 #define MAIL0_PEEK 0x90 19 #define MAIL0_SENDER 0x94 20 #define MAIL1_STATUS 0xb8 21 22 /* Mailbox status register */ 23 #define MAIL0_STATUS 0x98 24 #define ARM_MS_FULL 0x80000000 25 #define ARM_MS_EMPTY 0x40000000 26 #define ARM_MS_LEVEL 0x400000FF /* Max. value depends on mailbox depth */ 27 28 /* MAILBOX config/status register */ 29 #define MAIL0_CONFIG 0x9c 30 /* ANY write to this register clears the error bits! */ 31 #define ARM_MC_IHAVEDATAIRQEN 0x00000001 /* mbox irq enable: has data */ 32 #define ARM_MC_IHAVESPACEIRQEN 0x00000002 /* mbox irq enable: has space */ 33 #define ARM_MC_OPPISEMPTYIRQEN 0x00000004 /* mbox irq enable: Opp is empty */ 34 #define ARM_MC_MAIL_CLEAR 0x00000008 /* mbox clear write 1, then 0 */ 35 #define ARM_MC_IHAVEDATAIRQPEND 0x00000010 /* mbox irq pending: has space */ 36 #define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mbox irq pending: Opp is empty */ 37 #define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mbox irq pending */ 38 /* Bit 7 is unused */ 39 #define ARM_MC_ERRNOOWN 0x00000100 /* error : none owner read from mailbox */ 40 #define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */ 41 #define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */ 42 43 static void mbox_update_status(BCM2835Mbox *mb) 44 { 45 mb->status &= ~(ARM_MS_EMPTY | ARM_MS_FULL); 46 if (mb->count == 0) { 47 mb->status |= ARM_MS_EMPTY; 48 } else if (mb->count == MBOX_SIZE) { 49 mb->status |= ARM_MS_FULL; 50 } 51 } 52 53 static void mbox_reset(BCM2835Mbox *mb) 54 { 55 int n; 56 57 mb->count = 0; 58 mb->config = 0; 59 for (n = 0; n < MBOX_SIZE; n++) { 60 mb->reg[n] = MBOX_INVALID_DATA; 61 } 62 mbox_update_status(mb); 63 } 64 65 static uint32_t mbox_pull(BCM2835Mbox *mb, int index) 66 { 67 int n; 68 uint32_t val; 69 70 assert(mb->count > 0); 71 assert(index < mb->count); 72 73 val = mb->reg[index]; 74 for (n = index + 1; n < mb->count; n++) { 75 mb->reg[n - 1] = mb->reg[n]; 76 } 77 mb->count--; 78 mb->reg[mb->count] = MBOX_INVALID_DATA; 79 80 mbox_update_status(mb); 81 82 return val; 83 } 84 85 static void mbox_push(BCM2835Mbox *mb, uint32_t val) 86 { 87 assert(mb->count < MBOX_SIZE); 88 mb->reg[mb->count++] = val; 89 mbox_update_status(mb); 90 } 91 92 static void bcm2835_mbox_update(BCM2835MboxState *s) 93 { 94 uint32_t value; 95 bool set; 96 int n; 97 98 s->mbox_irq_disabled = true; 99 100 /* Get pending responses and put them in the vc->arm mbox, 101 * as long as it's not full 102 */ 103 for (n = 0; n < MBOX_CHAN_COUNT; n++) { 104 while (s->available[n] && !(s->mbox[0].status & ARM_MS_FULL)) { 105 value = ldl_le_phys(&s->mbox_as, n << MBOX_AS_CHAN_SHIFT); 106 assert(value != MBOX_INVALID_DATA); /* Pending interrupt but no data */ 107 mbox_push(&s->mbox[0], value); 108 } 109 } 110 111 /* TODO (?): Try to push pending requests from the arm->vc mbox */ 112 113 /* Re-enable calls from the IRQ routine */ 114 s->mbox_irq_disabled = false; 115 116 /* Update ARM IRQ status */ 117 set = false; 118 s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQPEND; 119 if (!(s->mbox[0].status & ARM_MS_EMPTY)) { 120 s->mbox[0].config |= ARM_MC_IHAVEDATAIRQPEND; 121 if (s->mbox[0].config & ARM_MC_IHAVEDATAIRQEN) { 122 set = true; 123 } 124 } 125 qemu_set_irq(s->arm_irq, set); 126 } 127 128 static void bcm2835_mbox_set_irq(void *opaque, int irq, int level) 129 { 130 BCM2835MboxState *s = opaque; 131 132 s->available[irq] = level; 133 134 /* avoid recursively calling bcm2835_mbox_update when the interrupt 135 * status changes due to the ldl_phys call within that function 136 */ 137 if (!s->mbox_irq_disabled) { 138 bcm2835_mbox_update(s); 139 } 140 } 141 142 static uint64_t bcm2835_mbox_read(void *opaque, hwaddr offset, unsigned size) 143 { 144 BCM2835MboxState *s = opaque; 145 uint32_t res = 0; 146 147 offset &= 0xff; 148 149 switch (offset) { 150 case 0x80 ... 0x8c: /* MAIL0_READ */ 151 if (s->mbox[0].status & ARM_MS_EMPTY) { 152 res = MBOX_INVALID_DATA; 153 } else { 154 res = mbox_pull(&s->mbox[0], 0); 155 } 156 break; 157 158 case MAIL0_PEEK: 159 res = s->mbox[0].reg[0]; 160 break; 161 162 case MAIL0_SENDER: 163 break; 164 165 case MAIL0_STATUS: 166 res = s->mbox[0].status; 167 break; 168 169 case MAIL0_CONFIG: 170 res = s->mbox[0].config; 171 break; 172 173 case MAIL1_STATUS: 174 res = s->mbox[1].status; 175 break; 176 177 default: 178 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 179 __func__, offset); 180 return 0; 181 } 182 183 bcm2835_mbox_update(s); 184 185 return res; 186 } 187 188 static void bcm2835_mbox_write(void *opaque, hwaddr offset, 189 uint64_t value, unsigned size) 190 { 191 BCM2835MboxState *s = opaque; 192 hwaddr childaddr; 193 uint8_t ch; 194 195 offset &= 0xff; 196 197 switch (offset) { 198 case MAIL0_SENDER: 199 break; 200 201 case MAIL0_CONFIG: 202 s->mbox[0].config &= ~ARM_MC_IHAVEDATAIRQEN; 203 s->mbox[0].config |= value & ARM_MC_IHAVEDATAIRQEN; 204 break; 205 206 case 0xa0 ... 0xac: /* MAIL1_WRITE */ 207 if (s->mbox[1].status & ARM_MS_FULL) { 208 /* Mailbox full */ 209 qemu_log_mask(LOG_GUEST_ERROR, "%s: mailbox full\n", __func__); 210 } else { 211 ch = value & 0xf; 212 if (ch < MBOX_CHAN_COUNT) { 213 childaddr = ch << MBOX_AS_CHAN_SHIFT; 214 if (ldl_le_phys(&s->mbox_as, childaddr + MBOX_AS_PENDING)) { 215 /* Child busy, push delayed. Push it in the arm->vc mbox */ 216 mbox_push(&s->mbox[1], value); 217 } else { 218 /* Push it directly to the child device */ 219 stl_le_phys(&s->mbox_as, childaddr, value); 220 } 221 } else { 222 /* Invalid channel number */ 223 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid channel %u\n", 224 __func__, ch); 225 } 226 } 227 break; 228 229 default: 230 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 231 __func__, offset); 232 return; 233 } 234 235 bcm2835_mbox_update(s); 236 } 237 238 static const MemoryRegionOps bcm2835_mbox_ops = { 239 .read = bcm2835_mbox_read, 240 .write = bcm2835_mbox_write, 241 .endianness = DEVICE_NATIVE_ENDIAN, 242 .valid.min_access_size = 4, 243 .valid.max_access_size = 4, 244 }; 245 246 /* vmstate of a single mailbox */ 247 static const VMStateDescription vmstate_bcm2835_mbox_box = { 248 .name = TYPE_BCM2835_MBOX "_box", 249 .version_id = 1, 250 .minimum_version_id = 1, 251 .fields = (VMStateField[]) { 252 VMSTATE_UINT32_ARRAY(reg, BCM2835Mbox, MBOX_SIZE), 253 VMSTATE_UINT32(count, BCM2835Mbox), 254 VMSTATE_UINT32(status, BCM2835Mbox), 255 VMSTATE_UINT32(config, BCM2835Mbox), 256 VMSTATE_END_OF_LIST() 257 } 258 }; 259 260 /* vmstate of the entire device */ 261 static const VMStateDescription vmstate_bcm2835_mbox = { 262 .name = TYPE_BCM2835_MBOX, 263 .version_id = 1, 264 .minimum_version_id = 1, 265 .minimum_version_id_old = 1, 266 .fields = (VMStateField[]) { 267 VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT), 268 VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1, 269 vmstate_bcm2835_mbox_box, BCM2835Mbox), 270 VMSTATE_END_OF_LIST() 271 } 272 }; 273 274 static void bcm2835_mbox_init(Object *obj) 275 { 276 BCM2835MboxState *s = BCM2835_MBOX(obj); 277 278 memory_region_init_io(&s->iomem, obj, &bcm2835_mbox_ops, s, 279 TYPE_BCM2835_MBOX, 0x400); 280 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 281 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->arm_irq); 282 qdev_init_gpio_in(DEVICE(s), bcm2835_mbox_set_irq, MBOX_CHAN_COUNT); 283 } 284 285 static void bcm2835_mbox_reset(DeviceState *dev) 286 { 287 BCM2835MboxState *s = BCM2835_MBOX(dev); 288 int n; 289 290 mbox_reset(&s->mbox[0]); 291 mbox_reset(&s->mbox[1]); 292 s->mbox_irq_disabled = false; 293 for (n = 0; n < MBOX_CHAN_COUNT; n++) { 294 s->available[n] = false; 295 } 296 } 297 298 static void bcm2835_mbox_realize(DeviceState *dev, Error **errp) 299 { 300 BCM2835MboxState *s = BCM2835_MBOX(dev); 301 Object *obj; 302 Error *err = NULL; 303 304 obj = object_property_get_link(OBJECT(dev), "mbox-mr", &err); 305 if (obj == NULL) { 306 error_setg(errp, "%s: required mbox-mr link not found: %s", 307 __func__, error_get_pretty(err)); 308 return; 309 } 310 311 s->mbox_mr = MEMORY_REGION(obj); 312 address_space_init(&s->mbox_as, s->mbox_mr, NULL); 313 bcm2835_mbox_reset(dev); 314 } 315 316 static void bcm2835_mbox_class_init(ObjectClass *klass, void *data) 317 { 318 DeviceClass *dc = DEVICE_CLASS(klass); 319 320 dc->realize = bcm2835_mbox_realize; 321 dc->reset = bcm2835_mbox_reset; 322 dc->vmsd = &vmstate_bcm2835_mbox; 323 } 324 325 static TypeInfo bcm2835_mbox_info = { 326 .name = TYPE_BCM2835_MBOX, 327 .parent = TYPE_SYS_BUS_DEVICE, 328 .instance_size = sizeof(BCM2835MboxState), 329 .class_init = bcm2835_mbox_class_init, 330 .instance_init = bcm2835_mbox_init, 331 }; 332 333 static void bcm2835_mbox_register_types(void) 334 { 335 type_register_static(&bcm2835_mbox_info); 336 } 337 338 type_init(bcm2835_mbox_register_types) 339