summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/google/brya/variants/agah/Makefile.inc1
-rw-r--r--src/mainboard/google/brya/variants/agah/gpio.c4
-rw-r--r--src/mainboard/google/brya/variants/agah/overridetree.cb9
-rw-r--r--src/mainboard/google/brya/variants/agah/variant.c179
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();
+}