Skip to content

Commit c7a2f7b

Browse files
mcaylandvivier
authored andcommitted
macfb: add vertical blank interrupt
The MacOS driver expects a 60.15Hz vertical blank interrupt to be generated by the framebuffer which in turn schedules the mouse driver via the Vertical Retrace Manager. Signed-off-by: Mark Cave-Ayland <[email protected]> Reviewed-by: Laurent Vivier <[email protected]> Message-Id: <[email protected]> Signed-off-by: Laurent Vivier <[email protected]>
1 parent 432d59c commit c7a2f7b

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

hw/display/macfb.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,16 @@
3333
#define DAFB_MODE_CTRL1 0x8
3434
#define DAFB_MODE_CTRL2 0xc
3535
#define DAFB_MODE_SENSE 0x1c
36+
#define DAFB_INTR_MASK 0x104
37+
#define DAFB_INTR_STAT 0x108
38+
#define DAFB_INTR_CLEAR 0x10c
3639
#define DAFB_RESET 0x200
3740
#define DAFB_LUT 0x213
3841

42+
#define DAFB_INTR_VBL 0x4
43+
44+
/* Vertical Blank period (60.15Hz) */
45+
#define DAFB_INTR_VBL_PERIOD_NS 16625800
3946

4047
/*
4148
* Quadra sense codes taken from Apple Technical Note HW26:
@@ -470,6 +477,36 @@ static void macfb_update_display(void *opaque)
470477
macfb_draw_graphic(s);
471478
}
472479

480+
static void macfb_update_irq(MacfbState *s)
481+
{
482+
uint32_t irq_state = s->irq_state & s->irq_mask;
483+
484+
if (irq_state) {
485+
qemu_irq_raise(s->irq);
486+
} else {
487+
qemu_irq_lower(s->irq);
488+
}
489+
}
490+
491+
static int64_t macfb_next_vbl(void)
492+
{
493+
return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + DAFB_INTR_VBL_PERIOD_NS) /
494+
DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS;
495+
}
496+
497+
static void macfb_vbl_timer(void *opaque)
498+
{
499+
MacfbState *s = opaque;
500+
int64_t next_vbl;
501+
502+
s->irq_state |= DAFB_INTR_VBL;
503+
macfb_update_irq(s);
504+
505+
/* 60 Hz irq */
506+
next_vbl = macfb_next_vbl();
507+
timer_mod(s->vbl_timer, next_vbl);
508+
}
509+
473510
static void macfb_reset(MacfbState *s)
474511
{
475512
int i;
@@ -498,6 +535,9 @@ static uint64_t macfb_ctrl_read(void *opaque,
498535
case DAFB_MODE_CTRL2:
499536
val = s->regs[addr >> 2];
500537
break;
538+
case DAFB_INTR_STAT:
539+
val = s->irq_state;
540+
break;
501541
case DAFB_MODE_SENSE:
502542
val = macfb_sense_read(s);
503543
break;
@@ -513,6 +553,8 @@ static void macfb_ctrl_write(void *opaque,
513553
unsigned int size)
514554
{
515555
MacfbState *s = opaque;
556+
int64_t next_vbl;
557+
516558
switch (addr) {
517559
case DAFB_MODE_VADDR1:
518560
case DAFB_MODE_VADDR2:
@@ -528,8 +570,23 @@ static void macfb_ctrl_write(void *opaque,
528570
case DAFB_MODE_SENSE:
529571
macfb_sense_write(s, val);
530572
break;
573+
case DAFB_INTR_MASK:
574+
s->irq_mask = val;
575+
if (val & DAFB_INTR_VBL) {
576+
next_vbl = macfb_next_vbl();
577+
timer_mod(s->vbl_timer, next_vbl);
578+
} else {
579+
timer_del(s->vbl_timer);
580+
}
581+
break;
582+
case DAFB_INTR_CLEAR:
583+
s->irq_state &= ~DAFB_INTR_VBL;
584+
macfb_update_irq(s);
585+
break;
531586
case DAFB_RESET:
532587
s->palette_current = 0;
588+
s->irq_state &= ~DAFB_INTR_VBL;
589+
macfb_update_irq(s);
533590
break;
534591
case DAFB_LUT:
535592
s->color_palette[s->palette_current] = val;
@@ -611,6 +668,7 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
611668
s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
612669
memory_region_set_coalescing(&s->mem_vram);
613670

671+
s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s);
614672
macfb_update_mode(s);
615673
return true;
616674
}
@@ -626,6 +684,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
626684

627685
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
628686
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
687+
688+
qdev_init_gpio_out(dev, &ms->irq, 1);
689+
}
690+
691+
static void macfb_nubus_set_irq(void *opaque, int n, int level)
692+
{
693+
MacfbNubusState *s = NUBUS_MACFB(opaque);
694+
NubusDevice *nd = NUBUS_DEVICE(s);
695+
696+
nubus_set_irq(nd, level);
629697
}
630698

631699
static void macfb_nubus_realize(DeviceState *dev, Error **errp)
@@ -646,6 +714,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp)
646714

647715
memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
648716
memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
717+
718+
ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0);
719+
}
720+
721+
static void macfb_nubus_unrealize(DeviceState *dev)
722+
{
723+
MacfbNubusState *s = NUBUS_MACFB(dev);
724+
MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
725+
MacfbState *ms = &s->macfb;
726+
727+
ndc->parent_unrealize(dev);
728+
729+
qemu_free_irq(ms->irq);
649730
}
650731

651732
static void macfb_sysbus_reset(DeviceState *d)
@@ -696,6 +777,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data)
696777

697778
device_class_set_parent_realize(dc, macfb_nubus_realize,
698779
&ndc->parent_realize);
780+
device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
781+
&ndc->parent_unrealize);
699782
dc->desc = "Nubus Macintosh framebuffer";
700783
dc->reset = macfb_nubus_reset;
701784
dc->vmsd = &vmstate_macfb;

include/hw/display/macfb.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
#define MACFB_H
1515

1616
#include "exec/memory.h"
17+
#include "hw/irq.h"
1718
#include "ui/console.h"
19+
#include "qemu/timer.h"
1820
#include "qom/object.h"
1921

2022
typedef enum {
@@ -63,6 +65,11 @@ typedef struct MacfbState {
6365

6466
uint32_t regs[MACFB_NUM_REGS];
6567
MacFbMode *mode;
68+
69+
uint32_t irq_state;
70+
uint32_t irq_mask;
71+
QEMUTimer *vbl_timer;
72+
qemu_irq irq;
6673
} MacfbState;
6774

6875
#define TYPE_MACFB "sysbus-macfb"
@@ -81,6 +88,7 @@ struct MacfbNubusDeviceClass {
8188
DeviceClass parent_class;
8289

8390
DeviceRealize parent_realize;
91+
DeviceUnrealize parent_unrealize;
8492
};
8593

8694

0 commit comments

Comments
 (0)