Message ID | 20211002110007.30825-12-mark.cave-ayland@ilande.co.uk |
---|---|
State | New |
Headers | show |
Series | macfb: fixes for booting MacOS | expand |
Le 02/10/2021 à 13:00, Mark Cave-Ayland a écrit : > 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 <mark.cave-ayland@ilande.co.uk> > --- > hw/display/macfb.c | 81 ++++++++++++++++++++++++++++++++++++++ > include/hw/display/macfb.h | 8 ++++ > 2 files changed, 89 insertions(+) > > diff --git a/hw/display/macfb.c b/hw/display/macfb.c > index 29f6ad8eba..60a203e67b 100644 > --- a/hw/display/macfb.c > +++ b/hw/display/macfb.c > @@ -33,9 +33,16 @@ > #define DAFB_MODE_CTRL1 0x8 > #define DAFB_MODE_CTRL2 0xc > #define DAFB_MODE_SENSE 0x1c > +#define DAFB_INTR_MASK 0x104 > +#define DAFB_INTR_STAT 0x108 > +#define DAFB_INTR_CLEAR 0x10c > #define DAFB_RESET 0x200 > #define DAFB_LUT 0x213 > > +#define DAFB_INTR_VBL 0x4 > + > +/* Vertical Blank period (60.15Hz) */ > +#define DAFB_INTR_VBL_PERIOD_NS 16625800 > > /* > * Quadra sense codes taken from Apple Technical Note HW26: > @@ -449,6 +456,32 @@ static void macfb_update_display(void *opaque) > macfb_draw_graphic(s); > } > > +static void macfb_update_irq(MacfbState *s) > +{ > + uint32_t irq_state = s->irq_state & s->irq_mask; > + > + if (irq_state) { > + qemu_irq_raise(s->irq); > + } else { > + qemu_irq_lower(s->irq); > + } > +} > + > +static void macfb_vbl_timer(void *opaque) > +{ > + MacfbState *s = opaque; > + int64_t next_vbl; > + > + s->irq_state |= DAFB_INTR_VBL; > + macfb_update_irq(s); > + > + /* 60 Hz irq */ > + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > + DAFB_INTR_VBL_PERIOD_NS) / > + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; > + timer_mod(s->vbl_timer, next_vbl); perhaps you can move this to a function and call it here and below? > +} > + > static void macfb_reset(MacfbState *s) > { > int i; > @@ -477,6 +510,9 @@ static uint64_t macfb_ctrl_read(void *opaque, > case DAFB_MODE_CTRL2: > val = s->regs[addr >> 2]; > break; > + case DAFB_INTR_STAT: > + val = s->irq_state; > + break; > case DAFB_MODE_SENSE: > val = macfb_sense_read(s); > break; > @@ -492,6 +528,8 @@ static void macfb_ctrl_write(void *opaque, > unsigned int size) > { > MacfbState *s = opaque; > + int64_t next_vbl; > + > switch (addr) { > case DAFB_MODE_VADDR1: > case DAFB_MODE_VADDR2: > @@ -507,8 +545,25 @@ static void macfb_ctrl_write(void *opaque, > case DAFB_MODE_SENSE: > macfb_sense_write(s, val); > break; > + case DAFB_INTR_MASK: > + s->irq_mask = val; > + if (val & DAFB_INTR_VBL) { > + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > + DAFB_INTR_VBL_PERIOD_NS) / > + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; > + timer_mod(s->vbl_timer, next_vbl); > + } else { > + timer_del(s->vbl_timer); > + } > + break; > + case DAFB_INTR_CLEAR: > + s->irq_state &= ~DAFB_INTR_VBL; > + macfb_update_irq(s); > + break; > case DAFB_RESET: > s->palette_current = 0; > + s->irq_state &= ~DAFB_INTR_VBL; > + macfb_update_irq(s); > break; > case DAFB_LUT: > s->color_palette[s->palette_current++] = val; > @@ -586,6 +641,7 @@ static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) > s->vram_bit_mask = MACFB_VRAM_SIZE - 1; > memory_region_set_coalescing(&s->mem_vram); > > + s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s); > macfb_update_mode(s); > } > > @@ -601,6 +657,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp) > > sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); > sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); > + > + qdev_init_gpio_out(dev, &ms->irq, 1); > +} > + > +static void macfb_nubus_set_irq(void *opaque, int n, int level) > +{ > + MacfbNubusState *s = NUBUS_MACFB(opaque); > + NubusDevice *nd = NUBUS_DEVICE(s); > + > + nubus_set_irq(nd, level); > } > > static void macfb_nubus_realize(DeviceState *dev, Error **errp) > @@ -622,6 +688,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp) > > memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); > memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); > + > + ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0); > +} > + > +static void macfb_nubus_unrealize(DeviceState *dev) > +{ > + MacfbNubusState *s = NUBUS_MACFB(dev); > + MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev); > + MacfbState *ms = &s->macfb; > + > + ndc->parent_unrealize(dev); > + > + qemu_free_irq(ms->irq); > } > > static void macfb_sysbus_reset(DeviceState *d) > @@ -672,6 +751,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data) > > device_class_set_parent_realize(dc, macfb_nubus_realize, > &ndc->parent_realize); > + device_class_set_parent_unrealize(dc, macfb_nubus_unrealize, > + &ndc->parent_unrealize); > dc->desc = "Nubus Macintosh framebuffer"; > dc->reset = macfb_nubus_reset; > dc->vmsd = &vmstate_macfb; > diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h > index 0aff0d84d2..e52775aa21 100644 > --- a/include/hw/display/macfb.h > +++ b/include/hw/display/macfb.h > @@ -14,7 +14,9 @@ > #define MACFB_H > > #include "exec/memory.h" > +#include "hw/irq.h" > #include "ui/console.h" > +#include "qemu/timer.h" > #include "qom/object.h" > > typedef enum { > @@ -63,6 +65,11 @@ typedef struct MacfbState { > > uint32_t regs[MACFB_NUM_REGS]; > MacFbMode *mode; > + > + uint32_t irq_state; > + uint32_t irq_mask; > + QEMUTimer *vbl_timer; > + qemu_irq irq; > } MacfbState; > > #define TYPE_MACFB "sysbus-macfb" > @@ -81,6 +88,7 @@ struct MacfbNubusDeviceClass { > DeviceClass parent_class; > > DeviceRealize parent_realize; > + DeviceUnrealize parent_unrealize; > }; > > > Reviewed-by: Laurent Vivier <laurent@vivier.eu>
On 04/10/2021 17:32, Laurent Vivier wrote: > Le 02/10/2021 à 13:00, Mark Cave-Ayland a écrit : >> 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 <mark.cave-ayland@ilande.co.uk> >> --- >> hw/display/macfb.c | 81 ++++++++++++++++++++++++++++++++++++++ >> include/hw/display/macfb.h | 8 ++++ >> 2 files changed, 89 insertions(+) >> >> diff --git a/hw/display/macfb.c b/hw/display/macfb.c >> index 29f6ad8eba..60a203e67b 100644 >> --- a/hw/display/macfb.c >> +++ b/hw/display/macfb.c >> @@ -33,9 +33,16 @@ >> #define DAFB_MODE_CTRL1 0x8 >> #define DAFB_MODE_CTRL2 0xc >> #define DAFB_MODE_SENSE 0x1c >> +#define DAFB_INTR_MASK 0x104 >> +#define DAFB_INTR_STAT 0x108 >> +#define DAFB_INTR_CLEAR 0x10c >> #define DAFB_RESET 0x200 >> #define DAFB_LUT 0x213 >> >> +#define DAFB_INTR_VBL 0x4 >> + >> +/* Vertical Blank period (60.15Hz) */ >> +#define DAFB_INTR_VBL_PERIOD_NS 16625800 >> >> /* >> * Quadra sense codes taken from Apple Technical Note HW26: >> @@ -449,6 +456,32 @@ static void macfb_update_display(void *opaque) >> macfb_draw_graphic(s); >> } >> >> +static void macfb_update_irq(MacfbState *s) >> +{ >> + uint32_t irq_state = s->irq_state & s->irq_mask; >> + >> + if (irq_state) { >> + qemu_irq_raise(s->irq); >> + } else { >> + qemu_irq_lower(s->irq); >> + } >> +} >> + >> +static void macfb_vbl_timer(void *opaque) >> +{ >> + MacfbState *s = opaque; >> + int64_t next_vbl; >> + >> + s->irq_state |= DAFB_INTR_VBL; >> + macfb_update_irq(s); >> + >> + /* 60 Hz irq */ >> + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + >> + DAFB_INTR_VBL_PERIOD_NS) / >> + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; >> + timer_mod(s->vbl_timer, next_vbl); > > perhaps you can move this to a function and call it here and below? I'd like to keep the timer_mod() outside of the function but I agree it is nicer to keep the next_vbl logci in a single place. >> +} >> + >> static void macfb_reset(MacfbState *s) >> { >> int i; >> @@ -477,6 +510,9 @@ static uint64_t macfb_ctrl_read(void *opaque, >> case DAFB_MODE_CTRL2: >> val = s->regs[addr >> 2]; >> break; >> + case DAFB_INTR_STAT: >> + val = s->irq_state; >> + break; >> case DAFB_MODE_SENSE: >> val = macfb_sense_read(s); >> break; >> @@ -492,6 +528,8 @@ static void macfb_ctrl_write(void *opaque, >> unsigned int size) >> { >> MacfbState *s = opaque; >> + int64_t next_vbl; >> + >> switch (addr) { >> case DAFB_MODE_VADDR1: >> case DAFB_MODE_VADDR2: >> @@ -507,8 +545,25 @@ static void macfb_ctrl_write(void *opaque, >> case DAFB_MODE_SENSE: >> macfb_sense_write(s, val); >> break; >> + case DAFB_INTR_MASK: >> + s->irq_mask = val; >> + if (val & DAFB_INTR_VBL) { >> + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + >> + DAFB_INTR_VBL_PERIOD_NS) / >> + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; >> + timer_mod(s->vbl_timer, next_vbl); >> + } else { >> + timer_del(s->vbl_timer); >> + } >> + break; >> + case DAFB_INTR_CLEAR: >> + s->irq_state &= ~DAFB_INTR_VBL; >> + macfb_update_irq(s); >> + break; >> case DAFB_RESET: >> s->palette_current = 0; >> + s->irq_state &= ~DAFB_INTR_VBL; >> + macfb_update_irq(s); >> break; >> case DAFB_LUT: >> s->color_palette[s->palette_current++] = val; >> @@ -586,6 +641,7 @@ static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) >> s->vram_bit_mask = MACFB_VRAM_SIZE - 1; >> memory_region_set_coalescing(&s->mem_vram); >> >> + s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s); >> macfb_update_mode(s); >> } >> >> @@ -601,6 +657,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp) >> >> sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); >> sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); >> + >> + qdev_init_gpio_out(dev, &ms->irq, 1); >> +} >> + >> +static void macfb_nubus_set_irq(void *opaque, int n, int level) >> +{ >> + MacfbNubusState *s = NUBUS_MACFB(opaque); >> + NubusDevice *nd = NUBUS_DEVICE(s); >> + >> + nubus_set_irq(nd, level); >> } >> >> static void macfb_nubus_realize(DeviceState *dev, Error **errp) >> @@ -622,6 +688,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp) >> >> memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); >> memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); >> + >> + ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0); >> +} >> + >> +static void macfb_nubus_unrealize(DeviceState *dev) >> +{ >> + MacfbNubusState *s = NUBUS_MACFB(dev); >> + MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev); >> + MacfbState *ms = &s->macfb; >> + >> + ndc->parent_unrealize(dev); >> + >> + qemu_free_irq(ms->irq); >> } >> >> static void macfb_sysbus_reset(DeviceState *d) >> @@ -672,6 +751,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data) >> >> device_class_set_parent_realize(dc, macfb_nubus_realize, >> &ndc->parent_realize); >> + device_class_set_parent_unrealize(dc, macfb_nubus_unrealize, >> + &ndc->parent_unrealize); >> dc->desc = "Nubus Macintosh framebuffer"; >> dc->reset = macfb_nubus_reset; >> dc->vmsd = &vmstate_macfb; >> diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h >> index 0aff0d84d2..e52775aa21 100644 >> --- a/include/hw/display/macfb.h >> +++ b/include/hw/display/macfb.h >> @@ -14,7 +14,9 @@ >> #define MACFB_H >> >> #include "exec/memory.h" >> +#include "hw/irq.h" >> #include "ui/console.h" >> +#include "qemu/timer.h" >> #include "qom/object.h" >> >> typedef enum { >> @@ -63,6 +65,11 @@ typedef struct MacfbState { >> >> uint32_t regs[MACFB_NUM_REGS]; >> MacFbMode *mode; >> + >> + uint32_t irq_state; >> + uint32_t irq_mask; >> + QEMUTimer *vbl_timer; >> + qemu_irq irq; >> } MacfbState; >> >> #define TYPE_MACFB "sysbus-macfb" >> @@ -81,6 +88,7 @@ struct MacfbNubusDeviceClass { >> DeviceClass parent_class; >> >> DeviceRealize parent_realize; >> + DeviceUnrealize parent_unrealize; >> }; >> >> >> > > Reviewed-by: Laurent Vivier <laurent@vivier.eu> ATB, Mark.
diff --git a/hw/display/macfb.c b/hw/display/macfb.c index 29f6ad8eba..60a203e67b 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -33,9 +33,16 @@ #define DAFB_MODE_CTRL1 0x8 #define DAFB_MODE_CTRL2 0xc #define DAFB_MODE_SENSE 0x1c +#define DAFB_INTR_MASK 0x104 +#define DAFB_INTR_STAT 0x108 +#define DAFB_INTR_CLEAR 0x10c #define DAFB_RESET 0x200 #define DAFB_LUT 0x213 +#define DAFB_INTR_VBL 0x4 + +/* Vertical Blank period (60.15Hz) */ +#define DAFB_INTR_VBL_PERIOD_NS 16625800 /* * Quadra sense codes taken from Apple Technical Note HW26: @@ -449,6 +456,32 @@ static void macfb_update_display(void *opaque) macfb_draw_graphic(s); } +static void macfb_update_irq(MacfbState *s) +{ + uint32_t irq_state = s->irq_state & s->irq_mask; + + if (irq_state) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +} + +static void macfb_vbl_timer(void *opaque) +{ + MacfbState *s = opaque; + int64_t next_vbl; + + s->irq_state |= DAFB_INTR_VBL; + macfb_update_irq(s); + + /* 60 Hz irq */ + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + DAFB_INTR_VBL_PERIOD_NS) / + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; + timer_mod(s->vbl_timer, next_vbl); +} + static void macfb_reset(MacfbState *s) { int i; @@ -477,6 +510,9 @@ static uint64_t macfb_ctrl_read(void *opaque, case DAFB_MODE_CTRL2: val = s->regs[addr >> 2]; break; + case DAFB_INTR_STAT: + val = s->irq_state; + break; case DAFB_MODE_SENSE: val = macfb_sense_read(s); break; @@ -492,6 +528,8 @@ static void macfb_ctrl_write(void *opaque, unsigned int size) { MacfbState *s = opaque; + int64_t next_vbl; + switch (addr) { case DAFB_MODE_VADDR1: case DAFB_MODE_VADDR2: @@ -507,8 +545,25 @@ static void macfb_ctrl_write(void *opaque, case DAFB_MODE_SENSE: macfb_sense_write(s, val); break; + case DAFB_INTR_MASK: + s->irq_mask = val; + if (val & DAFB_INTR_VBL) { + next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + DAFB_INTR_VBL_PERIOD_NS) / + DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; + timer_mod(s->vbl_timer, next_vbl); + } else { + timer_del(s->vbl_timer); + } + break; + case DAFB_INTR_CLEAR: + s->irq_state &= ~DAFB_INTR_VBL; + macfb_update_irq(s); + break; case DAFB_RESET: s->palette_current = 0; + s->irq_state &= ~DAFB_INTR_VBL; + macfb_update_irq(s); break; case DAFB_LUT: s->color_palette[s->palette_current++] = val; @@ -586,6 +641,7 @@ static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) s->vram_bit_mask = MACFB_VRAM_SIZE - 1; memory_region_set_coalescing(&s->mem_vram); + s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s); macfb_update_mode(s); } @@ -601,6 +657,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); + + qdev_init_gpio_out(dev, &ms->irq, 1); +} + +static void macfb_nubus_set_irq(void *opaque, int n, int level) +{ + MacfbNubusState *s = NUBUS_MACFB(opaque); + NubusDevice *nd = NUBUS_DEVICE(s); + + nubus_set_irq(nd, level); } static void macfb_nubus_realize(DeviceState *dev, Error **errp) @@ -622,6 +688,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); + + ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0); +} + +static void macfb_nubus_unrealize(DeviceState *dev) +{ + MacfbNubusState *s = NUBUS_MACFB(dev); + MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev); + MacfbState *ms = &s->macfb; + + ndc->parent_unrealize(dev); + + qemu_free_irq(ms->irq); } static void macfb_sysbus_reset(DeviceState *d) @@ -672,6 +751,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data) device_class_set_parent_realize(dc, macfb_nubus_realize, &ndc->parent_realize); + device_class_set_parent_unrealize(dc, macfb_nubus_unrealize, + &ndc->parent_unrealize); dc->desc = "Nubus Macintosh framebuffer"; dc->reset = macfb_nubus_reset; dc->vmsd = &vmstate_macfb; diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h index 0aff0d84d2..e52775aa21 100644 --- a/include/hw/display/macfb.h +++ b/include/hw/display/macfb.h @@ -14,7 +14,9 @@ #define MACFB_H #include "exec/memory.h" +#include "hw/irq.h" #include "ui/console.h" +#include "qemu/timer.h" #include "qom/object.h" typedef enum { @@ -63,6 +65,11 @@ typedef struct MacfbState { uint32_t regs[MACFB_NUM_REGS]; MacFbMode *mode; + + uint32_t irq_state; + uint32_t irq_mask; + QEMUTimer *vbl_timer; + qemu_irq irq; } MacfbState; #define TYPE_MACFB "sysbus-macfb" @@ -81,6 +88,7 @@ struct MacfbNubusDeviceClass { DeviceClass parent_class; DeviceRealize parent_realize; + DeviceUnrealize parent_unrealize; };
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 <mark.cave-ayland@ilande.co.uk> --- hw/display/macfb.c | 81 ++++++++++++++++++++++++++++++++++++++ include/hw/display/macfb.h | 8 ++++ 2 files changed, 89 insertions(+)