aboutsummaryrefslogtreecommitdiff
path: root/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4')
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/INFO4
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/INFO4
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/INFO8
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch601
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch35
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch27
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/INFO8
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/reused.list4
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/INFO4
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/INFO4
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/reused.list7
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/INFO5
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/reused.list5
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/reused.list5
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch88
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch45
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch229
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch50
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch38
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch212
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch379
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch31
-rw-r--r--resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/INFO5
63 files changed, 8689 insertions, 0 deletions
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/INFO
new file mode 100644
index 00000000..ad7d12f4
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/INFO
@@ -0,0 +1,4 @@
+# NOTE: remove this when updating coreboot. This has been merged upstream
+printf "ThinkPad R400 support (clone of the T400)\n"
+git am "../resources/libreboot/patch/misc/0007-lenovo-r400-Add-clone-of-Lenovo-T400.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/93/8393/5 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/reused.list
new file mode 100644
index 00000000..451d1b75
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb//0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/INFO
new file mode 100644
index 00000000..ad7d12f4
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/INFO
@@ -0,0 +1,4 @@
+# NOTE: remove this when updating coreboot. This has been merged upstream
+printf "ThinkPad R400 support (clone of the T400)\n"
+git am "../resources/libreboot/patch/misc/0007-lenovo-r400-Add-clone-of-Lenovo-T400.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/93/8393/5 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/INFO
new file mode 100644
index 00000000..9ef6d54a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/INFO
@@ -0,0 +1,8 @@
+# NOTE: merged upstream already
+printf "mainboard/lenovo/t400: Add initial hybrid graphics support\n"
+git am "../resources/libreboot/patch/misc/0001-mainboard-lenovo-t400-Add-initial-hybrid-graphics-su.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/19/9319/18 && git cherry-pick FETCH_HEAD
+
+printf "NOTFORMERGE: lenovo/t400: hard-code enable integrated-only video\n"
+git am "../resources/libreboot/patch/misc/0002-NOTFORMERGE-lenovo-t400-hard-code-enable-integrated-.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/50/10550/1 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
new file mode 100644
index 00000000..67420ca7
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
@@ -0,0 +1,601 @@
+From fbbc8d6a278c733eca475c17cbf95a8946e2c173 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 4 Aug 2016 11:00:13 +0200
+Subject: [PATCH 1/3] Revert "drivers/lenovo: Add hybrid graphics driver"
+
+This reverts commit 5919ba42ed0ce5b1b13717514698444232c6036c.
+
+Change-Id: I027581ef769ca8232e72f89738c1bdec13f62687
+
+diff --git a/src/drivers/lenovo/Kconfig b/src/drivers/lenovo/Kconfig
+index f8eddf2..f20f3b2 100644
+--- a/src/drivers/lenovo/Kconfig
++++ b/src/drivers/lenovo/Kconfig
+@@ -27,16 +27,3 @@ config DIGITIZER_ABSENT
+ endchoice
+
+ endif
+-
+-config DRIVERS_LENOVO_HYBRID_GRAPHICS
+- bool
+- default n
+-
+-config HYBRID_GRAPHICS_GPIO_NUM
+- depends on DRIVERS_LENOVO_HYBRID_GRAPHICS
+- int
+- default 52
+- help
+- Set a default GPIO that sets the panel LVDS signal routing to
+- integrated or discrete GPU.
+-
+diff --git a/src/drivers/lenovo/Makefile.inc b/src/drivers/lenovo/Makefile.inc
+index 66f8594..c50db5b 100644
+--- a/src/drivers/lenovo/Makefile.inc
++++ b/src/drivers/lenovo/Makefile.inc
+@@ -1,2 +1 @@
+ ramstage-$(CONFIG_DRIVERS_LENOVO_WACOM) += wacom.c
+-ramstage-$(CONFIG_DRIVERS_LENOVO_HYBRID_GRAPHICS) += hybrid_graphics.c
+diff --git a/src/drivers/lenovo/hybrid_graphics.c b/src/drivers/lenovo/hybrid_graphics.c
+deleted file mode 100644
+index 9b46646..0000000
+--- a/src/drivers/lenovo/hybrid_graphics.c
++++ /dev/null
+@@ -1,125 +0,0 @@
+-/*
+- * This file is part of the coreboot project.
+- *
+- * Copyright (C) 2015-2016 Patrick Rudolph
+- * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; version 2 of the License.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- */
+-
+-#include <types.h>
+-#include <string.h>
+-#include <option.h>
+-#include <device/device.h>
+-#include <device/pci_def.h>
+-#include <device/pci_ops.h>
+-#include <device/pci_ids.h>
+-#include <device/pci.h>
+-#include <console/console.h>
+-#include <southbridge/intel/common/gpio.h>
+-
+-/* Hybrid graphics allows to connect LVDS interface to either iGPU
+- * or dGPU depending on GPIO level.
+- * Nvidia is calling this functionality "muxed Optimus".
+- * Some devices, like T430s, only support "muxless Optimus" where the
+- * Intel GPU is always connected to the panel.
+- * As it is only linked on lenovo and only executed if the GPU exists
+- * we know for sure that the dGPU is there and connected to first PEG slot.
+- *
+- * Note: Once native gfx init is done for AMD or Nvida graphic
+- * cards, merge this code.
+- */
+-
+-#define HYBRID_GRAPHICS_INTEGRATED 0
+-#define HYBRID_GRAPHICS_DISCRETE 1
+-
+-static void hybrid_graphics_disable_peg(struct device *dev)
+-{
+- struct device *peg_dev;
+-
+- /* connect LVDS interface to iGPU */
+- set_gpio(CONFIG_HYBRID_GRAPHICS_GPIO_NUM, GPIO_LEVEL_HIGH);
+- printk(BIOS_DEBUG, "Hybrid graphics: Switching panel to integrated GPU.\n");
+- dev->enabled = 0;
+-
+- /* Disable PEG10 */
+- peg_dev = dev_find_slot(0, PCI_DEVFN(1, 0));
+- if (peg_dev)
+- peg_dev->enabled = 0;
+-
+- printk(BIOS_DEBUG, "Hybrid graphics: Disabled PEG10.\n");
+-}
+-
+-/* Called before VGA enable bits are set and only if dGPU
+- * is present. Enable/disable VGA devices here. */
+-static void hybrid_graphics_enable_peg(struct device *dev)
+-{
+- u8 hybrid_graphics_mode;
+-
+- hybrid_graphics_mode = HYBRID_GRAPHICS_INTEGRATED;
+- get_option(&hybrid_graphics_mode, "hybrid_graphics_mode");
+-
+- if (hybrid_graphics_mode == HYBRID_GRAPHICS_DISCRETE) {
+- /* connect LVDS interface to dGPU */
+- set_gpio(CONFIG_HYBRID_GRAPHICS_GPIO_NUM, GPIO_LEVEL_LOW);
+- printk(BIOS_DEBUG, "Hybrid graphics: Switching panel to discrete GPU.\n");
+- dev->enabled = 1;
+-
+- /* Disable IGD */
+- dev = dev_find_slot(0, PCI_DEVFN(2, 0));
+- if (dev && dev->ops->disable)
+- dev->ops->disable(dev);
+- dev->enabled = 0;
+-
+- printk(BIOS_DEBUG, "Hybrid graphics: Disabled IGD.\n");
+- } else
+- hybrid_graphics_disable_peg(dev);
+-}
+-
+-static struct pci_operations pci_dev_ops_pci = {
+- .set_subsystem = pci_dev_set_subsystem,
+-};
+-
+-struct device_operations hybrid_graphics_ops = {
+- .read_resources = pci_dev_read_resources,
+- .set_resources = pci_dev_set_resources,
+- .enable_resources = pci_dev_enable_resources,
+- .init = pci_dev_init,
+- .scan_bus = 0,
+- .enable = hybrid_graphics_enable_peg,
+- .disable = hybrid_graphics_disable_peg,
+- .ops_pci = &pci_dev_ops_pci,
+-};
+-
+-static const unsigned short pci_device_ids_nvidia[] = {
+- 0x0ffc, /* Nvidia NVS Quadro K1000m Lenovo W530 */
+- 0x0def, /* NVidia NVS 5400m Lenovo T430/T530 */
+- 0x0dfc, /* NVidia NVS 5200m Lenovo T430s */
+- 0x1056, /* NVidia NVS 4200m Lenovo T420/T520 */
+- 0x1057, /* NVidia NVS 4200m Lenovo T420/T520 */
+- 0x0a6c, /* NVidia NVS 3100m Lenovo T410/T510 */
+- 0 };
+-
+-static const struct pci_driver hybrid_peg_nvidia __pci_driver = {
+- .ops = &hybrid_graphics_ops,
+- .vendor = PCI_VENDOR_ID_NVIDIA,
+- .devices = pci_device_ids_nvidia,
+-};
+-
+-static const unsigned short pci_device_ids_amd[] = {
+- 0x9591, /* ATI Mobility Radeon HD 3650 Lenovo T500/W500 */
+- 0x95c4, /* ATI Mobility Radeon HD 3470 Lenovo T400/R400 */
+- 0 };
+-
+-static const struct pci_driver hybrid_peg_amd __pci_driver = {
+- .ops = &hybrid_graphics_ops,
+- .vendor = PCI_VENDOR_ID_ATI,
+- .devices = pci_device_ids_amd,
+-};
+diff --git a/src/mainboard/lenovo/t400/Kconfig b/src/mainboard/lenovo/t400/Kconfig
+index a444bf8..d74a813 100644
+--- a/src/mainboard/lenovo/t400/Kconfig
++++ b/src/mainboard/lenovo/t400/Kconfig
+@@ -22,7 +22,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+ select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
+ select INTEL_INT15
+ select SUPERIO_NSC_PC87382
+- select DRIVERS_LENOVO_HYBRID_GRAPHICS
+
+ config MAINBOARD_DIR
+ string
+diff --git a/src/mainboard/lenovo/t400/cmos.default b/src/mainboard/lenovo/t400/cmos.default
+index 5cf3e63..ac9f96d 100644
+--- a/src/mainboard/lenovo/t400/cmos.default
++++ b/src/mainboard/lenovo/t400/cmos.default
+@@ -13,5 +13,3 @@ sticky_fn=Disable
+ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
+-hybrid_graphics_mode=Integrated Only
+-gfx_uma_size=32M
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t400/cmos.layout b/src/mainboard/lenovo/t400/cmos.layout
+index b4b7766..e1a088d 100644
+--- a/src/mainboard/lenovo/t400/cmos.layout
++++ b/src/mainboard/lenovo/t400/cmos.layout
+@@ -77,8 +77,7 @@ entries
+ 940 1 e 1 uwb
+
+ # coreboot config options: northbridge
+-944 2 e 12 hybrid_graphics_mode
+-946 4 e 11 gfx_uma_size
++941 4 e 11 gfx_uma_size
+
+ # coreboot config options: EC
+ 952 8 h 0 volume
+diff --git a/src/mainboard/lenovo/t420/cmos.default b/src/mainboard/lenovo/t420/cmos.default
+index 3a82c97..1b8e212 100644
+--- a/src/mainboard/lenovo/t420/cmos.default
++++ b/src/mainboard/lenovo/t420/cmos.default
+@@ -14,4 +14,3 @@ fn_ctrl_swap=Disable
+ sticky_fn=Disable
+ trackpoint=Enable
+ hyper_threading=Enable
+-hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t420/cmos.layout b/src/mainboard/lenovo/t420/cmos.layout
+index 58a4abe..bf0f195 100644
+--- a/src/mainboard/lenovo/t420/cmos.layout
++++ b/src/mainboard/lenovo/t420/cmos.layout
+@@ -77,8 +77,7 @@ entries
+
+ # coreboot config options: northbridge
+ 432 3 e 11 gfx_uma_size
+-435 2 e 12 hybrid_graphics_mode
+-#437 3 r 0 unused
++#435 5 r 0 unused
+
+ 440 8 h 0 volume
+
+@@ -136,8 +135,6 @@ enumerations
+ 11 4 160M
+ 11 5 192M
+ 11 6 224M
+-12 0 Integrated Only
+-12 1 Discrete Only
+
+ # -----------------------------------------------------------------
+ checksums
+diff --git a/src/mainboard/lenovo/t420s/Kconfig b/src/mainboard/lenovo/t420s/Kconfig
+index feacb51..935e659 100644
+--- a/src/mainboard/lenovo/t420s/Kconfig
++++ b/src/mainboard/lenovo/t420s/Kconfig
+@@ -18,7 +18,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+ select INTEL_INT15
+ select SANDYBRIDGE_IVYBRIDGE_LVDS
+ select MAINBOARD_HAS_LPC_TPM
+- select DRIVERS_LENOVO_HYBRID_GRAPHICS
+
+ # Workaround for EC/KBC IRQ1.
+ select SERIRQ_CONTINUOUS_MODE
+diff --git a/src/mainboard/lenovo/t420s/cmos.default b/src/mainboard/lenovo/t420s/cmos.default
+index 3a82c97..1b8e212 100644
+--- a/src/mainboard/lenovo/t420s/cmos.default
++++ b/src/mainboard/lenovo/t420s/cmos.default
+@@ -14,4 +14,3 @@ fn_ctrl_swap=Disable
+ sticky_fn=Disable
+ trackpoint=Enable
+ hyper_threading=Enable
+-hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t420s/cmos.layout b/src/mainboard/lenovo/t420s/cmos.layout
+index 3521849..43628406 100644
+--- a/src/mainboard/lenovo/t420s/cmos.layout
++++ b/src/mainboard/lenovo/t420s/cmos.layout
+@@ -77,8 +77,7 @@ entries
+
+ # coreboot config options: northbridge
+ 432 3 e 11 gfx_uma_size
+-435 2 e 12 hybrid_graphics_mode
+-#437 3 r 0 unused
++#435 5 r 0 unused
+
+ 440 8 h 0 volume
+
+@@ -136,8 +135,6 @@ enumerations
+ 11 4 160M
+ 11 5 192M
+ 11 6 224M
+-12 0 Integrated Only
+-12 1 Discrete Only
+
+ # -----------------------------------------------------------------
+ checksums
+diff --git a/src/mainboard/lenovo/t520/Kconfig b/src/mainboard/lenovo/t520/Kconfig
+index ee5dd81..c70581a 100644
+--- a/src/mainboard/lenovo/t520/Kconfig
++++ b/src/mainboard/lenovo/t520/Kconfig
+@@ -18,7 +18,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+ select INTEL_INT15
+ select SANDYBRIDGE_IVYBRIDGE_LVDS
+ select MAINBOARD_HAS_LPC_TPM
+- select DRIVERS_LENOVO_HYBRID_GRAPHICS
+
+ # Workaround for EC/KBC IRQ1.
+ select SERIRQ_CONTINUOUS_MODE
+diff --git a/src/mainboard/lenovo/t520/cmos.default b/src/mainboard/lenovo/t520/cmos.default
+index ad7dcf5..00e8863 100644
+--- a/src/mainboard/lenovo/t520/cmos.default
++++ b/src/mainboard/lenovo/t520/cmos.default
+@@ -15,4 +15,3 @@ sticky_fn=Disable
+ trackpoint=Enable
+ hyper_threading=Enable
+ backlight=Both
+-hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t520/cmos.layout b/src/mainboard/lenovo/t520/cmos.layout
+index 044c310..2cf3629 100644
+--- a/src/mainboard/lenovo/t520/cmos.layout
++++ b/src/mainboard/lenovo/t520/cmos.layout
+@@ -77,8 +77,7 @@ entries
+
+ # coreboot config options: northbridge
+ 432 3 e 11 gfx_uma_size
+-435 2 e 12 hybrid_graphics_mode
+-#437 3 r 0 unused
++#435 5 r 0 unused
+ 440 8 h 0 volume
+
+ # SandyBridge MRC Scrambler Seed values
+@@ -135,8 +134,6 @@ enumerations
+ 11 4 160M
+ 11 5 192M
+ 11 6 224M
+-12 0 Integrated Only
+-12 1 Discrete Only
+ # -----------------------------------------------------------------
+ checksums
+
+diff --git a/src/mainboard/lenovo/t530/Kconfig b/src/mainboard/lenovo/t530/Kconfig
+index 76147fc..030c01f 100644
+--- a/src/mainboard/lenovo/t530/Kconfig
++++ b/src/mainboard/lenovo/t530/Kconfig
+@@ -21,7 +21,6 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+ select SANDYBRIDGE_IVYBRIDGE_LVDS
+ select ENABLE_VMX
+ select MAINBOARD_HAS_LPC_TPM
+- select DRIVERS_LENOVO_HYBRID_GRAPHICS
+
+ # Workaround for EC/KBC IRQ1.
+ select SERIRQ_CONTINUOUS_MODE
+diff --git a/src/mainboard/lenovo/t530/cmos.default b/src/mainboard/lenovo/t530/cmos.default
+index ad7dcf5..00e8863 100644
+--- a/src/mainboard/lenovo/t530/cmos.default
++++ b/src/mainboard/lenovo/t530/cmos.default
+@@ -15,4 +15,3 @@ sticky_fn=Disable
+ trackpoint=Enable
+ hyper_threading=Enable
+ backlight=Both
+-hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t530/cmos.layout b/src/mainboard/lenovo/t530/cmos.layout
+index 0e28bdd..e21c197 100644
+--- a/src/mainboard/lenovo/t530/cmos.layout
++++ b/src/mainboard/lenovo/t530/cmos.layout
+@@ -77,8 +77,7 @@ entries
+
+ # coreboot config options: northbridge
+ 432 3 e 11 gfx_uma_size
+-435 2 e 12 hybrid_graphics_mode
+-#437 3 r 0 unused
++#435 5 r 0 unused
+
+ 440 8 h 0 volume
+
+@@ -136,9 +135,6 @@ enumerations
+ 11 4 160M
+ 11 5 192M
+ 11 6 224M
+-12 0 Integrated Only
+-12 1 Discrete Only
+-
+ # -----------------------------------------------------------------
+ checksums
+
+diff --git a/src/southbridge/intel/i82801ix/Kconfig b/src/southbridge/intel/i82801ix/Kconfig
+index b3e5069..2822774 100644
+--- a/src/southbridge/intel/i82801ix/Kconfig
++++ b/src/southbridge/intel/i82801ix/Kconfig
+@@ -23,7 +23,6 @@ config SOUTHBRIDGE_INTEL_I82801IX
+ select USE_WATCHDOG_ON_BOOT
+ select HAVE_SMI_HANDLER
+ select HAVE_USBDEBUG_OPTIONS
+- select SOUTHBRIDGE_INTEL_COMMON_GPIO
+
+ if SOUTHBRIDGE_INTEL_I82801IX
+
+--
+2.9.2
+
+From 90f5f34629ff88506bb803988da1552f3373d4f0 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 4 Aug 2016 11:01:53 +0200
+Subject: [PATCH 2/3] Revert "Revert "mainboard/lenovo/t400: Add initial hybrid
+ graphics support""
+
+This reverts commit 14d1a93e444b91311eeed2a25953bf6c0779cdcb.
+
+Change-Id: I965ea55bddb7cf919e7b02ecf8e160c9ad3ea3d4
+
+diff --git a/src/mainboard/lenovo/t400/cmos.default b/src/mainboard/lenovo/t400/cmos.default
+index ac9f96d..98ce970 100644
+--- a/src/mainboard/lenovo/t400/cmos.default
++++ b/src/mainboard/lenovo/t400/cmos.default
+@@ -13,3 +13,4 @@ sticky_fn=Disable
+ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
++hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/t400/cmos.layout b/src/mainboard/lenovo/t400/cmos.layout
+index e1a088d..b4b7766 100644
+--- a/src/mainboard/lenovo/t400/cmos.layout
++++ b/src/mainboard/lenovo/t400/cmos.layout
+@@ -77,7 +77,8 @@ entries
+ 940 1 e 1 uwb
+
+ # coreboot config options: northbridge
+-941 4 e 11 gfx_uma_size
++944 2 e 12 hybrid_graphics_mode
++946 4 e 11 gfx_uma_size
+
+ # coreboot config options: EC
+ 952 8 h 0 volume
+diff --git a/src/mainboard/lenovo/t400/romstage.c b/src/mainboard/lenovo/t400/romstage.c
+index f518775..fcc545b 100644
+--- a/src/mainboard/lenovo/t400/romstage.c
++++ b/src/mainboard/lenovo/t400/romstage.c
+@@ -1,6 +1,7 @@
+ /*
+ * This file is part of the coreboot project.
+ *
++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
+ * Copyright (C) 2012 secunet Security Networks AG
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -34,6 +35,118 @@
+ #define LPC_DEV PCI_DEV(0, 0x1f, 0)
+ #define MCH_DEV PCI_DEV(0, 0, 0)
+
++#define HYBRID_GRAPHICS_INTEGRATED_ONLY 0
++#define HYBRID_GRAPHICS_DISCRETE_ONLY 1
++#define HYBRID_GRAPHICS_SWITCHABLE 2
++
++#define HYBRID_GRAPHICS_GP_LVL_BITS 0x004a0000
++#define HYBRID_GRAPHICS_GP_LVL2_BITS 0x00020000
++
++#define HYBRID_GRAPHICS_DETECT_GP_BITS 0x00000010
++
++#define HYBRID_GRAPHICS_INT_CLAIM_VGA 0x2
++#define HYBRID_GRAPHICS_SEC_VGA_EN 0x2
++
++static void hybrid_graphics_configure_switchable_graphics(bool enable)
++{
++ uint32_t tmp;
++
++ if (enable) {
++ /* Disable integrated graphics legacy VGA cycles */
++ tmp = pci_read_config16(MCH_DEV, D0F0_GGC);
++ pci_write_config16(MCH_DEV, D0F0_GGC, tmp | HYBRID_GRAPHICS_INT_CLAIM_VGA);
++
++ /* Enable secondary VGA controller */
++ tmp = pci_read_config16(MCH_DEV, D0F0_DEVEN);
++ pci_write_config16(MCH_DEV, D0F0_DEVEN, tmp | HYBRID_GRAPHICS_SEC_VGA_EN);
++ }
++ else {
++ /* Enable integrated graphics legacy VGA cycles */
++ tmp = pci_read_config16(MCH_DEV, D0F0_GGC);
++ pci_write_config16(MCH_DEV, D0F0_GGC, tmp & ~HYBRID_GRAPHICS_INT_CLAIM_VGA);
++
++ /* Disable secondary VGA controller */
++ tmp = pci_read_config16(MCH_DEV, D0F0_DEVEN);
++ pci_write_config16(MCH_DEV, D0F0_DEVEN, tmp & ~HYBRID_GRAPHICS_SEC_VGA_EN);
++ }
++}
++
++static void hybrid_graphics_set_up_gpio(void)
++{
++ uint32_t tmp;
++
++ /* Enable hybrid graphics GPIO lines */
++ tmp = inl(DEFAULT_GPIOBASE + GP_IO_USE_SEL);
++ tmp = tmp | HYBRID_GRAPHICS_GP_LVL_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_IO_USE_SEL);
++
++ tmp = inl(DEFAULT_GPIOBASE + GP_IO_USE_SEL2);
++ tmp = tmp | HYBRID_GRAPHICS_GP_LVL2_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_IO_USE_SEL2);
++
++ /* Set hybrid graphics control GPIO lines to output */
++ tmp = inl(DEFAULT_GPIOBASE + GP_IO_SEL);
++ tmp = tmp & ~HYBRID_GRAPHICS_GP_LVL_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_IO_SEL);
++
++ tmp = inl(DEFAULT_GPIOBASE + GP_IO_SEL2);
++ tmp = tmp & ~HYBRID_GRAPHICS_GP_LVL2_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_IO_SEL2);
++
++ /* Set hybrid graphics detect GPIO lines to input */
++ tmp = inl(DEFAULT_GPIOBASE + GP_IO_SEL);
++ tmp = tmp | HYBRID_GRAPHICS_DETECT_GP_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_IO_SEL);
++}
++
++static bool hybrid_graphics_installed(void)
++{
++ if (inl(DEFAULT_GPIOBASE + GP_LVL) & HYBRID_GRAPHICS_DETECT_GP_BITS)
++ return false;
++ else
++ return true;
++}
++
++static void hybrid_graphics_switch_to_integrated_graphics(void)
++{
++ uint32_t tmp;
++
++ /* Disable switchable graphics */
++ hybrid_graphics_configure_switchable_graphics(false);
++
++ /* Configure muxes */
++ tmp = inl(DEFAULT_GPIOBASE + GP_LVL);
++ tmp = tmp & ~HYBRID_GRAPHICS_GP_LVL_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_LVL);
++
++ tmp = inl(DEFAULT_GPIOBASE + GP_LVL2);
++ tmp = tmp & ~HYBRID_GRAPHICS_GP_LVL2_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_LVL2);
++}
++
++static void hybrid_graphics_switch_to_discrete_graphics(void)
++{
++ uint32_t tmp;
++
++ /* Disable switchable graphics */
++ hybrid_graphics_configure_switchable_graphics(false);
++
++ /* Configure muxes */
++ tmp = inl(DEFAULT_GPIOBASE + GP_LVL);
++ tmp = tmp | HYBRID_GRAPHICS_GP_LVL_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_LVL);
++
++ tmp = inl(DEFAULT_GPIOBASE + GP_LVL2);
++ tmp = tmp | HYBRID_GRAPHICS_GP_LVL2_BITS;
++ outl(tmp, DEFAULT_GPIOBASE + GP_LVL2);
++}
++
++static void hybrid_graphics_switch_to_dual_graphics(void)
++{
++ /* Enable switchable graphics */
++ hybrid_graphics_configure_switchable_graphics(true);
++}
++
+ static void default_southbridge_gpio_setup(void)
+ {
+ outl(0x197e23fe, DEFAULT_GPIOBASE + GP_IO_USE_SEL);
+@@ -95,6 +208,31 @@ void mainboard_romstage_entry(unsigned long bist)
+
+ default_southbridge_gpio_setup();
+
++ uint8_t hybrid_graphics_mode = HYBRID_GRAPHICS_INTEGRATED_ONLY;
++ get_option(&hybrid_graphics_mode, "hybrid_graphics_mode");
++
++ /* Set up hybrid graphics */
++ hybrid_graphics_set_up_gpio();
++ if (hybrid_graphics_installed()) {
++ /* Select appropriate hybrid graphics device */
++ printk(BIOS_DEBUG, "Hybrid graphics available, setting mode %d\n", hybrid_graphics_mode);
++ if (hybrid_graphics_mode == HYBRID_GRAPHICS_INTEGRATED_ONLY)
++ hybrid_graphics_switch_to_integrated_graphics();
++ else if (hybrid_graphics_mode == HYBRID_GRAPHICS_DISCRETE_ONLY)
++ hybrid_graphics_switch_to_discrete_graphics();
++ else if (hybrid_graphics_mode == HYBRID_GRAPHICS_SWITCHABLE)
++ hybrid_graphics_switch_to_integrated_graphics();
++ /* Switchable graphics are fully enabled after raminit */
++ /* FIXME
++ * Enabling switchable graphics prevents bootup!
++ * Debug and fix appropriately...
++ */
++ }
++ else {
++ printk(BIOS_DEBUG, "Hybrid graphics not installed\n");
++ hybrid_graphics_switch_to_integrated_graphics();
++ }
++
+ /* ASPM related setting, set early by original BIOS. */
+ DMIBAR16(0x204) &= ~(3 << 10);
+
+@@ -174,6 +312,11 @@ void mainboard_romstage_entry(unsigned long bist)
+ outl(inl(DEFAULT_GPIOBASE + 0x38) & ~0x400, DEFAULT_GPIOBASE + 0x38);
+
+ cbmem_initted = !cbmem_recovery(s3resume);
++
++ if (hybrid_graphics_installed())
++ if (hybrid_graphics_mode == HYBRID_GRAPHICS_SWITCHABLE)
++ hybrid_graphics_switch_to_dual_graphics();
++
+ #if CONFIG_HAVE_ACPI_RESUME
+ /* If there is no high memory area, we didn't boot before, so
+ * this is not a resume. In that case we just create the cbmem toc.
+--
+2.9.2
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
new file mode 100644
index 00000000..49b9549a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
@@ -0,0 +1,35 @@
+From 873402fb594f06e748563ebf3abc7970613b9bda Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 8 Aug 2016 23:55:13 +0200
+Subject: [PATCH] make 256M vram the default for gm45 laptops
+
+Change-Id: Id213807d1ed3260846118f69b459bcad7a146c30
+
+diff --git a/src/mainboard/lenovo/t400/cmos.default b/src/mainboard/lenovo/t400/cmos.default
+index 98ce970..90d796f 100644
+--- a/src/mainboard/lenovo/t400/cmos.default
++++ b/src/mainboard/lenovo/t400/cmos.default
+@@ -13,4 +13,5 @@ sticky_fn=Disable
+ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
+-hybrid_graphics_mode=Integrated Only
+\ No newline at end of file
++hybrid_graphics_mode=Integrated Only
++gfx_uma_size=256M
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/x200/cmos.default b/src/mainboard/lenovo/x200/cmos.default
+index 1d7b420..ec7ab46 100644
+--- a/src/mainboard/lenovo/x200/cmos.default
++++ b/src/mainboard/lenovo/x200/cmos.default
+@@ -13,4 +13,4 @@ sticky_fn=Disable
+ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
+-gfx_uma_size=32M
+\ No newline at end of file
++gfx_uma_size=256M
+\ No newline at end of file
+--
+2.9.2
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
new file mode 100644
index 00000000..76463937
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
@@ -0,0 +1,27 @@
+From 99b8fb271fd244d8e349ca956819c7e1b3420d80 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 8 Aug 2016 21:51:34 +0200
+Subject: [PATCH] hardcode use on intel integrated graphic device on t400
+
+Change-Id: I2ff2d93b024866063715d26aedf510a9753a5445
+---
+ src/mainboard/lenovo/t400/romstage.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/mainboard/lenovo/t400/romstage.c b/src/mainboard/lenovo/t400/romstage.c
+index 147131f..1316d69 100644
+--- a/src/mainboard/lenovo/t400/romstage.c
++++ b/src/mainboard/lenovo/t400/romstage.c
+@@ -208,7 +208,8 @@ void main(unsigned long bist)
+ default_southbridge_gpio_setup();
+
+ uint8_t hybrid_graphics_mode = HYBRID_GRAPHICS_INTEGRATED_ONLY;
+- get_option(&hybrid_graphics_mode, "hybrid_graphics_mode");
++ /* hardcode use of integrated graphic device for libreboot */
++ /* get_option(&hybrid_graphics_mode, "hybrid_graphics_mode"); */
+
+ /* Set up hybrid graphics */
+ hybrid_graphics_set_up_gpio();
+--
+2.9.2
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/INFO
new file mode 100644
index 00000000..9ef6d54a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/INFO
@@ -0,0 +1,8 @@
+# NOTE: merged upstream already
+printf "mainboard/lenovo/t400: Add initial hybrid graphics support\n"
+git am "../resources/libreboot/patch/misc/0001-mainboard-lenovo-t400-Add-initial-hybrid-graphics-su.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/19/9319/18 && git cherry-pick FETCH_HEAD
+
+printf "NOTFORMERGE: lenovo/t400: hard-code enable integrated-only video\n"
+git am "../resources/libreboot/patch/misc/0002-NOTFORMERGE-lenovo-t400-hard-code-enable-integrated-.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/50/10550/1 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/reused.list
new file mode 100644
index 00000000..4ea9a7ad
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/reused.list
@@ -0,0 +1,4 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/INFO
new file mode 100644
index 00000000..0537bbc8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/INFO
@@ -0,0 +1,4 @@
+# NOTE: remove this when updating coreboot. This has been merged upstream
+printf "ThinkPad T500 (depends on T400 patch)\n"
+git am "../resources/libreboot/patch/misc/0008-lenovo-t500-Add-clone-of-Lenovo-T400.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/45/10545/1 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/INFO
new file mode 100644
index 00000000..0537bbc8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/INFO
@@ -0,0 +1,4 @@
+# NOTE: remove this when updating coreboot. This has been merged upstream
+printf "ThinkPad T500 (depends on T400 patch)\n"
+git am "../resources/libreboot/patch/misc/0008-lenovo-t500-Add-clone-of-Lenovo-T400.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/45/10545/1 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/reused.list
new file mode 100644
index 00000000..59e0a36a
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/reused.list
@@ -0,0 +1,7 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0001-Revert-hybrid-driver.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-make-256M-vram-the-default-for-gm45-laptops.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-hardcode-use-on-intel-integrated-graphic-device-on-t.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/INFO
new file mode 100644
index 00000000..220b8583
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/INFO
@@ -0,0 +1,5 @@
+# NOTE: remove this when updating to the latest version of coreboot. this patch
+# makes the patch below redundant: https://review.coreboot.org/#/c/12814/
+printf "northbridge/gm45/raminit.c: enable GS45 high-perf (i.e. add X200S support to libreboot)\n"
+git am "../resources/libreboot/patch/misc/0006-northbridge-gm45-raminit.c-enable-GS45-high-performa.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/35/11135/3 && git cherry-pick FETCH_HEAD
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/reused.list
new file mode 100644
index 00000000..8a98e98c
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/reused.list
@@ -0,0 +1,5 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/reused.list b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/reused.list
new file mode 100644
index 00000000..8a98e98c
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/reused.list
@@ -0,0 +1,5 @@
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
+/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
new file mode 100644
index 00000000..8e5e1dca
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-NOTFORMERGE-ec-lenovo-h8-wlan-trackpoint-touchpad-bl.patch
@@ -0,0 +1,88 @@
+From 63db6e96d846b8cab2df30afdccc6b6b18232e33 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <info@minifree.org>
+Date: Mon, 13 Oct 2014 00:14:53 +0100
+Subject: [PATCH] NOTFORMERGE: ec/lenovo/h8:
+ wlan/trackpoint/touchpad/bluetooth/wwan
+
+Permanently enable them.
+
+Change-Id: Ic76ab9ab9c865f30312378e18af58bece6c3260a
+Signed-off-by: Leah Rowe <info@minifree.org>
+---
+ src/ec/lenovo/h8/h8.c | 21 +++++++++++----------
+ src/ec/lenovo/pmh7/pmh7.c | 11 ++++-------
+ 2 files changed, 15 insertions(+), 17 deletions(-)
+
+diff --git a/src/ec/lenovo/h8/h8.c b/src/ec/lenovo/h8/h8.c
+index 943bdd4..32285ac 100644
+--- a/src/ec/lenovo/h8/h8.c
++++ b/src/ec/lenovo/h8/h8.c
+@@ -252,9 +252,11 @@ static void h8_enable(struct device *dev)
+
+ ec_write(H8_FAN_CONTROL, H8_FAN_CONTROL_AUTO);
+
+- if (get_option(&val, "wlan") != CB_SUCCESS)
+- val = 1;
+- h8_wlan_enable(val);
++ // Permanently enable wifi
++ // Intel wifi could be a security risk because it uses firmware. Wlan chip has DMA
++ // and could leak data over a side-channel. Using another manufacturer is recommended.
++ // see http://libreboot.org/docs/index.html#recommended_wifi
++ h8_wlan_enable(1);
+
+ h8_trackpoint_enable(1);
+ h8_usb_power_enable(1);
+@@ -262,14 +264,13 @@ static void h8_enable(struct device *dev)
+ if (get_option(&val, "volume") == CB_SUCCESS && !acpi_is_wakeup_s3())
+ ec_write(H8_VOLUME_CONTROL, val);
+
+- if (get_option(&val, "bluetooth") != CB_SUCCESS)
+- val = 1;
+- h8_bluetooth_enable(val);
+-
+- if (get_option(&val, "wwan") != CB_SUCCESS)
+- val = 1;
++ // Permanently enable bluetooth.
++ // NOTE: bluetooth is a potential security risk. Physical removal of the bluetooth module is recommended.
++ h8_bluetooth_enable(1);
+
+- h8_wwan_enable(val);
++ // Permanently enable wwan.
++ // NOTE: wwan is a security risk (remove access plus DMA). Physical removal of both the wwan and sim card is recommended.
++ h8_wwan_enable(1);
+
+ if (conf->has_uwb) {
+ if (get_option(&val, "uwb") != CB_SUCCESS)
+diff --git a/src/ec/lenovo/pmh7/pmh7.c b/src/ec/lenovo/pmh7/pmh7.c
+index b2c3c08..1570cd6 100644
+--- a/src/ec/lenovo/pmh7/pmh7.c
++++ b/src/ec/lenovo/pmh7/pmh7.c
+@@ -102,7 +102,6 @@ static void enable_dev(struct device *dev)
+ {
+ struct ec_lenovo_pmh7_config *conf = dev->chip_info;
+ struct resource *resource;
+- u8 val;
+
+ resource = new_resource(dev, EC_LENOVO_PMH7_INDEX);
+ resource->flags = IORESOURCE_IO | IORESOURCE_FIXED;
+@@ -114,13 +113,11 @@ static void enable_dev(struct device *dev)
+ pmh7_backlight_enable(conf->backlight_enable);
+ pmh7_dock_event_enable(conf->dock_event_enable);
+
+- if (get_option(&val, "touchpad") != CB_SUCCESS)
+- val = 1;
+- pmh7_touchpad_enable(val);
++ // Permanently enable touchpad
++ pmh7_touchpad_enable(1);
+
+- if (get_option(&val, "trackpoint") != CB_SUCCESS)
+- val = 1;
+- pmh7_trackpoint_enable(val);
++ // Permanently enable trackpoint
++ pmh7_trackpoint_enable(1);
+ }
+
+ struct chip_operations ec_lenovo_pmh7_ops = {
+--
+1.9.1
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
new file mode 100644
index 00000000..046192dd
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-add-acpi-c3-cpu-c4-state-for-gm45-thinpads.patch
@@ -0,0 +1,45 @@
+From c63113e56ad2d5f6b318a837e4345e0e962a5c1b Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Wed, 4 May 2016 22:49:07 +0200
+Subject: [PATCH 1/1] add acpi c3 / cpu c4 state for gm45 thinpads
+
+---
+ src/mainboard/lenovo/t400/cstates.c | 5 +++++
+ src/mainboard/lenovo/x200/cstates.c | 5 +++++
+ 2 files changed, 10 insertions(+)
+
+diff --git a/src/mainboard/lenovo/t400/cstates.c b/src/mainboard/lenovo/t400/cstates.c
+index 827f76e..7d92d6f 100644
+--- a/src/mainboard/lenovo/t400/cstates.c
++++ b/src/mainboard/lenovo/t400/cstates.c
+@@ -27,6 +27,11 @@ static acpi_cstate_t cst_entries[] = {
+ /* acpi C2 / cpu C2 */
+ 2, 0x01, 500,
+ { ACPI_ADDRESS_SPACE_FIXED, 1, 2, { 1 }, 0x10, 0 }
++ },
++ {
++ /* acpi C3 / cpu C4 */
++ 3, 0x02, 300,
++ { ACPI_ADDRESS_SPACE_FIXED, 1, 2, { 1 }, 0x30, 0 }
+ },
+ };
+
+diff --git a/src/mainboard/lenovo/x200/cstates.c b/src/mainboard/lenovo/x200/cstates.c
+index 827f76e..7d92d6f 100644
+--- a/src/mainboard/lenovo/x200/cstates.c
++++ b/src/mainboard/lenovo/x200/cstates.c
+@@ -27,6 +27,11 @@ static acpi_cstate_t cst_entries[] = {
+ /* acpi C2 / cpu C2 */
+ 2, 0x01, 500,
+ { ACPI_ADDRESS_SPACE_FIXED, 1, 2, { 1 }, 0x10, 0 }
++ },
++ {
++ /* acpi C3 / cpu C4 */
++ 3, 0x02, 300,
++ { ACPI_ADDRESS_SPACE_FIXED, 1, 2, { 1 }, 0x30, 0 }
+ },
+ };
+
+--
+2.8.2
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
new file mode 100644
index 00000000..61b36eb6
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-gm45-gma.c-clean-up-some-registers.patch
@@ -0,0 +1,229 @@
+From 79f4b168666e484191ed3196dffe691953ee783b Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 15 Aug 2016 00:04:34 +0200
+Subject: [PATCH] gm45/gma.c: clean up some registers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+According to "G45: Volume 3: Display Register
+Intel ® 965G Express Chipset Family and Intel ®
+G35 Express Chipset Graphics Controller" some registries
+are set incorrectly in gm45/gma.c.
+
+Some values are changed after comparing them with the values
+the i915 linux kernel (3.13 was used) module sets while modesetting.
+The values were obtained using 'intel_reg' from intel-gpu-tools,
+during a normal boot and with 'nomodeset' as a kernel argument.
+
+Some registers that don't exist on gm45 are set in gma.c, which is
+probably the result of copying code from a more recent intel
+northbridge.
+
+The result is that that gm45 laptops with wxga displays still work as
+before. Laptops with wxga+ displays previously did not display anything
+and now have a horizontal 20% strip of working display.
+
+TEST: build with native graphic init and flash on a gm45 target, like
+lenovo x200.
+
+Change-Id: If66b60c7189997c558270f9e474851fe7e2219f1
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 110 +++++++--------------------------------
+ 1 file changed, 18 insertions(+), 92 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index a89f9bb..b02c89b 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,60 +47,6 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void power_port(u8 *mmio)
+-{
+- read32(mmio + 0x00061100); // = 0x00000000
+- write32(mmio + 0x00061100, 0x00000000);
+- write32(mmio + 0x00061100, 0x00010000);
+- read32(mmio + 0x00061100); // = 0x00010000
+- read32(mmio + 0x00061100); // = 0x00010000
+- read32(mmio + 0x00061100); // = 0x00000000
+- write32(mmio + 0x00061100, 0x00000000);
+- read32(mmio + 0x00061100); // = 0x00000000
+- read32(mmio + 0x00064200); // = 0x0000001c
+- write32(mmio + 0x00064210, 0x8004003e);
+- write32(mmio + 0x00064214, 0x80060002);
+- write32(mmio + 0x00064218, 0x01000000);
+- read32(mmio + 0x00064210); // = 0x5144003e
+- write32(mmio + 0x00064210, 0x5344003e);
+- read32(mmio + 0x00064210); // = 0x0144003e
+- write32(mmio + 0x00064210, 0x8074003e);
+- read32(mmio + 0x00064210); // = 0x5144003e
+- read32(mmio + 0x00064210); // = 0x5144003e
+- write32(mmio + 0x00064210, 0x5344003e);
+- read32(mmio + 0x00064210); // = 0x0144003e
+- write32(mmio + 0x00064210, 0x8074003e);
+- read32(mmio + 0x00064210); // = 0x5144003e
+- read32(mmio + 0x00064210); // = 0x5144003e
+- write32(mmio + 0x00064210, 0x5344003e);
+- read32(mmio + 0x00064210); // = 0x0144003e
+- write32(mmio + 0x00064210, 0x8074003e);
+- read32(mmio + 0x00064210); // = 0x5144003e
+- read32(mmio + 0x00064210); // = 0x5144003e
+- write32(mmio + 0x00064210, 0x5344003e);
+- write32(mmio + 0x00064f00, 0x0100030c);
+- write32(mmio + 0x00064f04, 0x00b8230c);
+- write32(mmio + 0x00064f08, 0x06f8930c);
+- write32(mmio + 0x00064f0c, 0x09f8e38e);
+- write32(mmio + 0x00064f10, 0x00b8030c);
+- write32(mmio + 0x00064f14, 0x0b78830c);
+- write32(mmio + 0x00064f18, 0x0ff8d3cf);
+- write32(mmio + 0x00064f1c, 0x01e8030c);
+- write32(mmio + 0x00064f20, 0x0ff863cf);
+- write32(mmio + 0x00064f24, 0x0ff803cf);
+- write32(mmio + 0x000c4030, 0x00001000);
+- read32(mmio + 0x00044000); // = 0x00000000
+- write32(mmio + 0x00044030, 0x00001000);
+- read32(mmio + 0x00061150); // = 0x0000001c
+- write32(mmio + 0x00061150, 0x0000089c);
+- write32(mmio + 0x000fcc00, 0x01986f00);
+- write32(mmio + 0x000fcc0c, 0x01986f00);
+- write32(mmio + 0x000fcc18, 0x01986f00);
+- write32(mmio + 0x000fcc24, 0x01986f00);
+- read32(mmio + 0x00044000); // = 0x00000000
+- read32(mmio + LVDS); // = 0x40000002
+-}
+-
+ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+@@ -150,8 +96,6 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
+- power_port(mmio);
+-
+ intel_gmbus_read_edid(mmio + GMBUS0, 3, 0x50, edid_data, 128);
+ decode_edid(edid_data,
+ sizeof(edid_data), &edid);
+@@ -277,28 +221,32 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ (hpolarity << 20) | (vpolarity << 21)
+ | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
+ | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
+- | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL);
++ | LVDS_ENABLE_DITHER
++ | LVDS_CLOCK_A_POWERUP_ALL
++ | LVDS_PIPE(0));
+ mdelay(1);
+ write32(mmio + PP_CONTROL, PANEL_UNLOCK_REGS
+ | (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
+ write32(mmio + FP0(0),
+ ((pixel_n - 2) << 16)
+- | ((pixel_m1 - 2) << 8) | pixel_m2);
++ | ((pixel_m1 - 2) << 8) | (pixel_m2 - 2));
+ write32(mmio + DPLL(0),
+ DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
++ | DPLL_VGA_MODE_DIS
+ | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
+ : DPLLB_LVDS_P2_CLOCK_DIV_14)
+ | (0x10000 << (pixel_p1 - 1))
+ | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
+- | (0x1 << (pixel_p1 - 1)));
++ | (6 << 9));
+ mdelay(1);
+ write32(mmio + DPLL(0),
+ DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
++ | DPLL_VGA_MODE_DIS
+ | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
+ : DPLLB_LVDS_P2_CLOCK_DIV_14)
+ | (0x10000 << (pixel_p1 - 1))
+ | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
+- | (0x1 << (pixel_p1 - 1)));
++ | (6 << 9));
+ /* Re-lock the registers. */
+ write32(mmio + PP_CONTROL,
+ (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
+@@ -307,7 +255,9 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ (hpolarity << 20) | (vpolarity << 21)
+ | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
+ | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
+- | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL);
++ | LVDS_CLOCK_A_POWERUP_ALL
++ | LVDS_ENABLE_DITHER
++ | LVDS_PIPE(0));
+
+ write32(mmio + HTOTAL(0),
+ ((hactive + right_border + hblank - 1) << 16)
+@@ -324,7 +274,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- (vactive + bottom_border + vfront_porch + vsync - 1)
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
+ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+@@ -335,7 +285,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ | (vactive - 1));
+ write32(mmio + PF_CTL(0), 0);
+ write32(mmio + PF_WIN_SZ(0), 0);
+- write32(mmio + PFIT_CONTROL, 0x20000000);
++ write32(mmio + PFIT_CONTROL, 0);
+ } else {
+ write32(mmio + PIPESRC(0), (639 << 16) | 399);
+ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+@@ -362,7 +312,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
+- write32(mmio + VGACNTRL, 0xc4008e | VGA_DISP_DISABLE);
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
+ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
+ | DISPPLANE_BGRX888);
+ mdelay(1);
+@@ -370,37 +320,13 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ write32(mmio + VGACNTRL, 0xc4008e);
+ }
+
+- write32(mmio + TRANS_HTOTAL(0),
+- ((hactive + right_border + hblank - 1) << 16)
+- | (hactive - 1));
+- write32(mmio + TRANS_HBLANK(0),
+- ((hactive + right_border + hblank - 1) << 16)
+- | (hactive + right_border - 1));
+- write32(mmio + TRANS_HSYNC(0),
+- ((hactive + right_border + hfront_porch + hsync - 1) << 16)
+- | (hactive + right_border + hfront_porch - 1));
+-
+- write32(mmio + TRANS_VTOTAL(0),
+- ((vactive + bottom_border + vblank - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + TRANS_VBLANK(0),
+- ((vactive + bottom_border + vblank - 1) << 16)
+- | (vactive + bottom_border - 1));
+- write32(mmio + TRANS_VSYNC(0),
+- (vactive + bottom_border + vfront_porch + vsync - 1)
+- | (vactive + bottom_border + vfront_porch - 1));
+-
+- write32(mmio + 0x00060100, 0xb01c4000);
+- write32(mmio + 0x000f000c, 0xb01a2050);
+- mdelay(1);
+- write32(mmio + TRANSCONF(0), TRANS_ENABLE | TRANS_6BPC
+- );
+- write32(mmio + LVDS,
+- LVDS_PORT_ENABLE
++ write32(mmio + LVDS, LVDS_PORT_ENABLE
+ | (hpolarity << 20) | (vpolarity << 21)
+ | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
+ | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
+- | LVDS_BORDER_ENABLE | LVDS_CLOCK_A_POWERUP_ALL);
++ | LVDS_CLOCK_A_POWERUP_ALL
++ | LVDS_ENABLE_DITHER
++ | LVDS_PIPE(0));
+
+ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
new file mode 100644
index 00000000..d89e4884
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-nb-intel-gm45-Fix-IOMMU.patch
@@ -0,0 +1,50 @@
+From 0821d0290e7e17e375ffdb48a86b56504db4f77e Mon Sep 17 00:00:00 2001
+From: Damien Zammit <damien@zamaudio.com>
+Date: Sat, 27 Aug 2016 00:35:48 +1000
+Subject: [PATCH] nb/intel/gm45: Fix IOMMU
+
+Previously the ME was being reported as present in ACPI
+even when it's firmware was missing. Now we do a check via the pci device
+(HECI) to verify if the ME is there or not.
+
+Note that this test could fail if ME is present but disabled in devicetree,
+but in that case you won't see it in the lspci tree anyway so it shouldn't
+be an issue.
+
+Change-Id: Ib692d476d85236b4886ecf3d6e6814229f441de0
+Signed-off-by: Damien Zammit <damien@zamaudio.com>
+---
+ src/northbridge/intel/gm45/acpi.c | 3 ++-
+ src/northbridge/intel/gm45/iommu.c | 2 ++
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/acpi.c b/src/northbridge/intel/gm45/acpi.c
+index 8990c3b..b90afca 100644
+--- a/src/northbridge/intel/gm45/acpi.c
++++ b/src/northbridge/intel/gm45/acpi.c
+@@ -72,7 +72,8 @@ unsigned long acpi_fill_mcfg(unsigned long current)
+
+ static unsigned long acpi_fill_dmar(unsigned long current)
+ {
+- int me_active = (dev_find_slot(0, PCI_DEVFN(3, 0)) != NULL);
++ int me_active = (dev_find_slot(0, PCI_DEVFN(3, 0)) != NULL) &&
++ (pci_read_config8(dev_find_slot(0, PCI_DEVFN(3, 0)), PCI_CLASS_REVISION) != 0xff);
+ int stepping = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), PCI_CLASS_REVISION);
+
+ unsigned long tmp = current;
+diff --git a/src/northbridge/intel/gm45/iommu.c b/src/northbridge/intel/gm45/iommu.c
+index 10548f4..0c3c18e 100644
+--- a/src/northbridge/intel/gm45/iommu.c
++++ b/src/northbridge/intel/gm45/iommu.c
+@@ -40,6 +40,8 @@ void init_iommu()
+ }
+ if (me_active) {
+ MCHBAR32(0x10) = IOMMU_BASE3 | 1; /* ME @ 0:3.0-3 */
++ } else {
++ MCHBAR32(0x10) = 0; /* disable IOMMU for ME */
+ }
+ MCHBAR32(0x20) = IOMMU_BASE4 | 1; /* all other DMA sources */
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch
new file mode 100644
index 00000000..01124c34
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0001-set-default-vram-to-256M.patch
@@ -0,0 +1,38 @@
+From c98d8745d4dca650709e76269cf014e5ffbc1443 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Tue, 9 Aug 2016 00:54:37 +0200
+Subject: [PATCH] set default vram to 256M
+
+Change-Id: Ife906c47f32493d9a647a4f12f25982623eba189
+---
+ src/mainboard/lenovo/t400/cmos.default | 2 +-
+ src/mainboard/lenovo/x200/cmos.default | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/mainboard/lenovo/t400/cmos.default b/src/mainboard/lenovo/t400/cmos.default
+index 5cf3e63..90d796f 100644
+--- a/src/mainboard/lenovo/t400/cmos.default
++++ b/src/mainboard/lenovo/t400/cmos.default
+@@ -14,4 +14,4 @@ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
+ hybrid_graphics_mode=Integrated Only
+-gfx_uma_size=32M
+\ No newline at end of file
++gfx_uma_size=256M
+\ No newline at end of file
+diff --git a/src/mainboard/lenovo/x200/cmos.default b/src/mainboard/lenovo/x200/cmos.default
+index 1d7b420..ec7ab46 100644
+--- a/src/mainboard/lenovo/x200/cmos.default
++++ b/src/mainboard/lenovo/x200/cmos.default
+@@ -13,4 +13,4 @@ sticky_fn=Disable
+ power_management_beeps=Enable
+ low_battery_beep=Enable
+ sata_mode=AHCI
+-gfx_uma_size=32M
+\ No newline at end of file
++gfx_uma_size=256M
+\ No newline at end of file
+--
+2.9.2
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
new file mode 100644
index 00000000..26632b7d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch
@@ -0,0 +1,212 @@
+From 51dc727c71bbb10519a670b83b67a84f704e003a Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Mon, 22 Aug 2016 17:58:46 +0200
+Subject: [PATCH 1/2] gm45/gma.c: use screen on vga connector if connected
+
+The intel x4x and gm45 have very similar integrated graphic devices.
+Currently the x4x native graphic init enables VGA, while gm45 can output
+on LVDS.
+
+This patch reuses the x4x graphic initialisation code
+to enable output on VGA in gm45 in a way that the behavior is similar to vbios:
+If no VGA display is connected the internal LVDS screen is used.
+If an external screen is detected on the VGA port it will be used instead.
+
+Change-Id: I7e9ff793a5384ad8b4220fb1c0d9b28e6cee8391
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 157 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 153 insertions(+), 4 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..74c9bc3 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -47,7 +47,7 @@ void gtt_write(u32 reg, u32 data)
+ write32(res2mmio(gtt_res, reg, 0), data);
+ }
+
+-static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
++static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
+ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+@@ -101,7 +101,7 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ sizeof(edid_data), &edid);
+ mode = &edid.mode;
+
+- /* Disable screen memory to prevent garbage from appearing. */
++ /* Disable screen memory to prevent garbage from appearing. */
+ vga_sr_write(1, vga_sr_read(1) | 0x20);
+
+ hactive = edid.x_resolution;
+@@ -344,6 +344,152 @@ static void intel_gma_init(const struct northbridge_intel_gm45_config *info,
+ }
+ }
+
++static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
++ u8 *mmio)
++{
++
++ int i;
++ u32 hactive, vactive;
++
++ vga_gr_write(0x18, 0);
++
++ write32(mmio + VGA0, 0x31108);
++ write32(mmio + VGA1, 0x31406);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + 0x7041c, 0x0);
++ write32(mmio + DPLL_MD(0), 0x3);
++ write32(mmio + DPLL_MD(1), 0x3);
++
++ vga_misc_write(0x67);
++
++ const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
++ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
++ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
++ 0xff
++ };
++ vga_cr_write(0x11, 0);
++
++ for (i = 0; i <= 0x18; i++)
++ vga_cr_write(i, cr[i]);
++
++ /* Disable screen memory to prevent garbage from appearing. */
++ vga_sr_write(1, vga_sr_read(1) | 0x20);
++
++ hactive = 640;
++ vactive = 400;
++
++ mdelay(1);
++ write32(mmio + FP0(0), 0x31108);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++ mdelay(1);
++ write32(mmio + DPLL(0),
++ DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
++ | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
++ | 0x10601
++ );
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ write32(mmio + HTOTAL(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HBLANK(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++ write32(mmio + HSYNC(0),
++ ((hactive - 1) << 16)
++ | (hactive - 1));
++
++ write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + VSYNC(0),
++ ((vactive - 1) << 16)
++ | (vactive - 1));
++
++ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
++
++ write32(mmio + PF_WIN_POS(0), 0);
++
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0xa0000000);
++
++ mdelay(1);
++
++ write32(mmio + 0x000f000c, 0x00002040);
++ mdelay(1);
++ write32(mmio + 0x000f000c, 0x00002050);
++ write32(mmio + 0x00060100, 0x00044000);
++ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
++ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
++
++ write32(mmio + VGACNTRL, 0x0);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
++ mdelay(1);
++
++ write32(mmio + ADPA, ADPA_DAC_ENABLE
++ | ADPA_PIPE_A_SELECT
++ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
++ | ADPA_CRT_HOTPLUG_ENABLE
++ | ADPA_USE_VGA_HVPOLARITY
++ | ADPA_VSYNC_CNTL_ENABLE
++ | ADPA_HSYNC_CNTL_ENABLE
++ | ADPA_DPMS_ON
++ );
++
++ vga_textmode_init();
++
++ /* Enable screen memory. */
++ vga_sr_write(1, vga_sr_read(1) & ~0x20);
++
++ /* Clear interrupts. */
++ write32(mmio + DEIIR, 0xffffffff);
++ write32(mmio + SDEIIR, 0xffffffff);
++}
++
++/* 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, 128);
++ 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 void gma_pm_init_post_vbios(struct device *const dev)
+ {
+ const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
+@@ -419,8 +565,11 @@ static void gma_func0_init(struct device *dev)
+ printk(BIOS_SPEW,
+ "Initializing VGA without OPROM. MMIO 0x%llx\n",
+ gtt_res->base);
+- intel_gma_init(conf, res2mmio(gtt_res, 0, 0), physbase,
+- pio_res->base, lfb_res->base);
++ if (vga_connected(res2mmio(gtt_res, 0, 0)))
++ gma_init_vga(conf, res2mmio(gtt_res, 0, 0));
++ else
++ gma_init_lvds(conf, res2mmio(gtt_res, 0, 0),
++ physbase, pio_res->base, lfb_res->base);
+ }
+
+ /* Linux relies on VBT for panel info. */
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
new file mode 100644
index 00000000..ef42f3e8
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch
@@ -0,0 +1,379 @@
+From 44423cb3e0118b04739f89409e71a0ed1622ccd2 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Sat, 27 Aug 2016 01:09:19 +0200
+Subject: [PATCH 2/2] nb/gm45/gma.c: enable VESA framebuffer mode on VGA output
+
+This implements "Keep VESA framebuffer" behavior on VGA output of gm45.
+This patch reuses Linux code to compute vga divisors.
+
+Change-Id: I2db5dd9bb1a7e309ca763b1559b89f7f5c8e6d3d
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 251 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 209 insertions(+), 42 deletions(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index 74c9bc3..efaa210 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -25,6 +25,7 @@
+ #include <cpu/x86/msr.h>
+ #include <cpu/x86/mtrr.h>
+ #include <kconfig.h>
++#include <commonlib/helpers.h>
+
+ #include "drivers/intel/gma/i915_reg.h"
+ #include "chip.h"
+@@ -35,6 +36,8 @@
+ #include <pc80/vga.h>
+ #include <pc80/vga_io.h>
+
++#define BASE_FREQUECY 96000
++
+ static struct resource *gtt_res = NULL;
+
+ u32 gtt_read(u32 reg)
+@@ -345,14 +348,38 @@ 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)
++ u8 *mmio, u32 physbase, u16 piobase, u32 lfb)
+ {
+
+ int i;
+- u32 hactive, vactive;
++ u8 edid_data[128];
++ struct edid edid;
++ struct edid_mode *mode;
++ u32 hactive, vactive, right_border, bottom_border;
++ int hpolarity, vpolarity;
++ u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
++ u32 target_frequency;
++ u32 smallest_err = 0xffffffff;
++ u32 pixel_p1 = 1;
++ u32 pixel_n = 1;
++ u32 pixel_m1 = 1;
++ u32 pixel_m2 = 1;
++ u32 link_frequency = info->gfx.link_frequency_270_mhz ? 270000 : 162000;
++ u32 data_m1;
++ u32 data_n1 = 0x00800000;
++ u32 link_m1;
++ u32 link_n1 = 0x00040000;
++
+
+ vga_gr_write(0x18, 0);
+
++ /* Setup GTT. */
++ for (i = 0; i < 0x2000; i++) {
++ outl((i << 2) | 1, piobase);
++ outl(physbase + (i << 12) + 1, piobase + 4);
++ }
++
++
+ write32(mmio + VGA0, 0x31108);
+ write32(mmio + VGA1, 0x31406);
+
+@@ -363,8 +390,7 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+- | ADPA_DPMS_ON
+- );
++ | ADPA_DPMS_ON);
+
+ write32(mmio + 0x7041c, 0x0);
+ write32(mmio + DPLL_MD(0), 0x3);
+@@ -382,95 +408,234 @@ static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
+ for (i = 0; i <= 0x18; i++)
+ vga_cr_write(i, cr[i]);
+
++ udelay(1);
++
++ intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data, 128);
++ 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);
+
+- hactive = 640;
+- vactive = 400;
++ hactive = edid.x_resolution;
++ vactive = edid.y_resolution;
++ right_border = mode->hborder;
++ bottom_border = mode->vborder;
++ hpolarity = (mode->phsync == '-');
++ vpolarity = (mode->pvsync == '-');
++ vsync = mode->vspw;
++ hsync = mode->hspw;
++ vblank = mode->vbl;
++ hblank = mode->hbl;
++ hfront_porch = mode->hso;
++ vfront_porch = mode->vso;
++ target_frequency = mode->pixel_clock;
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ vga_sr_write(1, 1);
++ vga_sr_write(0x2, 0xf);
++ vga_sr_write(0x3, 0x0);
++ vga_sr_write(0x4, 0xe);
++ vga_gr_write(0, 0x0);
++ vga_gr_write(1, 0x0);
++ vga_gr_write(2, 0x0);
++ vga_gr_write(3, 0x0);
++ vga_gr_write(4, 0x0);
++ vga_gr_write(5, 0x0);
++ vga_gr_write(6, 0x5);
++ vga_gr_write(7, 0xf);
++ vga_gr_write(0x10, 0x1);
++ vga_gr_write(0x11, 0);
++
++ edid.bytes_per_line = (edid.bytes_per_line + 63) & ~63;
++
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ write32(mmio + DSPADDR(0), 0);
++ write32(mmio + DSPSTRIDE(0), edid.bytes_per_line);
++ write32(mmio + DSPSURF(0), 0);
++ for (i = 0; i < 0x100; i++)
++ write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
++ } else {
++ vga_textmode_init();
++ }
++
++ u32 candn, candm1, candm2, candp1;
++ for (candn = 1; candn <= 4; candn++) {
++ for (candm1 = 23; candm1 >= 17; candm1--) {
++ for (candm2 = 11; candm2 >= 5; candm2--) {
++ for (candp1 = 8; candp1 >= 1; candp1--) {
++ u32 m = 5 * (candm1 + 2) + (candm2 + 2);
++ u32 p = candp1 * 10; /* 10 == p2 */
++ u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUECY * m, candn + 2);
++ u32 dot = DIV_ROUND_CLOSEST(vco, p);
++ u32 this_err = ABS(dot - target_frequency);
++ if (this_err < smallest_err) {
++ smallest_err= this_err;
++ pixel_n = candn;
++ pixel_m1 = candm1;
++ pixel_m2 = candm2;
++ pixel_p1 = candp1;
++ }
++ }
++ }
++ }
++ }
++
++ if (smallest_err == 0xffffffff) {
++ printk(BIOS_ERR, "Couldn't find GFX clock divisors\n");
++ return;
++ }
++
++ link_m1 = ((uint64_t)link_n1 * mode->pixel_clock) / link_frequency;
++ data_m1 = ((uint64_t)data_n1 * 18 * mode->pixel_clock)
++ / (link_frequency * 8 * 4);
++
++ printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
++ hactive, vactive);
++ printk(BIOS_DEBUG, "Borders %d x %d\n",
++ right_border, bottom_border);
++ printk(BIOS_DEBUG, "Blank %d x %d\n",
++ hblank, vblank);
++ printk(BIOS_DEBUG, "Sync %d x %d\n",
++ hsync, vsync);
++ printk(BIOS_DEBUG, "Front porch %d x %d\n",
++ hfront_porch, vfront_porch);
++ printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
++ ? "Spread spectrum clock\n" : "DREF clock\n"));
++ printk(BIOS_DEBUG, "Polarities %d, %d\n",
++ hpolarity, vpolarity);
++ printk(BIOS_DEBUG, "Data M1=%d, N1=%d\n",
++ data_m1, data_n1);
++ printk(BIOS_DEBUG, "Link frequency %d kHz\n",
++ link_frequency);
++ printk(BIOS_DEBUG, "Link M1=%d, N1=%d\n",
++ link_m1, link_n1);
++ printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
++ pixel_n, pixel_m1, pixel_m2, pixel_p1);
++ printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
++ BASE_FREQUECY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2) / (pixel_n + 2)
++ / (pixel_p1 * 10)));
+
+ mdelay(1);
+- write32(mmio + FP0(0), 0x31108);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + FP0(0), (pixel_n << 16)
++ | (pixel_m1 << 8) | pixel_m2);
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
++
+ mdelay(1);
+- write32(mmio + DPLL(0),
+- DPLL_VCO_ENABLE | DPLLB_MODE_DAC_SERIAL
+- | DPLL_DAC_SERIAL_P2_CLOCK_DIV_10
+- | 0x10601
+- );
++ write32(mmio + DPLL(0), DPLL_VCO_ENABLE
++ | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
++ | (0x10000 << (pixel_p1 - 1))
++ | (6 << 9));
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+ write32(mmio + HTOTAL(0),
+- ((hactive - 1) << 16)
++ ((hactive + right_border + hblank - 1) << 16)
+ | (hactive - 1));
+ write32(mmio + HBLANK(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hblank - 1) << 16)
++ | (hactive + right_border - 1));
+ write32(mmio + HSYNC(0),
+- ((hactive - 1) << 16)
+- | (hactive - 1));
++ ((hactive + right_border + hfront_porch + hsync - 1) << 16)
++ | (hactive + right_border + hfront_porch - 1));
+
+- write32(mmio + VTOTAL(0), ((vactive - 1) << 16)
+- | (vactive - 1));
+- write32(mmio + VBLANK(0), ((vactive - 1) << 16)
++ write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
+ | (vactive - 1));
++ write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
++ | (vactive + bottom_border - 1));
+ write32(mmio + VSYNC(0),
+- ((vactive - 1) << 16)
+- | (vactive - 1));
++ ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
++ | (vactive + bottom_border + vfront_porch - 1));
+
+ write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
+
+ write32(mmio + PF_WIN_POS(0), 0);
+-
+- write32(mmio + PIPESRC(0), (639 << 16) | 399);
+- write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
+- write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
+- write32(mmio + PFIT_CONTROL, 0xa0000000);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
++ | (vactive - 1));
++ write32(mmio + PF_CTL(0), 0);
++ write32(mmio + PF_WIN_SZ(0), 0);
++ write32(mmio + PFIT_CONTROL, 0);
++ } else {
++ write32(mmio + PIPESRC(0), (639 << 16) | 399);
++ write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
++ write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
++ write32(mmio + PFIT_CONTROL, 0x80000000);
++ }
+
+ mdelay(1);
+
++ write32(mmio + PIPE_DATA_M1(0), 0x7e000000 | data_m1);
++ write32(mmio + PIPE_DATA_N1(0), data_n1);
++ write32(mmio + PIPE_LINK_M1(0), link_m1);
++ write32(mmio + PIPE_LINK_N1(0), link_n1);
++
+ write32(mmio + 0x000f000c, 0x00002040);
+ mdelay(1);
+ write32(mmio + 0x000f000c, 0x00002050);
+ write32(mmio + 0x00060100, 0x00044000);
+ mdelay(1);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
++ write32(mmio + 0x000f0008, 0x00000040);
++ write32(mmio + 0x000f000c, 0x00022050);
++ write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+ write32(mmio + PIPECONF(0), PIPECONF_ENABLE
+ | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
+
+- write32(mmio + VGACNTRL, 0x0);
+- write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE | DISPPLANE_BGRX888);
+- mdelay(1);
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
++ write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
++ | DISPPLANE_BGRX888);
++ mdelay(1);
++ } else {
++ write32(mmio + VGACNTRL, 0xc4008e);
++ }
+
+ write32(mmio + ADPA, ADPA_DAC_ENABLE
+ | ADPA_PIPE_A_SELECT
+ | ADPA_CRT_HOTPLUG_MONITOR_COLOR
+ | ADPA_CRT_HOTPLUG_ENABLE
+- | ADPA_USE_VGA_HVPOLARITY
+ | ADPA_VSYNC_CNTL_ENABLE
+ | ADPA_HSYNC_CNTL_ENABLE
+ | ADPA_DPMS_ON
+- );
++ | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
++ ADPA_VSYNC_ACTIVE_HIGH)
++ | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
++ ADPA_HSYNC_ACTIVE_HIGH));
+
+- vga_textmode_init();
++ write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
+
+- /* Enable screen memory. */
++ /* Enable screen memory. */
+ vga_sr_write(1, vga_sr_read(1) & ~0x20);
+
+ /* Clear interrupts. */
+ write32(mmio + DEIIR, 0xffffffff);
+ write32(mmio + SDEIIR, 0xffffffff);
++
++ if (IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)) {
++ memset((void *) lfb, 0,
++ edid.x_resolution * edid.y_resolution * 4);
++ set_vbe_mode_info_valid(&edid, lfb);
++ }
++
++
+ }
+
+ /* compare the header of the vga edid header */
+@@ -480,6 +645,7 @@ 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, 128);
++ 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");
+@@ -566,7 +732,8 @@ static void gma_func0_init(struct device *dev)
+ "Initializing VGA 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));
++ 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);
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
new file mode 100644
index 00000000..fb30c4c2
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0004-gm45-gma.c-use-correct-id-string-for-fake-VBT.patch
@@ -0,0 +1,31 @@
+From d7fe366539f2a492b4a64030618506690bfbb232 Mon Sep 17 00:00:00 2001
+From: Arthur Heymans <arthur@aheymans.xyz>
+Date: Thu, 8 Sep 2016 22:21:54 +0200
+Subject: [PATCH] gm45/gma.c: use correct id string for fake VBT
+
+The correct id string for gm45 is "$VBT CANTIGA ".
+This can be found in the gm45 option rom:
+"strings vbios.bin | grep VBT".
+
+Change-Id: Icd67a87dac774b4b3c211511c784c4fb4e2ea97c
+Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
+---
+ src/northbridge/intel/gm45/gma.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/northbridge/intel/gm45/gma.c b/src/northbridge/intel/gm45/gma.c
+index d5f6471..19bd944 100644
+--- a/src/northbridge/intel/gm45/gma.c
++++ b/src/northbridge/intel/gm45/gma.c
+@@ -425,7 +425,7 @@ static void gma_func0_init(struct device *dev)
+
+ /* Linux relies on VBT for panel info. */
+ generate_fake_intel_oprom(&conf->gfx, dev,
+- "$VBT IRONLAKE-MOBILE");
++ "$VBT CANTIGA ");
+ }
+ }
+
+--
+2.9.3
+
diff --git a/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/INFO b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/INFO
new file mode 100644
index 00000000..220b8583
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/INFO
@@ -0,0 +1,5 @@
+# NOTE: remove this when updating to the latest version of coreboot. this patch
+# makes the patch below redundant: https://review.coreboot.org/#/c/12814/
+printf "northbridge/gm45/raminit.c: enable GS45 high-perf (i.e. add X200S support to libreboot)\n"
+git am "../resources/libreboot/patch/misc/0006-northbridge-gm45-raminit.c-enable-GS45-high-performa.patch"
+# git fetch http://review.coreboot.org/coreboot refs/changes/35/11135/3 && git cherry-pick FETCH_HEAD