This patch adds the ability for the Bochs VGA ROM to return information about a HD wide monitor.
It is constructed from defitions at run time.
Inspired by this patch I digged out from the vgabios mailing list: http://old.nabble.com/VBE-BIOS-support-for-monitor-information-(EDID)-td2295...
Signed-off-by: Hiroshi Miura miurahr@linux.com --- Makefile | 3 +- vgasrc/bochsedid.c | 101 ++++++++++++++++++++++++++++++++++++++ vgasrc/bochsedid.h | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/bochsvga.c | 1 + vgasrc/vgahw.h | 5 ++ 5 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 vgasrc/bochsedid.c create mode 100644 vgasrc/bochsedid.h
diff --git a/Makefile b/Makefile index 45ea48a..d3e22b9 100644 --- a/Makefile +++ b/Makefile @@ -189,7 +189,8 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py SRCVGA=src/output.c src/util.c src/pci.c \ vgasrc/vgabios.c vgasrc/vgafb.c vgasrc/vgafonts.c vgasrc/vbe.c \ vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \ - vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c + vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c \ + vgasrc/bochsedid.c
CFLAGS16VGA = $(CFLAGS16INC) -Isrc
diff --git a/vgasrc/bochsedid.c b/vgasrc/bochsedid.c new file mode 100644 index 0000000..ec43d41 --- /dev/null +++ b/vgasrc/bochsedid.c @@ -0,0 +1,101 @@ +// VESA VBE EDID capability for virtual display +// +// Copyright (C) 2012 Hiroshi Miura miurahr@linux.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "vbe.h" // VBE_CAPABILITY_8BIT_DAC +#include "biosvar.h" // GET_GLOBAL +#include "util.h" // dprintf +#include "config.h" // CONFIG_* +#include "bochsedid.h" + +struct edid_detailed_timing edid_dtd_1920x1200 VAR16 = { + 0x4B7D, 0xB0, 0xA0, 0x72, 0xB0, 0x2D, + 0x40, 0x88, 0xC8, 0x55, 0x75, 0x21, + 0x00, 0x00, 0x1C}; +struct edid_monitor_range_limit edid_range_limit VAR16 = { + {0x00,0x00,0x00,0xfD,0x00}, + 50,150, /* Vertical 50Hz - 150Hz */ + 31,135, /* Horiz 31kHz - 135kHz */ + 20, /* clock 200MHz */ + 0, /* no ext */ + 0x0A,0x20,0x20, + 0x2020, + 0x20,0x20 /* padding */ + }; +struct edid_monitor_text edid_serial VAR16 = { + {0,0,0,0xFF,0}, + {'1','2','3','4','5','6','7','8','9','0',0x0A, 0x20, 0x20} +}; +struct edid_monitor_text edid_name VAR16 = { + {0,0,0,0xFC,0}, + {'S','e','a',' ','V','G','A','B','I','O','S',0x0A, 0x20} +}; + +struct edid_info BochsEDID VAR16 = { + .header={0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00}, + .vendor=0x2104, .product=0xCDAB, .serial=0x00000000, + .week=36, .year=22, .major_version=1, .minor_version=3, + .video_setup=0x0F, + /* Video signal interface (analogue, 0.700 : 0.300 : 1.000 V p-p, + Video Setup: Blank Level = Black Level, Separate Sync H & V Signals are + supported, Composite Sync Signal on Horizontal is supported, Composite + Sync Signal on Green Video is supported, Serration on the Vertical Sync + is supported) */ + .screen_width=0x21, .screen_height=0x19,/* 330 mm * 250 mm */ + .gamma=0x78,/* 2.2 */ + .feature_flag=0x0F,/* no DMPS states, RGB, display is continuous frequency, prefered mode */ + .least_chromaticity={0x78, 0xF5}, + .most_chromaticity={0xA6,0x55,0x48,0x9B,0x26,0x12,0x50,0x54}, + .established_timing={0xFF,0xEF,0x80}, + /* 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_timing={EDID_STD_640x480_85Hz, EDID_STD_800x600_85Hz, + EDID_STD_1024x768_85Hz, EDID_STD_1280x720_70Hz, + EDID_STD_1280x960_60Hz, EDID_STD_1440x900_60Hz, + EDID_STD_1600x1200_60Hz,EDID_STD_NOP}, +}; + +void bochs_pupulate_edid_block0(u8 next) +{ + /* detailed timing block */ + memcpy_far(get_global_seg(), &(BochsEDID.desc[0]), get_global_seg(), + &edid_dtd_1920x1200, sizeof (struct edid_detailed_timing)); + /* monitor range */ + memcpy_far(get_global_seg(), &(BochsEDID.desc[1].mrld), get_global_seg(), &edid_range_limit, + sizeof(edid_range_limit)); + /* serial */ + memcpy_far(get_global_seg(), &(BochsEDID.desc[2]), get_global_seg(), &edid_serial, + sizeof (struct edid_monitor_text)); + /* monitor name */ + memcpy_far(get_global_seg(), &(BochsEDID.desc[3]), get_global_seg(), &edid_name, + sizeof (struct edid_monitor_text)); + + SET_VGA(BochsEDID.extensions, next); + u8 sum = -checksum_far(get_global_seg(), &BochsEDID, sizeof(BochsEDID)); + SET_VGA(BochsEDID.checksum, sum); +} + +int bochs_read_edid_block0(u16 unit, u16 block, u16 seg, void *data) +{ + memcpy_far(seg, data, get_global_seg(), &BochsEDID, sizeof(BochsEDID)); + return 0; +} + +int bochs_get_ddc_capabilities(u16 unit) +{ + if (unit != 0) + return -1; + + return (1 << 8) | VBE_DDC1_PROTOCOL_SUPPORTED; +} + +int bochs_read_edid(u16 unit, u16 block, u16 seg, void *data) +{ + if (unit != 0 || block != 0) + return -1; + + return bochs_read_edid_block0(unit, block, seg, data); +} diff --git a/vgasrc/bochsedid.h b/vgasrc/bochsedid.h new file mode 100644 index 0000000..b6b2e3a --- /dev/null +++ b/vgasrc/bochsedid.h @@ -0,0 +1,137 @@ +#ifndef __BOCHEDID_H +#define __BOCHEDID_H + +/* EDID infomation definitions */ +/* Detailed Timing Descriptor */ +struct edid_detailed_timing { + u16 pixel_clock; + u8 horizontal_addressable_low; + u8 horizontal_blanking_low; + u8 horizontal_high; + u8 vertical_addressable_low; + u8 vertical_blanking_low; + u8 vertical_high; + u8 horizontal_front_porch_low; + u8 horizontal_sync_pulse_low; + u8 vertical_low4; + u8 horizontal_vertical_sync_hi; + u8 horizontal_video_image_low; + u8 vertical_video_image_low; + u8 video_image_high; + u8 horizontal_border; + u8 vertical_border; + u8 features; +} PACKED; + +/* Other Monitor Descriptors */ +/* + 0xFF: Monitor serial number (text) + 0xFE: Unspecified text (text) + 0xFC: Monitor name (text) + */ +struct edid_monitor_text { + u8 header[5]; + u8 text[13]; +} PACKED; + +/* Monitor Range Limits Descriptor */ +/* + 0xFD: Monitor range limits. 6- or 13-byte binary descriptor. + */ +struct edid_monitor_range_limit { + u8 header[5]; + u8 vertical_rate_min; + u8 vertical_rate_max; + u8 horizontal_rate_min; + u8 horizontal_rate_max; + u8 pixel_clock_max; + u8 extended_timing_type; + u8 reserved; + u8 start_frequency; + u8 gtf_c_val; + u16 gtf_m_val; + u8 gtf_k_val; + u8 gtf_j_val; +} PACKED; + +/* White point Descriptor */ +/* + 0xFB: Additional white point data. 2à5-byte descriptors, padded with 0A 20 20. + 0xFA: Additional standard timing identifiers. 6à2-byte descriptors, padded with 0A + */ +struct edid_wp_desc { + u8 index; + u8 least; + u8 x; + u8 y; + u8 gamma; +} PACKED; + +struct edid_white_point { + u8 header[5]; + struct edid_wp_desc desc[2]; + u8 padding[3]; +} PACKED; + +struct edid_additional_timing { + u8 header[5]; + u16 standard_timing[6]; + u8 padding; +} PACKED; + +union edid_descriptors { + struct edid_detailed_timing dtd; + struct edid_monitor_range_limit mrld; + struct edid_monitor_text mtxtd; + struct edid_white_point wpd; + struct edid_additional_timing astd; +} PACKED; + +struct edid_info { + u8 header[8]; + u16 vendor; + u16 product; + u32 serial; + u8 week; + u8 year; + u8 major_version; + u8 minor_version; + u8 video_setup; + u8 screen_width; + u8 screen_height; + u8 gamma; + u8 feature_flag; + u8 least_chromaticity[2]; + u8 most_chromaticity[8]; + u8 established_timing[3]; + u16 standard_timing[8]; + union edid_descriptors desc[4]; + u8 extensions; + u8 checksum; +} PACKED; + +/* EDID Standard Timing Description */ + +/* First byte: X resolution, divided by 8, less 31 (256âÂÂ2288 pixels) */ +/* bit 7-6, X:Y pixel ratio: 00=16:10; 01=4:3; 10=5:4; 11=16:9 */ +/* bit 5-0, Vertical frequency, less 60 (60âÂÂ123 Hz), nop 01 01 in Big Endian*/ +#define EDID_STD_640x480_85Hz 0x5931 +#define EDID_STD_800x600_85Hz 0x5945 +#define EDID_STD_1024x768_85Hz 0x5961 +#define EDID_STD_1152x864_70Hz 0x4A71 +#define EDID_STD_1280x720_70Hz 0xCA81 +#define EDID_STD_1280x800_70Hz 0x0A81 +#define EDID_STD_1280x960_60Hz 0x4081 +#define EDID_STD_1280x1024_60Hz 0x8081 +#define EDID_STD_1440x900_60Hz 0x0095 +#define EDID_STD_1600x1200_60Hz 0x40A9 +#define EDID_STD_1600x900_60Hz 0xC0A9 +#define EDID_STD_1680x1050_60Hz 0x00B3 +#define EDID_STD_1920x1080_60Hz 0xC0D1 +#define EDID_STD_1920x1200_60Hz 0x00D1 +#define EDID_STD_NOP 0x0101 + +void bochs_pupulate_edid_block0(u8 next); +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..7b8f430 100644 --- a/vgasrc/bochsvga.c +++ b/vgasrc/bochsvga.c @@ -388,6 +388,7 @@ bochsvga_init(void) SET_VGA(m->mode, 0xffff); } } + bochs_pupulate_edid_block0(0);
return 0; } diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index 01d2609..130462c 100644 --- a/vgasrc/vgahw.h +++ b/vgasrc/vgahw.h @@ -8,6 +8,7 @@ #include "bochsvga.h" // bochsvga_set_mode #include "stdvga.h" // stdvga_set_mode #include "geodevga.h" // geodevga_init +#include "bochsedid.h"
static inline struct vgamode_s *vgahw_find_mode(int mode) { if (CONFIG_VGA_CIRRUS) @@ -130,10 +131,14 @@ static inline int vgahw_restore_state(u16 seg, void *data, int states) { }
static inline int vgahw_get_ddc_capabilities(u16 unit) { + if (CONFIG_VGA_BOCHS) + return bochs_get_ddc_capabilities(unit); return stdvga_get_ddc_capabilities(unit); }
static inline int vgahw_read_edid(u16 unit, u16 block, u16 seg, void *data) { + if (CONFIG_VGA_BOCHS) + return bochs_read_edid(unit, block, seg, data); return stdvga_read_edid(unit, block, seg, data); }