libreboot

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit dff764aef269f9d31113f468ce894dde1f9b10c6
parent 3de8da2ef12bacf3a20ab83c348ac2a679ba1333
Author: Leah Rowe <info@minifree.org>
Date:   Fri,  9 Sep 2016 21:31:03 +0100

gm45: add support for external monitors in grub (patch from Arthur Heymans)

Diffstat:
models.txt | 1+
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/r400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t400_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/t500_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_16mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_4mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0002-gm45-gma.c-use-screen-on-vga-connector-if-connected.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/coreboot/d83b0e9ac4174cca92ac2c3b83a7e8491a9a1ff4/grub/x200_8mb/0003-nb-gm45-gma.c-enable-VESA-framebuffer-mode-on-VGA-ou.patch | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 files changed, 7093 insertions(+), 0 deletions(-)

diff --git a/models.txt b/models.txt @@ -0,0 +1 @@ +http://gagarine.paulk.fr/collins/~paulk/libreboot/cros/models/ 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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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/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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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/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 @@ -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 @@ -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 +