summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/edid.c125
1 files changed, 67 insertions, 58 deletions
diff --git a/src/lib/edid.c b/src/lib/edid.c
index 8c8ab6f38d..3aebc65e00 100644
--- a/src/lib/edid.c
+++ b/src/lib/edid.c
@@ -91,6 +91,8 @@ static struct {
const char *stereo;
} extra_info;
+static struct edid tmp_edid;
+
static int vbe_valid;
static struct lb_framebuffer edid_fb;
@@ -197,9 +199,10 @@ extract_string(unsigned char *x, int *valid_termination, int len)
/* 1 means valid data */
static int
-detailed_block(struct edid *out, unsigned char *x, int in_extension,
+detailed_block(struct edid *result_edid, unsigned char *x, int in_extension,
struct edid_context *c)
{
+ struct edid *out = &tmp_edid;
int i;
#if 1
printk(BIOS_SPEW, "Hex of detail: ");
@@ -208,6 +211,9 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
printk(BIOS_SPEW, "\n");
#endif
+ /* Result might already have some valid fields like mode_is_supported */
+ *out = *result_edid;
+
if (x[0] == 0 && x[1] == 0) {
/* Monitor descriptor block, not detailed timing descriptor. */
if (x[2] != 0) {
@@ -443,63 +449,59 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
c->has_valid_descriptor_ordering = 0;
}
- if (! c->did_detailed_timing){
- /* Edid contains pixel clock in terms of 10KHz */
- out->mode.pixel_clock = (x[0] + (x[1] << 8)) * 10;
- /*
- LVDS supports following pixel clocks
- 25000...112000 kHz: single channel
- 80000...224000 kHz: dual channel
- There is some overlap in theoretically supported
- pixel clock between single-channel and dual-channel.
- In practice with current panels all panels
- <= 75200 kHz: single channel
- >= 97750 kHz: dual channel
- We have no samples between those values, so put a
- threshold at 95000 kHz. If we get anything over
- 95000 kHz with single channel, we can make this
- more sofisticated but it's currently not needed.
- */
- out->mode.lvds_dual_channel = (out->mode.pixel_clock >= 95000);
- extra_info.x_mm = (x[12] + ((x[14] & 0xF0) << 4));
- extra_info.y_mm = (x[13] + ((x[14] & 0x0F) << 8));
- out->mode.ha = (x[2] + ((x[4] & 0xF0) << 4));
- out->mode.hbl = (x[3] + ((x[4] & 0x0F) << 8));
- out->mode.hso = (x[8] + ((x[11] & 0xC0) << 2));
- out->mode.hspw = (x[9] + ((x[11] & 0x30) << 4));
- out->mode.hborder = x[15];
- out->mode.va = (x[5] + ((x[7] & 0xF0) << 4));
- out->mode.vbl = (x[6] + ((x[7] & 0x0F) << 8));
- out->mode.vso = ((x[10] >> 4) + ((x[11] & 0x0C) << 2));
- out->mode.vspw = ((x[10] & 0x0F) + ((x[11] & 0x03) << 4));
- out->mode.vborder = x[16];
- /* set up some reasonable defaults for payloads.
- * We observe that most modern chipsets we work with
- * tend to support rgb888 without regard to the
- * panel bits per color or other settings. The rgb888
- * is a convenient layout for software because
- * it avoids the messy bit stuffing of rgb565 or rgb444.
- * It makes a reasonable trade of memory for speed.
- * So, set up the default for
- * 32 bits per pixel
- * rgb888 (i.e. no alpha, but pixels on 32-bit boundaries)
- * The mainboard can modify these if needed, though
- * we have yet to see a case where that will happen.
- * The existing ARM mainboards don't even call this function
- * so this will not affect them.
- */
- out->framebuffer_bits_per_pixel = 32;
-
- out->x_resolution = ALIGN(out->mode.ha *
- ((out->framebuffer_bits_per_pixel + 7) / 8),
- 64) / (out->framebuffer_bits_per_pixel/8);
- out->y_resolution = out->mode.va;
- out->bytes_per_line = ALIGN(out->mode.ha *
- ((out->framebuffer_bits_per_pixel + 7)/8),
- 64);
- printk(BIOS_SPEW, "Did detailed timing\n");
- }
- c->did_detailed_timing = 1;
+ /* Edid contains pixel clock in terms of 10KHz */
+ out->mode.pixel_clock = (x[0] + (x[1] << 8)) * 10;
+ /*
+ LVDS supports following pixel clocks
+ 25000...112000 kHz: single channel
+ 80000...224000 kHz: dual channel
+ There is some overlap in theoretically supported
+ pixel clock between single-channel and dual-channel.
+ In practice with current panels all panels
+ <= 75200 kHz: single channel
+ >= 97750 kHz: dual channel
+ We have no samples between those values, so put a
+ threshold at 95000 kHz. If we get anything over
+ 95000 kHz with single channel, we can make this
+ more sofisticated but it's currently not needed.
+ */
+ out->mode.lvds_dual_channel = (out->mode.pixel_clock >= 95000);
+ extra_info.x_mm = (x[12] + ((x[14] & 0xF0) << 4));
+ extra_info.y_mm = (x[13] + ((x[14] & 0x0F) << 8));
+ out->mode.ha = (x[2] + ((x[4] & 0xF0) << 4));
+ out->mode.hbl = (x[3] + ((x[4] & 0x0F) << 8));
+ out->mode.hso = (x[8] + ((x[11] & 0xC0) << 2));
+ out->mode.hspw = (x[9] + ((x[11] & 0x30) << 4));
+ out->mode.hborder = x[15];
+ out->mode.va = (x[5] + ((x[7] & 0xF0) << 4));
+ out->mode.vbl = (x[6] + ((x[7] & 0x0F) << 8));
+ out->mode.vso = ((x[10] >> 4) + ((x[11] & 0x0C) << 2));
+ out->mode.vspw = ((x[10] & 0x0F) + ((x[11] & 0x03) << 4));
+ out->mode.vborder = x[16];
+ /* set up some reasonable defaults for payloads.
+ * We observe that most modern chipsets we work with
+ * tend to support rgb888 without regard to the
+ * panel bits per color or other settings. The rgb888
+ * is a convenient layout for software because
+ * it avoids the messy bit stuffing of rgb565 or rgb444.
+ * It makes a reasonable trade of memory for speed.
+ * So, set up the default for
+ * 32 bits per pixel
+ * rgb888 (i.e. no alpha, but pixels on 32-bit boundaries)
+ * The mainboard can modify these if needed, though
+ * we have yet to see a case where that will happen.
+ * The existing ARM mainboards don't even call this function
+ * so this will not affect them.
+ */
+ out->framebuffer_bits_per_pixel = 32;
+
+ out->x_resolution = ALIGN(out->mode.ha *
+ ((out->framebuffer_bits_per_pixel + 7) / 8),
+ 64) / (out->framebuffer_bits_per_pixel/8);
+ out->y_resolution = out->mode.va;
+ out->bytes_per_line = ALIGN(out->mode.ha *
+ ((out->framebuffer_bits_per_pixel + 7)/8),
+ 64);
switch ((x[17] & 0x18) >> 3) {
case 0x00:
extra_info.syncmethod = " analog composite";
@@ -556,6 +558,13 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension,
out->mode.phsync, out->mode.pvsync,
extra_info.syncmethod, x[17] & 0x80 ?" interlaced" : "",
extra_info.stereo);
+
+ if (! c->did_detailed_timing) {
+ printk(BIOS_SPEW, "Did detailed timing\n");
+ c->did_detailed_timing = 1;
+ *result_edid = *out;
+ }
+
return 1;
}