diff options
Diffstat (limited to 'src/mainboard/google/brya/variants/agah')
4 files changed, 191 insertions, 2 deletions
diff --git a/src/mainboard/google/brya/variants/agah/Makefile.inc b/src/mainboard/google/brya/variants/agah/Makefile.inc index 139345f260..3d5212f984 100644 --- a/src/mainboard/google/brya/variants/agah/Makefile.inc +++ b/src/mainboard/google/brya/variants/agah/Makefile.inc @@ -6,3 +6,4 @@ romstage-y += gpio.c romstage-y += memory.c ramstage-y += gpio.c +ramstage-y += variant.c diff --git a/src/mainboard/google/brya/variants/agah/gpio.c b/src/mainboard/google/brya/variants/agah/gpio.c index 81c9724d5a..369e373808 100644 --- a/src/mainboard/google/brya/variants/agah/gpio.c +++ b/src/mainboard/google/brya/variants/agah/gpio.c @@ -75,8 +75,8 @@ static const struct pad_config override_gpio_table[] = { /* D16 : ISH_UART0_CTS# ==> NC */ PAD_NC_LOCK(GPP_D16, NONE, LOCK_CONFIG), - /* E0 : SATAXPCIE0 ==> EN_PPVAR_GPU_NVVDD_X_OD */ - PAD_CFG_GPO(GPP_E0, 0, DEEP), + /* E0 : SATAXPCIE0 ==> EN_PPVAR_GPU_NVVDD_X_ODL */ + PAD_CFG_GPO(GPP_E0, 1, DEEP), /* E3 : PROC_GP0 ==> NC */ PAD_NC(GPP_E3, NONE), /* E4 : SATA_DEVSLP0 ==> PG_PPVAR_GPU_FBVDDQ_X_OD */ diff --git a/src/mainboard/google/brya/variants/agah/overridetree.cb b/src/mainboard/google/brya/variants/agah/overridetree.cb index ad23f7b6f1..70bc09289d 100644 --- a/src/mainboard/google/brya/variants/agah/overridetree.cb +++ b/src/mainboard/google/brya/variants/agah/overridetree.cb @@ -58,6 +58,15 @@ chip soc/intel/alderlake }" device domain 0 on + device ref pcie4_0 on + # Enable CPU PCIe RP 1 using CLKREQ 0 and CLKSRC 0 + register "cpu_pcie_rp[CPU_RP(1)]" = "{ + .clk_req = 0, + .clk_src = 0, + .flags = PCIE_RP_LTR | PCIE_RP_AER, + }" + device pci 00.0 alias dgpu on end + end device ref dtt on chip drivers/intel/dptf ## sensor information diff --git a/src/mainboard/google/brya/variants/agah/variant.c b/src/mainboard/google/brya/variants/agah/variant.c new file mode 100644 index 0000000000..979e4e02ef --- /dev/null +++ b/src/mainboard/google/brya/variants/agah/variant.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <acpi/acpigen.h> +#include <baseboard/variants.h> +#include <delay.h> +#include <gpio.h> +#include <timer.h> +#include <types.h> + +#define GPU_1V8_PWR_EN GPP_E18 +#define GPU_1V8_PG GPP_E20 +#define NV33_PWR_EN GPP_A21 +#define NV33_PG GPP_A22 +#define NVVDD_PWR_EN GPP_E0 +#define NVVDD_PG GPP_E16 +#define PEXVDD_PWR_EN GPP_E10 +#define PEXVDD_PG GPP_E17 +#define FBVDD_PWR_EN GPP_A17 +#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; +}; + +/* In GCOFF exit order (i.e., power-on order) */ +static const struct power_rail_sequence gpu_rails[] = { + { "GPU 1.8V", GPU_1V8_PWR_EN, false, GPU_1V8_PG, }, + { "NV3_3", NV33_PWR_EN, false, NV33_PG, }, + { "NVVDD+MSVDD", NVVDD_PWR_EN, true, NVVDD_PG, }, + { "PEXVDD", PEXVDD_PWR_EN, false, PEXVDD_PG, }, + { "FBVDD", FBVDD_PWR_EN, false, FBVDD_PG, }, +}; + +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) +{ + if (seq->pwr_en_active_low) + state = !state; + + gpio_output(seq->pwr_en_gpio, state); + return wait_us(DEFAULT_PG_TIMEOUT_US, gpio_get(seq->pg_gpio) == state) > 0; +} + +static void dgpu_power_sequence_off(void) +{ + /* Assert reset and clear power-good */ + gpio_output(GPU_PERST_L, 0); + mdelay(5); + + /* Inform the GPU that the power is no longer good. */ + gpio_output(GPU_ALLRAILS_PG, 0); + + for (int i = (int)ARRAY_SIZE(gpu_rails) - 1; i >= 0; i--) { + if (!sequence_rail(&gpu_rails[i], RAIL_OFF)) { + printk(BIOS_ERR, "Failed to disable %s rail, continuing!\n", + gpu_rails[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_rails); i++) { + if (!sequence_rail(&gpu_rails[i], RAIL_ON)) { + printk(BIOS_ERR, "Failed to enable %s rail, sequencing back down!\n", + gpu_rails[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"); + gpu_powered_on = true; +} + +void variant_init(void) +{ + if (acpi_is_wakeup_s3()) + return; + + dgpu_power_sequence_on(); +} + +void variant_finalize(void) +{ + if (acpi_is_wakeup_s3() || !gpu_powered_on) + return; + + /* + * Because the dGPU is used here in a way similar to "hybrid graphics" + * modes, it is powered down here. The DRIVERS_GFX_NVIDIA_SAVE_BARS + * option is selected for agah, so the BARs will be saved to ACPI memory + * during its finalize routine. Thus, it is powered down here, as the + * proper resources have already been allocated. + */ + dgpu_power_sequence_off(); + + printk(BIOS_INFO, "GPU power sequenced off.\n"); +} + +/* Save PCI BARs to the ACPI copy of the "saved PCI config space" */ +void variant_fill_ssdt(const struct device *unused) +{ + if (!gpu_powered_on) + return; + + const struct device *dgpu = DEV_PTR(dgpu); + acpigen_write_scope("\\_SB.PCI0.PEG0.PEGP"); + acpigen_write_method("_INI", 0); + { + /* Local0 = VGAR */ + acpigen_write_store(); + acpigen_emit_namestring("VGAR"); + acpigen_emit_byte(LOCAL0_OP); + + /* + * CreateDWordField(Local0, 11, BAR0) + * BAR0 = bases[0] + * CreateDWordField(Local0, 15, BAR1) + * BAR1 = bases[1] + * ... + */ + for (unsigned int idx = PCI_BASE_ADDRESS_0, i = 0; idx <= PCI_BASE_ADDRESS_5; + idx += sizeof(uint32_t), ++i) { + char name[ACPI_NAME_BUFFER_SIZE]; + const struct resource *res; + + res = probe_resource(dgpu, idx); + if (!res) + continue; + + snprintf(name, sizeof(name), "BAR%1d", i); + acpigen_write_create_dword_field(LOCAL0_OP, idx - VGAR_BYTE_OFFSET, + name); + acpigen_write_store_int_to_namestr(res->base & 0xffffffff, name); + } + + /* VGAR = Local0 */ + acpigen_write_store_op_to_namestr(LOCAL0_OP, "VGAR"); + } + + acpigen_write_method_end(); + acpigen_write_scope_end(); +} |