UPSTREAM: edid: Make framebuffer row alignment configurable

Our EDID code had always been aligning the framebuffer's
bytes_per_line (and x_resolution dependent on that) to 64. It turns out
that this is a controller-dependent parameter that seems to only really
be necessary for Intel chipsets, and commit 6911219cc (edid: Add helper
function to calculate bits-per-pixel dependent values) probably actually
broke this for some other controllers by applying the alignment too
widely.

This patch makes it explicitly configurable and depends the default on
ARCH_X86 (which seems to be the simplest and least intrusive way to make
it fit most cases for now... boards where this doesn't apply can still
override it manually by calling edid_set_framebuffer_bits_per_pixel()
again).

BRANCH=None
BUG=None
TEST=None

Change-Id: I1c565a72826fc5ddfbb1ae4a5db5e9063b761455
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/14267
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-on: https://chromium-review.googlesource.com/337692
Reviewed-by: Patrick Georgi <pgeorgi@chromium.org>
diff --git a/src/drivers/emulation/qemu/bochs.c b/src/drivers/emulation/qemu/bochs.c
index f32fee0..74a7247 100644
--- a/src/drivers/emulation/qemu/bochs.c
+++ b/src/drivers/emulation/qemu/bochs.c
@@ -113,7 +113,7 @@
 	edid.mode.va = height;
 	edid.panel_bits_per_color = 8;
 	edid.panel_bits_per_pixel = 24;
-	edid_set_framebuffer_bits_per_pixel(&edid, 32);
+	edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
 	set_vbe_mode_info_valid(&edid, addr);
 #else
 	vga_misc_write(0x1);
diff --git a/src/drivers/emulation/qemu/cirrus.c b/src/drivers/emulation/qemu/cirrus.c
index 84c2958..dc20f54 100644
--- a/src/drivers/emulation/qemu/cirrus.c
+++ b/src/drivers/emulation/qemu/cirrus.c
@@ -332,7 +332,7 @@
 	edid.mode.va = height;
 	edid.panel_bits_per_color = 8;
 	edid.panel_bits_per_pixel = 24;
-	edid_set_framebuffer_bits_per_pixel(&edid, 32);
+	edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
 	set_vbe_mode_info_valid(&edid, addr);
 #else
 	vga_misc_write(0x1);
diff --git a/src/include/edid.h b/src/include/edid.h
index f46c761..73412a3 100644
--- a/src/include/edid.h
+++ b/src/include/edid.h
@@ -93,7 +93,8 @@
 
 /* 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);
+void edid_set_framebuffer_bits_per_pixel(struct edid *edid, int fb_bpp,
+					 int row_byte_alignment);
 void set_vbe_mode_info_valid(struct edid *edid, uintptr_t fb_addr);
 int set_display_mode(struct edid *edid, enum edid_modes mode);
 
diff --git a/src/lib/edid.c b/src/lib/edid.c
index 52898fb..8bcb956 100644
--- a/src/lib/edid.c
+++ b/src/lib/edid.c
@@ -481,9 +481,14 @@
 	out->mode.vborder = x[16];
 
 	/* We assume rgb888 (32 bits per pixel) framebuffers by default.
-	 * Chipsets that want something else will need to override this
-	 * with another call to edid_set_framebuffer_bits_per_pixel(). */
-	edid_set_framebuffer_bits_per_pixel(out, 32);
+	 * Chipsets that want something else will need to override this with
+	 * another call to edid_set_framebuffer_bits_per_pixel(). As a cheap
+	 * heuristic, assume that X86 systems require a 64-byte row alignment
+	 * (since that seems to be true for most Intel chipsets). */
+	if (IS_ENABLED(CONFIG_ARCH_X86))
+		edid_set_framebuffer_bits_per_pixel(out, 32, 64);
+	else
+		edid_set_framebuffer_bits_per_pixel(out, 32, 0);
 
 	switch ((x[17] & 0x18) >> 3) {
 	case 0x00:
@@ -1524,14 +1529,16 @@
  */
 
 /* Set the framebuffer bits-per-pixel, recalculating all dependent values. */
-void edid_set_framebuffer_bits_per_pixel(struct edid *edid, int fb_bpp)
+void edid_set_framebuffer_bits_per_pixel(struct edid *edid, int fb_bpp,
+					 int row_byte_alignment)
 {
 	/* Caller should pass a supported value, everything else is BUG(). */
 	assert(fb_bpp == 32 || fb_bpp == 24 || fb_bpp == 16);
+	row_byte_alignment = max(row_byte_alignment, 1);
 
 	edid->framebuffer_bits_per_pixel = fb_bpp;
 	edid->bytes_per_line = ALIGN_UP(edid->mode.ha *
-					div_round_up(fb_bpp, 8), 64);
+		div_round_up(fb_bpp, 8), row_byte_alignment);
 	edid->x_resolution = edid->bytes_per_line / (fb_bpp / 8);
 	edid->y_resolution = edid->mode.va;
 }
diff --git a/src/soc/nvidia/tegra124/display.c b/src/soc/nvidia/tegra124/display.c
index 74202ba..bb96831 100644
--- a/src/soc/nvidia/tegra124/display.c
+++ b/src/soc/nvidia/tegra124/display.c
@@ -334,6 +334,6 @@
 	edid.mode.va = config->yres;
 	edid.mode.ha = config->xres;
 	edid_set_framebuffer_bits_per_pixel(&edid,
-					    config->framebuffer_bits_per_pixel);
+		config->framebuffer_bits_per_pixel, 0);
 	set_vbe_mode_info_valid(&edid, (uintptr_t)(framebuffer_base_mb*MiB));
 }
diff --git a/src/soc/nvidia/tegra132/dc.c b/src/soc/nvidia/tegra132/dc.c
index 562061a..3ae25bc 100644
--- a/src/soc/nvidia/tegra132/dc.c
+++ b/src/soc/nvidia/tegra132/dc.c
@@ -230,7 +230,7 @@
 	edid.mode.va = config->display_yres;
 	edid.mode.ha = config->display_xres;
 	edid_set_framebuffer_bits_per_pixel(&edid,
-					    config->framebuffer_bits_per_pixel);
+		config->framebuffer_bits_per_pixel, 0);
 
 	printk(BIOS_INFO, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
 			"               x_res x y_res: %d x %d, size: %d\n",
diff --git a/src/soc/nvidia/tegra210/dc.c b/src/soc/nvidia/tegra210/dc.c
index 72f1bcb..88e599d 100644
--- a/src/soc/nvidia/tegra210/dc.c
+++ b/src/soc/nvidia/tegra210/dc.c
@@ -230,7 +230,7 @@
 	edid.mode.va = config->display_yres;
 	edid.mode.ha = config->display_xres;
 	edid_set_framebuffer_bits_per_pixel(&edid,
-					    config->framebuffer_bits_per_pixel);
+		config->framebuffer_bits_per_pixel, 0);
 
 	printk(BIOS_INFO, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
 			"               x_res x y_res: %d x %d, size: %d\n",
diff --git a/src/soc/rockchip/rk3288/display.c b/src/soc/rockchip/rk3288/display.c
index 66b2edc..306baad 100644
--- a/src/soc/rockchip/rk3288/display.c
+++ b/src/soc/rockchip/rk3288/display.c
@@ -95,7 +95,7 @@
 	}
 
 	edid_set_framebuffer_bits_per_pixel(&edid,
-					    conf->framebuffer_bits_per_pixel);
+		conf->framebuffer_bits_per_pixel, 0);
 	rkvop_mode_set(conf->vop_id, &edid, detected_mode);
 
 	rkvop_enable(conf->vop_id, lcdbase, &edid);