shithub: riscv

Download patch

ref: 954f9f1fcf041c35fb7c3b2ad07cdf26b280da79
parent: d082a8972f9bd3ddb32079eb72b22ece25722970
author: Michael Forney <mforney@mforney.org>
date: Mon Feb 28 16:20:52 EST 2022

aux/vga: return modes according to EDID timing priority order

EDID 1.3 section 5 gives a table describing the priority order of
timing information. Use this ordering when constructing the EDID
mode list.

Since aux/vga selects the first mode in the modelist that matches
the given size, it will now select the mode of that size with the
highest preference. Or, if you set vgasize=auto (or some other
string without an 'x'), aux/vga will select the Preferred Detailed
Timing.

This should make it unnecessary to modify vgadb in many cases.

--- a/sys/src/cmd/aux/vga/edid.c
+++ b/sys/src/cmd/aux/vga/edid.c
@@ -6,8 +6,8 @@
 #include "pci.h"
 #include "vga.h"
 
-static Modelist*
-addmode(Modelist *l, Mode m)
+static void
+addmode(Modelist **l, Mode m)
 {
 	Modelist *ll;
 	int rr;
@@ -15,17 +15,15 @@
 	rr = (m.frequency+m.ht*m.vt/2)/(m.ht*m.vt);
 	snprint(m.name, sizeof m.name, "%dx%d@%dHz", m.x, m.y, rr);
 
-	for(ll = l; ll != nil; ll = ll->next){
-		if(strcmp(ll->name, m.name) == 0){
-			ll->Mode = m;
-			return l;
-		}
+	for(ll = *l; ll != nil; ll = *l){
+		if(strcmp(ll->name, m.name) == 0)
+			return;
+		l = &ll->next;
 	}
 
 	ll = alloc(sizeof(Modelist));
 	ll->Mode = m;
-	ll->next = l;
-	return ll;
+	*l = ll;
 }
 
 /*
@@ -282,70 +280,85 @@
 
 	assert(p == (uchar*)v+8+10+2+5+10);
 	/*
-	 * Established timings: a bitmask of 19 preset timings.
+	 * Timing information priority order (EDID 1.3 section 5)
+	 *   1. Preferred Timing Mode (first detailed timing block)
+	 *   2. Other Detailed Timing Mode, in order listed
+	 *   3. Standard Timings, in order listed
+	 *   4. Established Timings
 	 */
-	estab = (p[0]<<16) | (p[1]<<8) | p[2];
-	p += 3;
 
-	for(i=0, m=1<<23; i<nelem(estabtime); i++, m>>=1)
-		if(estab & m)
-			if(vesalookup(&mode, estabtime[i]) == 0)
-				e->modelist = addmode(e->modelist,  mode);
+	/*
+	 * Detailed Timings
+	 */
+	p = (uchar*)v+8+10+2+5+10+3+16;
+	for(i=0; i<4; i++, p+=18)
+		if(p[0] || p[1])	/* detailed timing block: p[0] or p[1] != 0 */
+			if(decodedtb(&mode, p) == 0)
+				addmode(&e->modelist, mode);
+	assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
 
-	assert(p == (uchar*)v+8+10+2+5+10+3);
 	/*
 	 * Standard Timing Identifications: eight 2-byte selectors
 	 * of more standard timings.
 	 */
-
+	p = (uchar*)v+8+10+2+5+10+3;
 	for(i=0; i<8; i++, p+=2)
 		if(decodesti(&mode, p+2*i) == 0)
-			e->modelist = addmode(e->modelist, mode);
-
+			addmode(&e->modelist, mode);
 	assert(p == (uchar*)v+8+10+2+5+10+3+16);
-	/*
-	 * Detailed Timings
-	 */
-	for(i=0; i<4; i++, p+=18) {
-		if(p[0] || p[1]) {	/* detailed timing block: p[0] or p[1] != 0 */
-			if(decodedtb(&mode, p) == 0)
-				e->modelist = addmode(e->modelist, mode);
-		} else if(p[2]==0) {	/* monitor descriptor block */
-			switch(p[3]) {
-			case 0xFF:	/* monitor serial number (13-byte ascii, 0A terminated) */
-				if(q = memchr(p+5, 0x0A, 13))
-					*q = '\0';
-				memset(e->serialstr, 0, sizeof(e->serialstr));
-				strncpy(e->serialstr, (char*)p+5, 13);
-				break;
-			case 0xFE:	/* ascii string (13-byte ascii, 0A terminated) */
-				break;
-			case 0xFD:	/* monitor range limits */
-				e->rrmin = p[5];
-				e->rrmax = p[6];
-				e->hrmin = p[7]*1000;
-				e->hrmax = p[8]*1000;
-				if(p[9] != 0xFF)
-					e->pclkmax = p[9]*10*1000000;
-				break;
-			case 0xFC:	/* monitor name (13-byte ascii, 0A terminated) */
-				if(q = memchr(p+5, 0x0A, 13))
-					*q = '\0';
-				memset(e->name, 0, sizeof(e->name));
-				strncpy(e->name, (char*)p+5, 13);
-				break;
-			case 0xFB:	/* extra color point data */
-				break;
-			case 0xFA:	/* extra standard timing identifications */
-				for(i=0; i<6; i++)
-					if(decodesti(&mode, p+5+2*i) == 0)
-						e->modelist = addmode(e->modelist, mode);
-				break;
-			}
+
+	p = (uchar*)v+8+10+2+5+10+3+16;
+	for(i=0; i<4; i++, p+=18){
+		if(p[0] || p[1])
+			continue;
+		/* monitor descriptor block */
+		switch(p[3]) {
+		case 0xFF:	/* monitor serial number (13-byte ascii, 0A terminated) */
+			if(q = memchr(p+5, 0x0A, 13))
+				*q = '\0';
+			memset(e->serialstr, 0, sizeof(e->serialstr));
+			strncpy(e->serialstr, (char*)p+5, 13);
+			break;
+		case 0xFE:	/* ascii string (13-byte ascii, 0A terminated) */
+			break;
+		case 0xFD:	/* monitor range limits */
+			e->rrmin = p[5];
+			e->rrmax = p[6];
+			e->hrmin = p[7]*1000;
+			e->hrmax = p[8]*1000;
+			if(p[9] != 0xFF)
+				e->pclkmax = p[9]*10*1000000;
+			break;
+		case 0xFC:	/* monitor name (13-byte ascii, 0A terminated) */
+			if(q = memchr(p+5, 0x0A, 13))
+				*q = '\0';
+			memset(e->name, 0, sizeof(e->name));
+			strncpy(e->name, (char*)p+5, 13);
+			break;
+		case 0xFB:	/* extra color point data */
+			break;
+		case 0xFA:	/* extra standard timing identifications */
+			for(i=0; i<6; i++)
+				if(decodesti(&mode, p+5+2*i) == 0)
+					addmode(&e->modelist, mode);
+			break;
 		}
 	}
-
 	assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
+
+	/*
+	 * Established timings: a bitmask of 19 preset timings.
+	 */
+	p = (uchar*)v+8+10+2+5+10;
+	estab = (p[0]<<16) | (p[1]<<8) | p[2];
+	p += 3;
+
+	for(i=0, m=1<<23; i<nelem(estabtime); i++, m>>=1)
+		if(estab & m)
+			if(vesalookup(&mode, estabtime[i]) == 0)
+				addmode(&e->modelist, mode);
+	assert(p == (uchar*)v+8+10+2+5+10+3);
+
 	return e;
 }