Patrick Rudolph (siro@das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/12897
-gerrit
commit ba7ac2235606b8bac2087b6196c748a8ba4801c2 Author: Patrick Rudolph siro@das-labor.org Date: Sat Dec 26 08:27:20 2015 +0100
device/device: handle multiple VGA devices
Add nvram options "vga_primary_is_peg" and "vga_secondary_powersave" to switch between VGA devices.
Both options only affects systems where an onboard and a PEG device is installed. Systems with only one VGA device will always use it as the primary VGA device.
vga_primary_is_peg allows to choose the primary VGA device, that is where the VGA Option ROM will be run on. In case of a laptop the panel will be connected to the primary device.
vga_primary_is_peg=0 : Onboard is primary vga_primary_is_peg=1 : Dedicated is primary
vga_secondary_powersave allows to disable secondary VGA devices to save power.
vga_secondary_powersave=0 : Leave secondary VGA devices enabled vga_secondary_powersave=1 : Disable secondary VGA devices
Tested on Lenovo T530 using Nvidia NVS 5400m.
WIP: Do not commit yet !
Change-Id: Ie37ec4aeae8ab49fe8e26438c430911d1815551c Signed-off-by: Patrick Rudolph siro@das-labor.org --- src/device/device.c | 93 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 21 deletions(-)
diff --git a/src/device/device.c b/src/device/device.c index 9ea32cc..5f2a487 100644 --- a/src/device/device.c +++ b/src/device/device.c @@ -50,6 +50,7 @@ #include <arch/ebda.h> #endif #include <timer.h> +#include <option.h>
/** Linked list of ALL devices */ struct device *all_devices = &dev_root; @@ -754,28 +755,52 @@ static void avoid_fixed_resources(struct device *dev) } }
+static struct device *get_next_vga_dev(struct device *dev) +{ + while ((dev = dev_find_class(PCI_CLASS_DISPLAY_VGA << 8, dev))) { + if (!dev->enabled) + continue; + + return dev; + } + return NULL; +} + +/* + * Disables all PCI_CLASS_DISPLAY_VGA devices except the one + * given as argument. + * @param dev_primary The device to ignore + */ +static void disable_secondary_vga_devs(struct device *dev_primary) +{ + struct device *dev = NULL; + + while ((dev = get_next_vga_dev(dev))) { + /* disable unused devices to save power */ + if (dev != dev_primary) { + if (dev->ops && dev->ops->disable) + dev->ops->disable(dev); + else + dev->enabled = 0; + } + } +} + device_t vga_pri = 0; static void set_vga_bridge_bits(void) { - /* - * FIXME: Modify set_vga_bridge() so it is less PCI-centric! - * This function knows too much about PCI stuff, it should be just - * an iterator/visitor. - */ - /* FIXME: Handle the VGA palette snooping. */ struct device *dev, *vga, *vga_onboard; struct bus *bus; + u8 vga_primary_is_peg; + u8 vga_secondary_powersave;
bus = 0; vga = 0; vga_onboard = 0;
dev = NULL; - while ((dev = dev_find_class(PCI_CLASS_DISPLAY_VGA << 8, dev))) { - if (!dev->enabled) - continue; - + while ((dev = get_next_vga_dev(dev))) { printk(BIOS_DEBUG, "found VGA at %s\n", dev_path(dev));
if (dev->on_mainboard) { @@ -788,23 +813,49 @@ static void set_vga_bridge_bits(void) dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO); }
- if (!vga) - vga = vga_onboard; + if ((get_option(&vga_primary_is_peg, "vga_primary_is_peg") != CB_SUCCESS) || + (get_option(&vga_secondary_powersave, "vga_secondary_powersave") != CB_SUCCESS) || + !vga || !vga_onboard) { + /* fallback */ + if (!vga) + vga = vga_onboard; + + if (IS_ENABLED(CONFIG_ONBOARD_VGA_IS_PRIMARY) && vga_onboard) + vga = vga_onboard; + + /* If we prefer plugin VGA over chipset VGA, the chipset might + want to know. */ + if (!IS_ENABLED(CONFIG_ONBOARD_VGA_IS_PRIMARY) && + (vga != vga_onboard) && + vga_onboard) { + printk(BIOS_DEBUG, "Use plugin graphics over integrated.\n"); + + if (vga_onboard->ops && vga_onboard->ops->disable) + vga_onboard->ops->disable(vga_onboard); + else + vga_onboard->enabled = 0; + } + + disable_secondary_vga_devs(vga); + } else { + /* have vga and vga_onboard (two or more VGAs) */
- if (CONFIG_ONBOARD_VGA_IS_PRIMARY && vga_onboard) - vga = vga_onboard; + /* make onboard primary if vga_primary_is_peg is disabled */ + if (vga_primary_is_peg == 0) { + printk(BIOS_DEBUG, "Use integrated graphics over plugin.\n"); + vga = vga_onboard; + }
- /* If we prefer plugin VGA over chipset VGA, the chipset might - want to know. */ - if (!CONFIG_ONBOARD_VGA_IS_PRIMARY && (vga != vga_onboard) && - vga_onboard && vga_onboard->ops && vga_onboard->ops->disable) { - printk(BIOS_DEBUG, "Use plugin graphics over integrated.\n"); - vga_onboard->ops->disable(vga_onboard); + /* disable secondary VGAs if vga_secondary_powersave is enabled */ + if (vga_secondary_powersave == 1) { + printk(BIOS_DEBUG, "Disable secondary graphics to save power.\n"); + disable_secondary_vga_devs(vga); + } }
if (vga) { /* VGA is first add-on card or the only onboard VGA. */ - printk(BIOS_DEBUG, "Setting up VGA for %s\n", dev_path(vga)); + printk(BIOS_DEBUG, "Setting up %s for primary VGA.\n", dev_path(vga)); /* All legacy VGA cards have MEM & I/O space registers. */ vga->command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_IO); vga_pri = vga;