[coreboot-gerrit] New patch to review for coreboot: nb/gm45/gma.c: Decode edid before doing native graphic init

Arthur Heymans (arthur@aheymans.xyz) gerrit at coreboot.org
Thu Jan 19 20:39:19 CET 2017


Arthur Heymans (arthur at aheymans.xyz) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18179

-gerrit

commit 7027c0cd0134d09246e0439d35dd4a6256d855a5
Author: Arthur Heymans <arthur at aheymans.xyz>
Date:   Thu Jan 19 14:38:34 2017 +0100

    nb/gm45/gma.c: Decode edid before doing native graphic init
    
    This allows the EDID data to be used outside of the native graphic
    init path without having to fetch it again.
    
    This extends return values of decode_edid to make the distinction
    between invalid EDID and 'not connected' EDID.
    
    TESTED on Lenovo X200
    
    Change-Id: I062b42e282beb88bee46aa17934a01845b9b50bf
    Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
 src/include/edid.h               |  6 +++
 src/lib/edid.c                   | 14 +++----
 src/northbridge/intel/gm45/gma.c | 88 +++++++++++++++++++---------------------
 3 files changed, 54 insertions(+), 54 deletions(-)

diff --git a/src/include/edid.h b/src/include/edid.h
index cf81258..f973503 100644
--- a/src/include/edid.h
+++ b/src/include/edid.h
@@ -91,6 +91,12 @@ struct edid {
 	int hdmi_monitor_detected;
 };
 
+enum edid_status {
+	EDID_NOT_CONFORMANT,
+	EDID_CONFORMANT,
+	EDID_ABSENT,
+};
+
 /* Defined in src/lib/edid.c */
 int decode_edid(unsigned char *edid, int size, struct edid *out);
 void edid_set_framebuffer_bits_per_pixel(struct edid *edid, int fb_bpp,
diff --git a/src/lib/edid.c b/src/lib/edid.c
index d1b9c9f..3dd2b08 100644
--- a/src/lib/edid.c
+++ b/src/lib/edid.c
@@ -1056,7 +1056,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 	    .has_valid_range_descriptor = 1,
 	    .has_valid_max_dotclock = 1,
 	    .has_valid_string_termination = 1,
-	    .conformant = 1,
+	    .conformant = EDID_CONFORMANT,
 	};
 
 	dump_breakdown(edid);
@@ -1065,7 +1065,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 
 	if (!edid || memcmp(edid, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8)) {
 		printk(BIOS_SPEW, "No header found\n");
-		return 1;
+		return EDID_ABSENT;
 	}
 
 	if (manufacturer_name(edid + 0x08))
@@ -1359,7 +1359,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 		    !c.has_valid_string_termination ||
 		    !c.has_valid_descriptor_pad ||
 		    !c.has_preferred_timing)
-			c.conformant = 0;
+			c.conformant = EDID_NOT_CONFORMANT;
 		if (!c.conformant)
 			printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.4!\n");
 		if (c.nonconformant_digital_display)
@@ -1376,7 +1376,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 		    !c.has_valid_string_termination ||
 		    !c.has_valid_descriptor_pad ||
 		    !c.has_preferred_timing) {
-			c.conformant = 0;
+			c.conformant = EDID_NOT_CONFORMANT;
 		}
 		/**
 		 * According to E-EDID (EDIDv1.3), has_name_descriptor and
@@ -1407,7 +1407,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 	} else if (c.claims_one_point_two) {
 		if (c.nonconformant_digital_display ||
 		    !c.has_valid_string_termination)
-			c.conformant = 0;
+			c.conformant = EDID_NOT_CONFORMANT;
 		if (!c.conformant)
 			printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.2!\n");
 		if (c.nonconformant_digital_display)
@@ -1417,7 +1417,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 			printk(BIOS_ERR, "\tDetailed block string not properly terminated\n");
 	} else if (c.claims_one_point_oh) {
 		if (c.seen_non_detailed_descriptor)
-			c.conformant = 0;
+			c.conformant = EDID_NOT_CONFORMANT;
 		if (!c.conformant)
 			printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.0!\n");
 		if (c.seen_non_detailed_descriptor)
@@ -1435,7 +1435,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out)
 	    !c.has_valid_descriptor_ordering ||
 	    !c.has_valid_range_descriptor ||
 	    !c.manufacturer_name_well_formed) {
-		c.conformant = 0;
+		c.conformant = EDID_CONFORMANT;
 		printk(BIOS_ERR, "EDID block does not conform at all!\n");
 		if (c.nonconformant_extension)
 			printk(BIOS_ERR, "\tHas %d nonconformant extension block(s)\n",
diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
index 4886bb2..38bd3ca 100644
--- a/src/northbridge/intel/gm45/gma.c
+++ b/src/northbridge/intel/gm45/gma.c
@@ -50,12 +50,10 @@ void gtt_write(u32 reg, u32 data)
 }
 
 static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
-			   u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+			u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
+			struct edid edid)
 {
-
 	int i;
-	u8 edid_data[128];
-	struct edid edid;
 	struct edid_mode *mode;
 	u32 hactive, vactive, right_border, bottom_border;
 	int hpolarity, vpolarity;
@@ -93,15 +91,11 @@ static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
 	for (i = 0; i <= 0x18; i++)
 		vga_cr_write(i, cr[i]);
 
-	intel_gmbus_read_edid(mmio + GMBUS0, 3, 0x50, edid_data,
-			sizeof(edid_data));
-	decode_edid(edid_data,
-		    sizeof(edid_data), &edid);
-	mode = &edid.mode;
-
 	/* Disable screen memory to prevent garbage from appearing. */
 	vga_sr_write(1, vga_sr_read(1) | 0x20);
 
+	mode = &edid.mode;
+
 	hactive = edid.x_resolution;
 	vactive = edid.y_resolution;
 	right_border = mode->hborder;
@@ -321,12 +315,11 @@ static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
 }
 
 static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
-			 u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+			u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
+			struct edid edid)
 {
 
 	int i;
-	u8 edid_data[128];
-	struct edid edid;
 	struct edid_mode *mode;
 	u32 hactive, vactive, right_border, bottom_border;
 	int hpolarity, vpolarity;
@@ -378,17 +371,11 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
 
 	udelay(1);
 
-	intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data,
-			sizeof(edid_data));
-	intel_gmbus_stop(mmio + GMBUS0);
-	decode_edid(edid_data,
-		    sizeof(edid_data), &edid);
-	mode = &edid.mode;
-
-
 	/* Disable screen memory to prevent garbage from appearing.  */
 	vga_sr_write(1, vga_sr_read(1) | 0x20);
 
+	mode = &edid.mode;
+
 	hactive = edid.x_resolution;
 	vactive = edid.y_resolution;
 	right_border = mode->hborder;
@@ -591,25 +578,6 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
 
 }
 
-/* compare the header of the vga edid header */
-/* if vga is not connected it should not have a correct header */
-static u8 vga_connected(u8 *mmio)
-{
-	u8 vga_edid[128];
-	u8 header[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
-	intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, vga_edid,
-			sizeof(vga_edid));
-	intel_gmbus_stop(mmio + GMBUS0);
-	for (int i = 0; i < 8; i++) {
-		if (vga_edid[i] != header[i]) {
-			printk(BIOS_DEBUG, "VGA not connected. Using LVDS display\n");
-			return 0;
-		}
-	}
-	printk(BIOS_SPEW, "VGA display connected\n");
-	return 1;
-}
-
 static u32 get_cdclk(struct device *const dev)
 {
 	const u16 cdclk_sel =
@@ -687,6 +655,10 @@ static void gma_pm_init_post_vbios(struct device *const dev)
 static void gma_func0_init(struct device *dev)
 {
 	u32 reg32;
+	u8 *mmio;
+	u8 edid_data_vga[128], edid_data_lvds[128];
+	struct edid edid_vga, edid_lvds;
+	int lvds_edid_status, vga_edid_status;
 
 	/* IGD needs to be Bus Master */
 	reg32 = pci_read_config32(dev, PCI_COMMAND);
@@ -695,14 +667,30 @@ static void gma_func0_init(struct device *dev)
 
 	/* Init graphics power management */
 	gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0);
+	mmio = res2mmio(gtt_res, 0, 0);
 
 	struct northbridge_intel_gm45_config *conf = dev->chip_info;
 
 	if (!IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)) {
 		/* PCI Init, will run VBIOS */
+		printk(BIOS_DEBUG, "Initialising IGD using VBIOS\n");
 		pci_dev_init(dev);
 	}
 
+	printk(BIOS_DEBUG, "LVDS EDID\n");
+	intel_gmbus_read_edid(mmio + GMBUS0, 3, 0x50, edid_data_lvds,
+			sizeof(edid_data_lvds));
+	intel_gmbus_stop(mmio + GMBUS0);
+	lvds_edid_status = decode_edid(edid_data_lvds,
+				sizeof(edid_data_lvds), &edid_lvds);
+
+	printk(BIOS_DEBUG, "VGA EDID\n");
+	intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data_vga,
+			sizeof(edid_data_vga));
+	intel_gmbus_stop(mmio + GMBUS0);
+	vga_edid_status = decode_edid(edid_data_vga,
+				sizeof(edid_data_vga), &edid_vga);
+
 	/* Post VBIOS init */
 	gma_pm_init_post_vbios(dev);
 
@@ -719,14 +707,20 @@ static void gma_func0_init(struct device *dev)
 		if (gtt_res && gtt_res->base && physbase && pio_res
 		    && pio_res->base && lfb_res && lfb_res->base) {
 			printk(BIOS_SPEW,
-			       "Initializing VGA without OPROM. MMIO 0x%llx\n",
+			       "Initializing display without OPROM. MMIO 0x%llx\n",
 			       gtt_res->base);
-			if (vga_connected(res2mmio(gtt_res, 0, 0)))
-				gma_init_vga(conf, res2mmio(gtt_res, 0, 0),
-					physbase, pio_res->base, lfb_res->base);
-			else
-				gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
-					physbase, pio_res->base, lfb_res->base);
+			if (vga_edid_status != EDID_ABSENT) {
+				printk(BIOS_DEBUG,
+					"Initialising display on VGA output\n");
+				gma_init_vga(conf, mmio, physbase,
+					pio_res->base, lfb_res->base, edid_vga);
+			} else {
+				printk(BIOS_DEBUG,
+					"Initialising display on LVDS output\n");
+				gma_init_lvds(conf, mmio, physbase,
+					pio_res->base, lfb_res->base,
+					edid_lvds);
+			}
 		}
 
 		/* Linux relies on VBT for panel info.  */



More information about the coreboot-gerrit mailing list