diff options
-rw-r--r-- | src/drivers/apple/hybrid_graphics/Kconfig | 3 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/Makefile.inc | 4 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/acpi/gmux.asl | 39 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/chip.h | 17 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/gmux.c | 138 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/gmux.h | 43 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/hybrid_graphics.c | 50 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/hybrid_graphics.h | 11 | ||||
-rw-r--r-- | src/drivers/apple/hybrid_graphics/romstage.c | 43 |
9 files changed, 348 insertions, 0 deletions
diff --git a/src/drivers/apple/hybrid_graphics/Kconfig b/src/drivers/apple/hybrid_graphics/Kconfig new file mode 100644 index 0000000000..252373fb55 --- /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 0000000000..caef42a351 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/Makefile.inc @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +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/acpi/gmux.asl b/src/drivers/apple/hybrid_graphics/acpi/gmux.asl new file mode 100644 index 0000000000..bf6c8f0e44 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/acpi/gmux.asl @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +Device (GMUX) +{ + Name (_HID, EisaId ("APP000B")) + Name (_CID, "gmux") + Name (_STA, 0x0B) + Name (_CRS, ResourceTemplate () + { + IO (Decode16, + 0x0700, // Range Minimum + 0x07FF, // Range Maximum + 0x01, // Alignment + 0xFF // Length + ) + }) + Name (_PRW, Package (0x02) { 0x16, 0x03 }) + Scope (\_GPE) + { + Method (_L16, 0, NotSerialized) + { + Notify (\_SB.PCI0.LPCB.GMUX, 0x80) + } + } + + Name (GMGP, 0x16) + Method (GMSP, 1, NotSerialized) + { + If (Arg0 == 0) + { + \GP06 |= Arg0 + } + } + + Method (GMLV, 0, NotSerialized) + { + Return (\GP06) + } +} diff --git a/src/drivers/apple/hybrid_graphics/chip.h b/src/drivers/apple/hybrid_graphics/chip.h new file mode 100644 index 0000000000..c7111f98a5 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/chip.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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 { + bool 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 0000000000..e3788b2436 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/gmux.c @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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(u8 port) +{ + return inb(GMUX_IOSTART + port); +} + +u8 gmux_index_read8(u8 port) +{ + u8 val; + + gmux_index_wait_ready(); + outb(port, GMUX_IOSTART + GMUX_PORT_READ); + gmux_index_wait_complete(); + val = inb(GMUX_IOSTART + GMUX_PORT_VALUE); + + return val; +} + +void gmux_pio_write8(u8 port, u8 val) +{ + outb(val, GMUX_IOSTART + port); +} + +void gmux_index_write8(u8 port, u8 val) +{ + outb(val, GMUX_IOSTART + GMUX_PORT_VALUE); + gmux_index_wait_ready(); + outb(port, GMUX_IOSTART + GMUX_PORT_WRITE); + gmux_index_wait_complete(); +} + +u32 gmux_pio_read32(u8 port) +{ + return inl(GMUX_IOSTART + port); +} + +u32 gmux_index_read32(u8 port) +{ + u32 val; + + gmux_index_wait_ready(); + outb(port, 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, u8 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, u8 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, u8 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 0000000000..075f9b6ca5 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/gmux.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef DRIVERS_APPLE_GMUX_H +#define DRIVERS_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(u8 port); +u8 gmux_pio_read8(u8 port); +u8 gmux_read8(const struct device *dev, u8 port); + +void gmux_index_write8(u8 port, u8 val); +void gmux_pio_write8(u8 port, u8 val); +void gmux_write8(const struct device *dev, u8 port, u8 val); + +u32 gmux_index_read32(u8 port); +u32 gmux_pio_read32(u8 port); +u32 gmux_read32(const struct device *dev, u8 port); + +void gmux_switch(const struct device *dev, bool dgpu); +void gmux_dgpu_power_enable(const struct device *dev, bool enable); + +#endif /* DRIVERS_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 0000000000..7ec29fc345 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/hybrid_graphics.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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) +{ + 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 0000000000..af2d56d528 --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/hybrid_graphics.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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 0000000000..8f2667111b --- /dev/null +++ b/src/drivers/apple/hybrid_graphics/romstage.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#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 device *dev; + enum hybrid_graphics_req mode = HYBRID_GRAPHICS_DEFAULT_GPU; + + /* 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; + } + + 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); +} |