Evgeny Zinoviev has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/32719
Change subject: drivers/apple: Add hybrid graphics driver ......................................................................
drivers/apple: Add hybrid graphics driver
Hybrid graphics driver for Apple MacBook Pro.
Change-Id: I22b66622cd2da0e9951ee726d650d204fbb8a5bc Signed-off-by: Evgeny Zinoviev me@ch1p.io --- A src/drivers/apple/hybrid_graphics/Kconfig A src/drivers/apple/hybrid_graphics/Makefile.inc A src/drivers/apple/hybrid_graphics/chip.h A src/drivers/apple/hybrid_graphics/gmux.c A src/drivers/apple/hybrid_graphics/gmux.h A src/drivers/apple/hybrid_graphics/hybrid_graphics.c A src/drivers/apple/hybrid_graphics/hybrid_graphics.h A src/drivers/apple/hybrid_graphics/romstage.c 8 files changed, 417 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/19/32719/1
diff --git a/src/drivers/apple/hybrid_graphics/Kconfig b/src/drivers/apple/hybrid_graphics/Kconfig new file mode 100644 index 0000000..252373f --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/Kconfig @@ -0,0 +1,3 @@ +config DRIVERS_APPLE_HYBRID_GRAPHICS + bool + default n diff --git a/src/drivers/apple/hybrid_graphics/Makefile.inc b/src/drivers/apple/hybrid_graphics/Makefile.inc new file mode 100644 index 0000000..ea45b45 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/Makefile.inc @@ -0,0 +1,15 @@ +# +# This file is part of the coreboot project. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +romstage-$(CONFIG_DRIVERS_APPLE_HYBRID_GRAPHICS) += gmux.c romstage.c +ramstage-$(CONFIG_DRIVERS_APPLE_HYBRID_GRAPHICS) += gmux.c hybrid_graphics.c diff --git a/src/drivers/apple/hybrid_graphics/chip.h b/src/drivers/apple/hybrid_graphics/chip.h new file mode 100644 index 0000000..39434f8 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/chip.h @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _APPLE_HYBRID_GRAPHICS_CHIP_H_ +#define _APPLE_HYBRID_GRAPHICS_CHIP_H_ + +enum hybrid_graphics_req { + HYBRID_GRAPHICS_INTEGRATED = 0, + HYBRID_GRAPHICS_DISCRETE = 1 +}; + +#define HYBRID_GRAPHICS_DEFAULT_GPU HYBRID_GRAPHICS_INTEGRATED + +struct drivers_apple_hybrid_graphics_config { + unsigned int gmux_indexed; +}; + +#endif /* _APPLE_HYBRID_GRAPHICS_CHIP_H_ */ diff --git a/src/drivers/apple/hybrid_graphics/gmux.c b/src/drivers/apple/hybrid_graphics/gmux.c new file mode 100644 index 0000000..e1f763a --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/gmux.c @@ -0,0 +1,158 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) Canonical Ltd. seth.forshee@canonical.com + * Copyright (C) 2010-2012 Andreas Heider andreas@meetr.de + * Copyright (C) 2015 Lukas Wunner lukas@wunner.de + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <delay.h> +#include <arch/io.h> +#include <device/device.h> +#include "gmux.h" +#include "chip.h" + +static int gmux_index_wait_ready(void) +{ + int i = 200; + u8 gwr = inb(GMUX_IOSTART + GMUX_PORT_WRITE); + + while (i && (gwr & 0x01)) { + inb(GMUX_IOSTART + GMUX_PORT_READ); + gwr = inb(GMUX_IOSTART + GMUX_PORT_WRITE); + udelay(100); + i--; + } + + return !!i; +} + +static int gmux_index_wait_complete(void) +{ + int i = 200; + u8 gwr = inb(GMUX_IOSTART + GMUX_PORT_WRITE); + + while (i && !(gwr & 0x01)) { + gwr = inb(GMUX_IOSTART + GMUX_PORT_WRITE); + udelay(100); + i--; + } + + if (gwr & 0x01) + inb(GMUX_IOSTART + GMUX_PORT_READ); + + return !!i; +} + +u8 gmux_pio_read8(int port) +{ + return inb(GMUX_IOSTART + port); +} + +u8 gmux_index_read8(int port) +{ + u8 val; + + gmux_index_wait_ready(); + outb((port & 0xff), GMUX_IOSTART + GMUX_PORT_READ); + gmux_index_wait_complete(); + val = inb(GMUX_IOSTART + GMUX_PORT_VALUE); + + return val; +} + +void gmux_pio_write8(int port, u8 val) +{ + outb(val, GMUX_IOSTART + port); +} + + +void gmux_index_write8(int port, u8 val) +{ + outb(val, GMUX_IOSTART + GMUX_PORT_VALUE); + gmux_index_wait_ready(); + outb(port & 0xff, GMUX_IOSTART + GMUX_PORT_WRITE); + gmux_index_wait_complete(); +} + +u32 gmux_pio_read32(int port) +{ + return inl(GMUX_IOSTART + port); +} + +u32 gmux_index_read32(int port) +{ + u32 val; + + gmux_index_wait_ready(); + outb((port & 0xff), GMUX_IOSTART + GMUX_PORT_READ); + gmux_index_wait_complete(); + val = inl(GMUX_IOSTART + GMUX_PORT_VALUE); + + return val; +} + +u8 gmux_read8(const struct device *dev, int port) +{ + const struct drivers_apple_hybrid_graphics_config *config = dev->chip_info; + if (config->gmux_indexed) { + return gmux_index_read8(port); + } else { + return gmux_pio_read8(port); + } +} + +void gmux_write8(const struct device *dev, int port, u8 val) +{ + const struct drivers_apple_hybrid_graphics_config *config = dev->chip_info; + if (config->gmux_indexed) { + gmux_index_write8(port, val); + } else { + gmux_pio_write8(port, val); + } +} + +u32 gmux_read32(const struct device *dev, int port) +{ + const struct drivers_apple_hybrid_graphics_config *config = dev->chip_info; + if (config->gmux_indexed) { + return gmux_index_read32(port); + } else { + return gmux_pio_read32(port); + } +} + +void gmux_dgpu_power_enable(const struct device *dev, bool enable) +{ + if (enable) { + gmux_write8(dev, GMUX_PORT_DISCRETE_POWER, 1); + gmux_write8(dev, GMUX_PORT_DISCRETE_POWER, 3); + } else { + gmux_write8(dev, GMUX_PORT_DISCRETE_POWER, 1); + gmux_write8(dev, GMUX_PORT_DISCRETE_POWER, 0); + } +} + +void gmux_switch(const struct device *dev, bool dgpu) +{ + if (dgpu) { + gmux_write8(dev, GMUX_PORT_SWITCH_DDC, 2); + gmux_write8(dev, GMUX_PORT_SWITCH_DISPLAY, 3); + } else { + gmux_write8(dev, GMUX_PORT_SWITCH_DDC, 1); + gmux_write8(dev, GMUX_PORT_SWITCH_DISPLAY, 2); + } +} + + diff --git a/src/drivers/apple/hybrid_graphics/gmux.h b/src/drivers/apple/hybrid_graphics/gmux.h new file mode 100644 index 0000000..18f6722 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/gmux.h @@ -0,0 +1,60 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) Canonical Ltd. seth.forshee@canonical.com + * Copyright (C) 2010-2012 Andreas Heider andreas@meetr.de + * Copyright (C) 2015 Lukas Wunner lukas@wunner.de + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef EC_APPLE_GMUX_H +#define EC_APPLE_GMUX_H + +#define GMUX_PORT_VERSION_MAJOR 0x04 +#define GMUX_PORT_VERSION_MINOR 0x05 +#define GMUX_PORT_VERSION_RELEASE 0x06 + +#define GMUX_PORT_SWITCH_DISPLAY 0x10 +#define GMUX_PORT_SWITCH_DDC 0x28 +#define GMUX_PORT_DISCRETE_POWER 0x50 +#define GMUX_PORT_MAX_BRIGHTNESS 0x70 +#define GMUX_PORT_BRIGHTNESS 0x74 +#define GMUX_PORT_VALUE 0xc2 +#define GMUX_PORT_READ 0xd0 +#define GMUX_PORT_WRITE 0xd4 + +#define GMUX_PORT_INTERRUPT_ENABLE 0x14 +#define GMUX_INTERRUPT_ENABLE 0xff +#define GMUX_INTERRUPT_DISABLE 0x00 + +#define GMUX_BRIGHTNESS_MASK 0x00ffffff +#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK + +#define GMUX_IOSTART 0x700 + +u8 gmux_index_read8(int port); +u8 gmux_pio_read8(int port); +u8 gmux_read8(const struct device *dev, int port); + +void gmux_index_write8(int port, u8 val); +void gmux_pio_write8(int port, u8 val); +void gmux_write8(const struct device *dev, int port, u8 val); + +u32 gmux_index_read32(int port); +u32 gmux_pio_read32(int port); +u32 gmux_read32(const struct device *dev, int port); + +void gmux_switch(const struct device *dev, bool dgpu); +void gmux_dgpu_power_enable(const struct device *dev, bool enable); + +#endif /* EC_APPLE_GMUX_H */ diff --git a/src/drivers/apple/hybrid_graphics/hybrid_graphics.c b/src/drivers/apple/hybrid_graphics/hybrid_graphics.c new file mode 100644 index 0000000..804eb76 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/hybrid_graphics.c @@ -0,0 +1,64 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <types.h> +#include <option.h> +#include <device/device.h> + +#include <southbridge/intel/common/gpio.h> +#include <console/console.h> +#include "chip.h" +#include "gmux.h" + +static void enable_dev(struct device *dev) +{ + printk(BIOS_INFO, "Hybrid graphics enable_dev\n"); + + const struct drivers_lenovo_hybrid_graphics_config *config; + enum hybrid_graphics_req mode; + u8 ver_major, ver_minor, ver_release; + u32 version, max_brightness, brightness; + + /* Don't confuse anyone else and disable the fake device */ + dev->enabled = 0; + + config = dev->chip_info; + if (!config) { + printk(BIOS_INFO, "Hybrid graphics: Not installed\n"); + return; + } + + version = gmux_index_read32(GMUX_PORT_VERSION_MAJOR); + ver_major = (version >> 24) & 0xff; + ver_minor = (version >> 16) & 0xff; + ver_release = (version >> 8) & 0xff; + max_brightness = gmux_index_read32(GMUX_PORT_MAX_BRIGHTNESS); + brightness = gmux_index_read32(GMUX_PORT_BRIGHTNESS) & GMUX_BRIGHTNESS_MASK; + + printk(BIOS_INFO, "gmux version: %d.%d.%d\n", + ver_major, ver_minor, ver_release); + printk(BIOS_INFO, "gmux max brightness: %d\n", max_brightness); + printk(BIOS_INFO, "gmux brightness: %d\n", brightness); + + mode = HYBRID_GRAPHICS_DEFAULT_GPU; + get_option(&mode, "hybrid_graphics_mode"); + + gmux_switch(dev, mode == HYBRID_GRAPHICS_DISCRETE); +} + +struct chip_operations drivers_apple_hybrid_graphics_ops = { + CHIP_NAME("Apple hybrid graphics driver") + .enable_dev = enable_dev +}; diff --git a/src/drivers/apple/hybrid_graphics/hybrid_graphics.h b/src/drivers/apple/hybrid_graphics/hybrid_graphics.h new file mode 100644 index 0000000..782be44 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/hybrid_graphics.h @@ -0,0 +1,24 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRIVERS_APPLE_HYBRID_GRAPHICS_H_ +#define _DRIVERS_APPLE_HYBRID_GRAPHICS_H_ + +#define HYBRID_GRAPHICS_PORT 0xff +#define HYBRID_GRAPHICS_DEVICE 0xf + +void early_hybrid_graphics(bool *enable_igd, bool *enable_peg); + +#endif /* _DRIVERS_APPLE_HYBRID_GRAPHICS_CHIP_H_ */ diff --git a/src/drivers/apple/hybrid_graphics/romstage.c b/src/drivers/apple/hybrid_graphics/romstage.c new file mode 100644 index 0000000..9cd5098 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/romstage.c @@ -0,0 +1,63 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Patrick Rudolph siro@das-labor.org + * Copyright (C) 2019 Evgeny Zinoviev me@ch1p.io + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <types.h> +#include <option.h> +#include <device/device.h> +#include <console/console.h> +#include "hybrid_graphics.h" +#include "chip.h" +#include "gmux.h" + +void early_hybrid_graphics(bool *enable_igd, bool *enable_peg) +{ + const struct drivers_apple_hybrid_graphics_config *config; + const struct device *dev; + + enum hybrid_graphics_req mode = HYBRID_GRAPHICS_DEFAULT_GPU; + + printk(BIOS_INFO, "Hybrid graphics early_hybrid_graphics\n"); + + /* TODO: Use generic device instead of dummy PNP device */ + dev = dev_find_slot_pnp(HYBRID_GRAPHICS_PORT, HYBRID_GRAPHICS_DEVICE); + + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "Hybrid graphics: ERROR\n"); + *enable_igd = true; + *enable_peg = false; + return; + } + + config = dev->chip_info; + + get_option(&mode, "hybrid_graphics_mode"); + + if (mode == HYBRID_GRAPHICS_DISCRETE) { + printk(BIOS_DEBUG, "Hybrid graphics:" + " Disabling integrated GPU.\n"); + + *enable_igd = false; + *enable_peg = true; + } else if (mode == HYBRID_GRAPHICS_INTEGRATED) { + printk(BIOS_DEBUG, "Hybrid graphics:" + " Disabling discrete GPU.\n"); + + *enable_igd = true; + *enable_peg = false; + } + + gmux_dgpu_power_enable(dev, *enable_peg); +}