Skip to content

Commit df8abbb

Browse files
mcaylandvivier
authored andcommitted
macfb: add common monitor modes supported by the MacOS toolbox ROM
The monitor modes table is found by experimenting with the Monitors Control Panel in MacOS and analysing the reads/writes. From this it can be found that the mode is controlled by writes to the DAFB_MODE_CTRL1 and DAFB_MODE_CTRL2 registers. Implement the first block of DAFB registers as a register array including the existing sense register, the newly discovered control registers above, and also the DAFB_MODE_VADDR1 and DAFB_MODE_VADDR2 registers which are used by NetBSD to determine the current video mode. These experiments also show that the offset of the start of video RAM and the stride can change depending upon the monitor mode, so update macfb_draw_graphic() and both the BI_MAC_VADDR and BI_MAC_VROW bootinfo for the q800 machine accordingly. Finally update macfb_common_realize() so that only the resolution and depth supported by the display type can be specified on the command line, and add an error hint showing the list of supported resolutions and depths if the user tries to specify an invalid display mode. 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 4317c51 commit df8abbb

File tree

4 files changed

+156
-21
lines changed

4 files changed

+156
-21
lines changed

hw/display/macfb.c

Lines changed: 133 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@
2222
#include "migration/vmstate.h"
2323
#include "trace.h"
2424

25-
#define VIDEO_BASE 0x00001000
25+
#define VIDEO_BASE 0x0
2626
#define DAFB_BASE 0x00800000
2727

2828
#define MACFB_PAGE_SIZE 4096
2929
#define MACFB_VRAM_SIZE (4 * MiB)
3030

31+
#define DAFB_MODE_VADDR1 0x0
32+
#define DAFB_MODE_VADDR2 0x4
33+
#define DAFB_MODE_CTRL1 0x8
34+
#define DAFB_MODE_CTRL2 0xc
3135
#define DAFB_MODE_SENSE 0x1c
3236
#define DAFB_RESET 0x200
3337
#define DAFB_LUT 0x213
@@ -89,6 +93,22 @@ static MacFbSense macfb_sense_table[] = {
8993
{ MACFB_DISPLAY_SVGA, 0x7, 0x5 },
9094
};
9195

96+
static MacFbMode macfb_mode_table[] = {
97+
{ MACFB_DISPLAY_VGA, 1, 0x100, 0x71e, 640, 480, 0x400, 0x1000 },
98+
{ MACFB_DISPLAY_VGA, 2, 0x100, 0x70e, 640, 480, 0x400, 0x1000 },
99+
{ MACFB_DISPLAY_VGA, 4, 0x100, 0x706, 640, 480, 0x400, 0x1000 },
100+
{ MACFB_DISPLAY_VGA, 8, 0x100, 0x702, 640, 480, 0x400, 0x1000 },
101+
{ MACFB_DISPLAY_VGA, 24, 0x100, 0x7ff, 640, 480, 0x1000, 0x1000 },
102+
{ MACFB_DISPLAY_VGA, 1, 0xd0 , 0x70e, 800, 600, 0x340, 0xe00 },
103+
{ MACFB_DISPLAY_VGA, 2, 0xd0 , 0x706, 800, 600, 0x340, 0xe00 },
104+
{ MACFB_DISPLAY_VGA, 4, 0xd0 , 0x702, 800, 600, 0x340, 0xe00 },
105+
{ MACFB_DISPLAY_VGA, 8, 0xd0, 0x700, 800, 600, 0x340, 0xe00 },
106+
{ MACFB_DISPLAY_VGA, 24, 0x340, 0x100, 800, 600, 0xd00, 0xe00 },
107+
{ MACFB_DISPLAY_APPLE_21_COLOR, 1, 0x90, 0x506, 1152, 870, 0x240, 0x80 },
108+
{ MACFB_DISPLAY_APPLE_21_COLOR, 2, 0x90, 0x502, 1152, 870, 0x240, 0x80 },
109+
{ MACFB_DISPLAY_APPLE_21_COLOR, 4, 0x90, 0x500, 1152, 870, 0x240, 0x80 },
110+
{ MACFB_DISPLAY_APPLE_21_COLOR, 8, 0x120, 0x5ff, 1152, 870, 0x480, 0x80 },
111+
};
92112

93113
typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
94114
int width);
@@ -246,7 +266,7 @@ static void macfb_draw_graphic(MacfbState *s)
246266
ram_addr_t page;
247267
uint32_t v = 0;
248268
int y, ymin;
249-
int macfb_stride = (s->depth * s->width + 7) / 8;
269+
int macfb_stride = s->mode->stride;
250270
macfb_draw_line_func *macfb_draw_line;
251271

252272
switch (s->depth) {
@@ -278,7 +298,7 @@ static void macfb_draw_graphic(MacfbState *s)
278298
DIRTY_MEMORY_VGA);
279299

280300
ymin = -1;
281-
page = 0;
301+
page = s->mode->offset;
282302
for (y = 0; y < s->height; y++, page += macfb_stride) {
283303
if (macfb_check_dirty(s, snap, page, macfb_stride)) {
284304
uint8_t *data_display;
@@ -323,25 +343,26 @@ static uint32_t macfb_sense_read(MacfbState *s)
323343
sense = 0;
324344
if (!(macfb_sense->ext_sense & 1)) {
325345
/* Pins 7-4 together */
326-
if (~s->sense & 3) {
327-
sense = (~s->sense & 7) | 3;
346+
if (~s->regs[DAFB_MODE_SENSE >> 2] & 3) {
347+
sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 3;
328348
}
329349
}
330350
if (!(macfb_sense->ext_sense & 2)) {
331351
/* Pins 10-7 together */
332-
if (~s->sense & 6) {
333-
sense = (~s->sense & 7) | 6;
352+
if (~s->regs[DAFB_MODE_SENSE >> 2] & 6) {
353+
sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 6;
334354
}
335355
}
336356
if (!(macfb_sense->ext_sense & 4)) {
337357
/* Pins 4-10 together */
338-
if (~s->sense & 5) {
339-
sense = (~s->sense & 7) | 5;
358+
if (~s->regs[DAFB_MODE_SENSE >> 2] & 5) {
359+
sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 5;
340360
}
341361
}
342362
} else {
343363
/* Normal sense */
344-
sense = (~macfb_sense->sense & 7) | (~s->sense & 7);
364+
sense = (~macfb_sense->sense & 7) |
365+
(~s->regs[DAFB_MODE_SENSE >> 2] & 7);
345366
}
346367

347368
trace_macfb_sense_read(sense);
@@ -350,12 +371,84 @@ static uint32_t macfb_sense_read(MacfbState *s)
350371

351372
static void macfb_sense_write(MacfbState *s, uint32_t val)
352373
{
353-
s->sense = val;
374+
s->regs[DAFB_MODE_SENSE >> 2] = val;
354375

355376
trace_macfb_sense_write(val);
356377
return;
357378
}
358379

380+
static void macfb_update_mode(MacfbState *s)
381+
{
382+
s->width = s->mode->width;
383+
s->height = s->mode->height;
384+
s->depth = s->mode->depth;
385+
386+
trace_macfb_update_mode(s->width, s->height, s->depth);
387+
macfb_invalidate_display(s);
388+
}
389+
390+
static void macfb_mode_write(MacfbState *s)
391+
{
392+
MacFbMode *macfb_mode;
393+
int i;
394+
395+
for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
396+
macfb_mode = &macfb_mode_table[i];
397+
398+
if (s->type != macfb_mode->type) {
399+
continue;
400+
}
401+
402+
if ((s->regs[DAFB_MODE_CTRL1 >> 2] & 0xff) ==
403+
(macfb_mode->mode_ctrl1 & 0xff) &&
404+
(s->regs[DAFB_MODE_CTRL2 >> 2] & 0xff) ==
405+
(macfb_mode->mode_ctrl2 & 0xff)) {
406+
s->mode = macfb_mode;
407+
macfb_update_mode(s);
408+
break;
409+
}
410+
}
411+
}
412+
413+
static MacFbMode *macfb_find_mode(MacfbDisplayType display_type,
414+
uint16_t width, uint16_t height,
415+
uint8_t depth)
416+
{
417+
MacFbMode *macfb_mode;
418+
int i;
419+
420+
for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
421+
macfb_mode = &macfb_mode_table[i];
422+
423+
if (display_type == macfb_mode->type && width == macfb_mode->width &&
424+
height == macfb_mode->height && depth == macfb_mode->depth) {
425+
return macfb_mode;
426+
}
427+
}
428+
429+
return NULL;
430+
}
431+
432+
static gchar *macfb_mode_list(void)
433+
{
434+
gchar *list = NULL;
435+
gchar *mode;
436+
MacFbMode *macfb_mode;
437+
int i;
438+
439+
for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
440+
macfb_mode = &macfb_mode_table[i];
441+
442+
mode = g_strdup_printf(" %dx%dx%d\n", macfb_mode->width,
443+
macfb_mode->height, macfb_mode->depth);
444+
list = g_strconcat(mode, list, NULL);
445+
g_free(mode);
446+
}
447+
448+
return list;
449+
}
450+
451+
359452
static void macfb_update_display(void *opaque)
360453
{
361454
MacfbState *s = opaque;
@@ -397,6 +490,12 @@ static uint64_t macfb_ctrl_read(void *opaque,
397490
uint64_t val = 0;
398491

399492
switch (addr) {
493+
case DAFB_MODE_VADDR1:
494+
case DAFB_MODE_VADDR2:
495+
case DAFB_MODE_CTRL1:
496+
case DAFB_MODE_CTRL2:
497+
val = s->regs[addr >> 2];
498+
break;
400499
case DAFB_MODE_SENSE:
401500
val = macfb_sense_read(s);
402501
break;
@@ -413,6 +512,17 @@ static void macfb_ctrl_write(void *opaque,
413512
{
414513
MacfbState *s = opaque;
415514
switch (addr) {
515+
case DAFB_MODE_VADDR1:
516+
case DAFB_MODE_VADDR2:
517+
s->regs[addr >> 2] = val;
518+
break;
519+
case DAFB_MODE_CTRL1 ... DAFB_MODE_CTRL1 + 3:
520+
case DAFB_MODE_CTRL2 ... DAFB_MODE_CTRL2 + 3:
521+
s->regs[addr >> 2] = val;
522+
if (val) {
523+
macfb_mode_write(s);
524+
}
525+
break;
416526
case DAFB_MODE_SENSE:
417527
macfb_sense_write(s, val);
418528
break;
@@ -442,7 +552,7 @@ static const MemoryRegionOps macfb_ctrl_ops = {
442552

443553
static int macfb_post_load(void *opaque, int version_id)
444554
{
445-
macfb_invalidate_display(opaque);
555+
macfb_mode_write(opaque);
446556
return 0;
447557
}
448558

@@ -455,7 +565,7 @@ static const VMStateDescription vmstate_macfb = {
455565
.fields = (VMStateField[]) {
456566
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
457567
VMSTATE_UINT32(palette_current, MacfbState),
458-
VMSTATE_UINT32(sense, MacfbState),
568+
VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS),
459569
VMSTATE_END_OF_LIST()
460570
}
461571
};
@@ -469,9 +579,15 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
469579
{
470580
DisplaySurface *surface;
471581

472-
if (s->depth != 1 && s->depth != 2 && s->depth != 4 && s->depth != 8 &&
473-
s->depth != 16 && s->depth != 24) {
474-
error_setg(errp, "unknown guest depth %d", s->depth);
582+
s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth);
583+
if (!s->mode) {
584+
gchar *list;
585+
error_setg(errp, "unknown display mode: width %d, height %d, depth %d",
586+
s->width, s->height, s->depth);
587+
list = macfb_mode_list();
588+
error_append_hint(errp, "Available modes:\n%s", list);
589+
g_free(list);
590+
475591
return false;
476592
}
477593

@@ -493,6 +609,7 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
493609
s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
494610
memory_region_set_coalescing(&s->mem_vram);
495611

612+
macfb_update_mode(s);
496613
return true;
497614
}
498615

hw/display/trace-events

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,4 @@ macfb_ctrl_read(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"PRIx
173173
macfb_ctrl_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"PRIx64 " value 0x%"PRIx64 " size %u"
174174
macfb_sense_read(uint32_t value) "video sense: 0x%"PRIx32
175175
macfb_sense_write(uint32_t value) "video sense: 0x%"PRIx32
176+
macfb_update_mode(uint32_t width, uint32_t height, uint8_t depth) "setting mode to width %"PRId32 " height %"PRId32 " size %d"

hw/m68k/q800.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
* is needed by the kernel to have early display and
7575
* thus provided by the bootloader
7676
*/
77-
#define VIDEO_BASE 0xf9001000
77+
#define VIDEO_BASE 0xf9000000
7878

7979
#define MAC_CLOCK 3686418
8080

@@ -221,6 +221,7 @@ static void q800_init(MachineState *machine)
221221
uint8_t *prom;
222222
const int io_slice_nb = (IO_SIZE / IO_SLICE) - 1;
223223
int i, checksum;
224+
MacFbMode *macfb_mode;
224225
ram_addr_t ram_size = machine->ram_size;
225226
const char *kernel_filename = machine->kernel_filename;
226227
const char *initrd_filename = machine->initrd_filename;
@@ -428,6 +429,8 @@ static void q800_init(MachineState *machine)
428429
}
429430
qdev_realize_and_unref(dev, BUS(nubus), &error_fatal);
430431

432+
macfb_mode = (NUBUS_MACFB(dev)->macfb).mode;
433+
431434
cs = CPU(cpu);
432435
if (linux_boot) {
433436
uint64_t high;
@@ -450,12 +453,12 @@ static void q800_init(MachineState *machine)
450453
BOOTINFO1(cs->as, parameters_base,
451454
BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */
452455
BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
453-
BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, VIDEO_BASE);
456+
BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR,
457+
VIDEO_BASE + macfb_mode->offset);
454458
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth);
455459
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM,
456460
(graphic_height << 16) | graphic_width);
457-
BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW,
458-
(graphic_width * graphic_depth + 7) / 8);
461+
BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW, macfb_mode->stride);
459462
BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE);
460463

461464
rom = g_malloc(sizeof(*rom));

include/hw/display/macfb.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ typedef enum {
3535
MACFB_DISPLAY_SVGA = 14,
3636
} MacfbDisplayType;
3737

38+
typedef struct MacFbMode {
39+
uint8_t type;
40+
uint8_t depth;
41+
uint32_t mode_ctrl1;
42+
uint32_t mode_ctrl2;
43+
uint32_t width;
44+
uint32_t height;
45+
uint32_t stride;
46+
uint32_t offset;
47+
} MacFbMode;
48+
49+
#define MACFB_NUM_REGS 8
50+
3851
typedef struct MacfbState {
3952
MemoryRegion mem_vram;
4053
MemoryRegion mem_ctrl;
@@ -48,7 +61,8 @@ typedef struct MacfbState {
4861
uint8_t depth;
4962
uint8_t type;
5063

51-
uint32_t sense;
64+
uint32_t regs[MACFB_NUM_REGS];
65+
MacFbMode *mode;
5266
} MacfbState;
5367

5468
#define TYPE_MACFB "sysbus-macfb"

0 commit comments

Comments
 (0)