Generate EDID according to preferred resolution from VBE_DISPI interface.
Signed-off-by: Hiroshi Miura miurahr@linux.com --- vgasrc/bochsedid.c | 54 ++++++++++++++++++++++++++++++++++++++++++---------- vgasrc/bochsedid.h | 1 + vgasrc/bochsvga.c | 2 ++ 3 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c index 5a40593..6bea389 100644 --- a/vgasrc/bochsedid.c +++ b/vgasrc/bochsedid.c @@ -47,6 +47,23 @@ struct edid_monitor_range_limit edid_range_limit VAR16 = { 0x20,0x20 /* padding */ };
+u16 prefered_xres VAR16, prefered_yres VAR16; + +void bochs_init_preferred_resolution(u16 max_xres, u16 max_yres) { + + if (max_xres >= 1920 && max_yres >= 1200){ + max_xres = 1920; max_yres = 1200; + } else if (max_xres >= 1600 && max_yres >= 1200){ + max_xres = 1600; max_yres = 1200; + } else if (max_xres >= 1280 && max_yres >= 1024){ + max_xres = 1280; max_yres = 1024; + } else { + max_xres = 1152; max_yres = 864; + } + SET_VGA(prefered_xres,max_xres); + SET_VGA(prefered_yres,max_yres); +} + int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next) { struct edid_info *info = data; @@ -90,18 +107,34 @@ int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data, u8 next) /* 720x400@70Hz, 720x400@88Hz, 640x480@60Hz, 640x480@67Hz, 640x480@72Hz, 640x480@75Hz, 800x600@56Hz, 800x600@60Hz, 800x600@72Hz, 800x600@75Hz, 832x624@75Hz, 1152x870@75Hz, not 1024x768@87Hz(I), 1024x768@60Hz, 1024x768@70Hz, 1024x768@75Hz, 1280x1024@75Hz */ - /* standard timings */ + /* standard timings & detailed timing block */ SET_FARVAR(seg, info->standard_timing[0], EDID_STD_640x480_85Hz); SET_FARVAR(seg, info->standard_timing[1], EDID_STD_800x600_85Hz); - SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1024x768_85Hz); - SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1280x720_70Hz); - SET_FARVAR(seg, info->standard_timing[4], EDID_STD_1280x960_60Hz); - SET_FARVAR(seg, info->standard_timing[5], EDID_STD_1440x900_60Hz); - SET_FARVAR(seg, info->standard_timing[6], EDID_STD_1600x1200_60Hz); - SET_FARVAR(seg, info->standard_timing[7], EDID_STD_NOP); - /* detailed timing blocks */ - memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200, - sizeof (edid_dtd_1600x1200)); + if (GET_GLOBAL(prefered_xres) < 1280) { + SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1024x768_85Hz); + SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1152x864_70Hz); + memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1152x864, + sizeof (struct edid_detailed_timing)); + } else if (GET_GLOBAL(prefered_xres) < 1600) { + SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1024x768_85Hz); + SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1280x1024_60Hz); + memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1280x1024, + sizeof (struct edid_detailed_timing)); + } else if (GET_GLOBAL(prefered_xres) >= 1600 && GET_GLOBAL(prefered_xres) < 1920) { + SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1440x900_60Hz); + SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1600x1200_60Hz); + memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1600x1200, + sizeof (struct edid_detailed_timing)); + } else { + SET_FARVAR(seg, info->standard_timing[2], EDID_STD_1440x900_60Hz); + SET_FARVAR(seg, info->standard_timing[3], EDID_STD_1920x1200_60Hz); + memcpy_far(seg, &(info->desc[0].dtd), get_global_seg(), &edid_dtd_1920x1200, + sizeof (struct edid_detailed_timing)); + } + for (i = 4; i < 8; i++) { /* FILL with NOP */ + SET_FARVAR(seg, info->standard_timing[i], EDID_STD_NOP); + } + /* detailed timing block here has already set with standard timings */ /* monitor range */ memcpy_far(seg, &(info->desc[1].mrld), get_global_seg(), &edid_range_limit, sizeof(edid_range_limit)); @@ -145,3 +178,4 @@ int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data) return -1; } } + diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h index 0f925df..be60f9f 100644 --- a/vgasrc/bochsedid.h +++ b/vgasrc/bochsedid.h @@ -131,6 +131,7 @@ struct edid_info { #define EDID_STD_1920x1200_60Hz 0x00D1 #define EDID_STD_NOP 0x0101
+void bochs_init_preferred_resolution(u16 max_xres, u16 max_yres); int bochs_get_ddc_capabilities(u16 unit); int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data); #endif /* bochedid.h */ diff --git a/vgasrc/bochsvga.c b/vgasrc/bochsvga.c index 2a8aeb1..72240c3 100644 --- a/vgasrc/bochsvga.c +++ b/vgasrc/bochsvga.c @@ -373,6 +373,7 @@ bochsvga_init(void) u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE); dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS); u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES); + u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES); u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP); dispi_write(VBE_DISPI_INDEX_ENABLE, en); struct bochsvga_mode *m = bochsvga_modes; @@ -388,6 +389,7 @@ bochsvga_init(void) SET_VGA(m->mode, 0xffff); } } + bochs_init_preferred_resolution(max_xres, max_yres);
return 0; }
On 09/09/12 16:00, Hiroshi Miura wrote:
Generate EDID according to preferred resolution from VBE_DISPI interface.
+void bochs_init_preferred_resolution(u16 max_xres, u16 max_yres) {
- if (max_xres >= 1920 && max_yres >= 1200){
max_xres = 1920; max_yres = 1200;
- } else if (max_xres >= 1600 && max_yres >= 1200){
max_xres = 1600; max_yres = 1200;
- } else if (max_xres >= 1280 && max_yres >= 1024){
max_xres = 1280; max_yres = 1024;
- } else {
max_xres = 1152; max_yres = 864;
- }
- SET_VGA(prefered_xres,max_xres);
- SET_VGA(prefered_yres,max_yres);
+}
u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
- u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES);
- bochs_init_preferred_resolution(max_xres, max_yres);
So how this is supposed to work? qemu gives you fixed max_xres and max_yres values, you'll never see anything below 1600x1200 ...
cheers, Gerd
Hi,
On 2012.09.10 15:57, Gerd Hoffmann wrote:
On 09/09/12 16:00, Hiroshi Miura wrote:
Generate EDID according to preferred resolution from VBE_DISPI interface. +void bochs_init_preferred_resolution(u16 max_xres, u16 max_yres) {
- if (max_xres >= 1920 && max_yres >= 1200){
max_xres = 1920; max_yres = 1200;
- } else if (max_xres >= 1600 && max_yres >= 1200){
max_xres = 1600; max_yres = 1200;
- } else if (max_xres >= 1280 && max_yres >= 1024){
max_xres = 1280; max_yres = 1024;
- } else {
max_xres = 1152; max_yres = 864;
- }
- SET_VGA(prefered_xres,max_xres);
- SET_VGA(prefered_yres,max_yres);
+} u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
- u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES);
- bochs_init_preferred_resolution(max_xres, max_yres);
So how this is supposed to work? qemu gives you fixed max_xres and max_yres values, you'll never see anything below 1600x1200 ...
After implementing this in Seabios/vgabios, qemu have a option to provide a preferred resolution (from several alternatives) thru API.
I'd like to propose qemu to implement max_xres/max_yres generating from user configuration and/or real-display resolutions.
It looks chicken-egg thing, which one should implement first? I think vgabios is good for implement first and qemu next.
I know there was discussion adding API interface to provide edid data block from qemu. and qemu can handle such as /etc/qemu-fw/some-binary.bin for configuration.
This is alternative proposal for not-changing bochs API and help qemu to select resolution in easy way.
Hiroshi
On 09/11/12 01:35, Hiroshi Miura wrote:
Hi,
On 2012.09.10 15:57, Gerd Hoffmann wrote:
On 09/09/12 16:00, Hiroshi Miura wrote:
Generate EDID according to preferred resolution from VBE_DISPI interface. +void bochs_init_preferred_resolution(u16 max_xres, u16 max_yres) {
- if (max_xres >= 1920 && max_yres >= 1200){
max_xres = 1920; max_yres = 1200;
- } else if (max_xres >= 1600 && max_yres >= 1200){
max_xres = 1600; max_yres = 1200;
- } else if (max_xres >= 1280 && max_yres >= 1024){
max_xres = 1280; max_yres = 1024;
- } else {
max_xres = 1152; max_yres = 864;
- }
- SET_VGA(prefered_xres,max_xres);
- SET_VGA(prefered_yres,max_yres);
+} u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
- u16 max_yres = dispi_read(VBE_DISPI_INDEX_YRES);
- bochs_init_preferred_resolution(max_xres, max_yres);
So how this is supposed to work? qemu gives you fixed max_xres and max_yres values, you'll never see anything below 1600x1200 ...
After implementing this in Seabios/vgabios, qemu have a option to provide a preferred resolution (from several alternatives) thru API.
I'd like to propose qemu to implement max_xres/max_yres generating from user configuration and/or real-display resolutions.
It looks chicken-egg thing, which one should implement first? I think vgabios is good for implement first and qemu next.
Usual way is to implement both and send patches for both seabios & qemu to the seabios & qemu lists for review.
Once all issues are sorted the usual process is to merge the qemu patches first, then make seabios use it.
I know there was discussion adding API interface to provide edid data block from qemu. and qemu can handle such as /etc/qemu-fw/some-binary.bin for configuration.
This is alternative proposal for not-changing bochs API and help qemu to select resolution in easy way.
I don't think there is a way around changing the bochs api. Using the maximum resolution values instead of adding new preferred resolution values has bad side effects.
cheers, Gerd
(2012.09.11 15:00), Gerd Hoffmann wrote:
On 09/11/12 01:35, Hiroshi Miura wrote:
I know there was discussion adding API interface to provide edid data block from qemu. and qemu can handle such as /etc/qemu-fw/some-binary.bin for configuration.
This is alternative proposal for not-changing bochs API and help qemu to select resolution in easy way.
I don't think there is a way around changing the bochs api. Using the maximum resolution values instead of adding new preferred resolution values has bad side effects.
I'd like to add bochs api for preferred res and resubmit. patches will be both qemu and seabios for review.
Hiroshi