From 166387f7903299287cea9537a3758ab66b56f42e Mon Sep 17 00:00:00 2001 From: Tarun Tuli Date: Wed, 29 Mar 2023 13:36:26 +0000 Subject: mb/google/brya/variants/hades: Update GPU power sequencing to add Hades support Add GPU power sequencing changes for the Hades baseboard and variant. Some signals were added, moved or inverted. Based on implementation from Agah. Moved signals: GPIO_1V8_PWR_EN GPP_E11 GPIO_NV33_PWR_EN GPP_E2 GPIO_NV33_PG GPP_E1 New signals: GPIO_NV12_PWR_EN GPP_D0 GPIO_NV12_PG GPP_D1 Inverted signals: GPIO_FBVDD_PWR_EN GPP_A19 ifdef's will be dropped once the Agah variant is retired. BUG=b:269371363 TEST=builds and verified on Agah that DGPU is still detectable (lspci) Change-Id: I0b8efe7a34102cf61d4f784103c4a4f9337213f7 Signed-off-by: Tarun Tuli Reviewed-on: https://review.coreboot.org/c/coreboot/+/73896 Tested-by: build bot (Jenkins) Reviewed-by: Ivy Jian --- src/mainboard/google/brya/acpi/power.asl | 36 ++++- .../google/brya/variants/hades/Makefile.inc | 1 + src/mainboard/google/brya/variants/hades/variant.c | 174 +++++++++++++++++++++ 3 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 src/mainboard/google/brya/variants/hades/variant.c (limited to 'src/mainboard/google/brya') diff --git a/src/mainboard/google/brya/acpi/power.asl b/src/mainboard/google/brya/acpi/power.asl index bd000fbb5b..23759f6b36 100644 --- a/src/mainboard/google/brya/acpi/power.asl +++ b/src/mainboard/google/brya/acpi/power.asl @@ -5,10 +5,23 @@ External (\_SB.PCI0.PMC.IPCS, MethodObj) /* Voltage rail control signals */ + +#if CONFIG(BOARD_GOOGLE_AGAH) #define GPIO_1V8_PWR_EN GPP_F12 -#define GPIO_1V8_PG GPP_E20 + #define GPIO_NV33_PWR_EN GPP_A21 #define GPIO_NV33_PG GPP_A22 +#else +#define GPIO_1V8_PWR_EN GPP_E11 + +#define GPIO_NV33_PWR_EN GPP_E2 +#define GPIO_NV33_PG GPP_E1 +#endif + +#define GPIO_1V8_PG GPP_E20 +#define GPIO_NV12_PWR_EN GPP_D0 +#define GPIO_NV12_PG GPP_D1 + #define GPIO_NVVDD_PWR_EN GPP_E0 #define GPIO_PEXVDD_PWR_EN GPP_E10 #define GPIO_PEXVDD_PG GPP_E17 @@ -197,6 +210,10 @@ Method (PGON, 0, Serialized) /* Assert PERST# */ CTXS (GPIO_GPU_PERST_L) + /* Ramp up 1.2V rail on boards with support */ + STXS (GPIO_NV12_PWR_EN) + GPPL (GPIO_NV12_PG, 1, 5) + /* Ramp up 1.8V rail */ STXS (GPEN) GPPL (GPIO_1V8_PG, 1, 20) @@ -213,8 +230,13 @@ Method (PGON, 0, Serialized) STXS (GPIO_PEXVDD_PWR_EN) GPPL (GPIO_PEXVDD_PG, 1, 5) - /* Ramp up FBVDD rail (active low) */ + /* Ramp up FBVDD rail */ +#if CONFIG(BOARD_GOOGLE_AGAH) CTXS (GPIO_FBVDD_PWR_EN) +#else + STXS (GPIO_FBVDD_PWR_EN) +#endif + GPPL (GPIO_FBVDD_PG, 1, 5) /* All rails are good */ @@ -239,8 +261,12 @@ Method (PGOF, 0, Serialized) CTXS (GPIO_GPU_ALLRAILS_PG) Sleep (1) - /* Ramp down FBVDD (active-low) and let rail discharge to <10% */ + /* Ramp down FBVDD and let rail discharge to <10% */ +#if CONFIG(BOARD_GOOGLE_AGAH) STXS (GPIO_FBVDD_PWR_EN) +#else + CTXS (GPIO_FBVDD_PWR_EN) +#endif GPPL (GPIO_FBVDD_PG, 0, 20) /* Ramp down PEXVDD and let rail discharge to <10% */ @@ -262,6 +288,10 @@ Method (PGOF, 0, Serialized) CTXS (GPEN) GPPL (GPIO_1V8_PG, 0, 20) + /* Ramp down 1.2V rail on boards with support */ + STXS (GPIO_NV12_PWR_EN) + GPPL (GPIO_NV12_PG, 0, 5) + GCOT = Timer GPPS = GPU_POWER_STATE_OFF diff --git a/src/mainboard/google/brya/variants/hades/Makefile.inc b/src/mainboard/google/brya/variants/hades/Makefile.inc index 837101ea25..81d298a708 100644 --- a/src/mainboard/google/brya/variants/hades/Makefile.inc +++ b/src/mainboard/google/brya/variants/hades/Makefile.inc @@ -2,3 +2,4 @@ bootblock-y += gpio.c romstage-y += gpio.c ramstage-y += gpio.c ramstage-y += ramstage.c +ramstage-y += variant.c diff --git a/src/mainboard/google/brya/variants/hades/variant.c b/src/mainboard/google/brya/variants/hades/variant.c new file mode 100644 index 0000000000..6e980977f3 --- /dev/null +++ b/src/mainboard/google/brya/variants/hades/variant.c @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPU_1V2_PWR_EN GPP_D0 +#define GPU_1V2_PG GPP_D1 +#define GPU_1V8_PWR_EN GPP_E11 +#define GPU_1V8_PG GPP_E20 +#define GPU_3V3_PWR_EN GPP_E1 +#define GPU_3V3_PG GPP_E2 +#define NVVDD_PWR_EN GPP_E0 +#define NVVDD_PG GPP_E3 +#define PEXVDD_PWR_EN GPP_E10 +#define PEXVDD_PG GPP_E17 +#define FBVDD_PWR_EN GPP_A19 +#define FBVDD_PG GPP_E4 +#define GPU_PERST_L GPP_B3 +#define GPU_ALLRAILS_PG GPP_E5 + +#define DEFAULT_PG_TIMEOUT_US 20000 + +#define VGAR_BYTE_OFFSET 5 + +/* Maximum size of PCI config space to save. */ +#define GPU_CONFIG_SAVE_SPACE_BYTES 0x100 + +static bool gpu_powered_on; + +struct power_rail_sequence { + const char *name; + + /* This is the GPIO (output) connected to the VR's enable pin. */ + gpio_t pwr_en_gpio; + bool pwr_en_active_low; + + /* This is the GPIO (input) connected to the VR's power-good pin. */ + gpio_t pg_gpio; + + /* Delay after sequencing this rail. */ + unsigned int delay_ms; +}; + +/* In GCOFF exit order (i.e., power-on order) */ +static struct power_rail_sequence gpu_on_seq[] = { + { "GPU 1.2V", GPU_1V2_PWR_EN, false, GPU_1V2_PG, }, + { "GPU 1.8V", GPU_1V8_PWR_EN, false, GPU_1V8_PG, }, + { "GPU 3.3V", GPU_3V3_PWR_EN, false, GPU_3V3_PG, }, + { "NVVDD+MSVDD", NVVDD_PWR_EN, false, NVVDD_PG, }, + { "PEXVDD", PEXVDD_PWR_EN, false, PEXVDD_PG, }, + { "FBVDD", FBVDD_PWR_EN, false, FBVDD_PG, }, +}; + +/* In GCOFF entry order (i.e., power-off order) */ +static struct power_rail_sequence gpu_off_seq[] = { + { "FBVDD", FBVDD_PWR_EN, false, FBVDD_PG, 0,}, + { "PEXVDD", PEXVDD_PWR_EN, false, PEXVDD_PG, 10,}, + { "NVVDD+MSVDD", NVVDD_PWR_EN, false, NVVDD_PG, 2,}, + { "GPU 3.3V", GPU_3V3_PWR_EN, false, GPU_3V3_PG, 4,}, + { "GPU 1.8V", GPU_1V8_PWR_EN, false, GPU_1V8_PG, 0,}, + { "GPU 1.2V", GPU_1V2_PWR_EN, false, GPU_1V2_PG, 0,}, +}; + +enum rail_state { + RAIL_OFF = 0, + RAIL_ON = 1, +}; + +/* Assert the VR's enable pin, and wait until the VR's power-good is asserted. */ +static bool sequence_rail(const struct power_rail_sequence *seq, enum rail_state state) +{ + enum rail_state pwr_en_state = state; + bool result; + + if (seq->pwr_en_active_low) + pwr_en_state = !pwr_en_state; + + gpio_output(seq->pwr_en_gpio, pwr_en_state); + result = wait_us(DEFAULT_PG_TIMEOUT_US, gpio_get(seq->pg_gpio) == state) >= 0; + if (seq->delay_ms) + mdelay(seq->delay_ms); + + return result; +} + +static void dgpu_power_sequence_off(void) +{ + /* Assert reset and clear power-good */ + gpio_output(GPU_PERST_L, 0); + + /* Inform the GPU that the power is no longer good. */ + gpio_output(GPU_ALLRAILS_PG, 0); + + for (size_t i = 0; i < ARRAY_SIZE(gpu_off_seq); i++) { + if (!sequence_rail(&gpu_off_seq[i], RAIL_OFF)) { + printk(BIOS_ERR, "Failed to disable %s rail, continuing!\n", + gpu_off_seq[i].name); + } + } +} + +static void dgpu_power_sequence_on(void) +{ + /* Assert PERST# */ + gpio_output(GPU_PERST_L, 0); + + for (size_t i = 0; i < ARRAY_SIZE(gpu_on_seq); i++) { + if (!sequence_rail(&gpu_on_seq[i], RAIL_ON)) { + printk(BIOS_ERR, "Failed to enable %s rail, sequencing back down!\n", + gpu_on_seq[i].name); + + /* If an error occurred, then perform the power-off sequence and + return early to avoid setting GPU_ALLRAILS_PG and PERST_L. */ + dgpu_power_sequence_off(); + return; + } + } + + /* Set power-good and release PERST# */ + gpio_output(GPU_ALLRAILS_PG, 1); + mdelay(1); + gpio_output(GPU_PERST_L, 1); + + printk(BIOS_INFO, "Sequenced GPU successfully\n"); + mdelay(1); + + gpu_powered_on = true; +} + +void variant_init(void) +{ + if (acpi_is_wakeup_s3()) + return; + + dgpu_power_sequence_on(); +} + +/* + * Pass the specific GPIO names + */ +void variant_fill_ssdt(const struct device *dev) +{ + const int nvvdd_pg_gpio = NVVDD_PG; + const int gpu_1v8_en_gpio = GPU_1V8_PWR_EN; + acpigen_write_scope("\\_SB.PCI0.PEG0.PEGP"); + acpigen_write_method("_INI", 0); + acpigen_write_store_int_to_namestr(nvvdd_pg_gpio, "NVPG"); + acpigen_write_store_int_to_namestr(gpu_1v8_en_gpio, "GPEN"); + acpigen_write_method_end(); + acpigen_write_scope_end(); +} + +void variant_finalize(void) +{ + /* + * Currently the `pch_pirq_init()` function in lpc_lib.c will program + * PIRQ IRQs for all PCI devices discovered during enumeration. This may + * not be correct for all devices, and causes strange behavior with the + * Nvidia dGPU; it will start out with IRQ 11 and then after a + * suspend/resume cycle, it will get programmed back to 16, so the Linux + * kernel must be doing some IRQ sanitization at some point. To fix + * this anomaly, explicitly program the IRQ to 16 (which we know is what + * IRQ it will eventually take). + */ + const struct device *dgpu = DEV_PTR(dgpu); + pci_write_config8(dgpu, PCI_INTERRUPT_LINE, 16); +} -- cgit v1.2.3