mb/google/fatcat/var/fatcat: Refactor GPIO programming for UFS support
[coreboot.git] / src / mainboard / google / brya / variants / hades / variant.c
blob7a258fbf406b59ec943bb21d20d05f8e238c4ebc
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <acpi/acpi.h>
4 #include <acpi/acpigen.h>
5 #include <baseboard/variants.h>
6 #include <boardid.h>
7 #include <delay.h>
8 #include <device/pci.h>
9 #include <gpio.h>
10 #include <static.h>
11 #include <timer.h>
12 #include <types.h>
14 #define GPU_1V2_PWR_EN GPP_D0
15 #define GPU_1V2_PG GPP_D1
16 #define GPU_1V8_PWR_EN GPP_E11
17 #define GPU_1V8_PG GPP_E20
18 #define GPU_3V3_PWR_EN GPP_E1
19 #define GPU_3V3_PG GPP_E2
20 #define NVVDD_PWR_EN GPP_E0
21 #define NVVDD_PG GPP_E8
22 #define PEXVDD_PWR_EN GPP_E10
23 #define PEXVDD_PG GPP_E17
24 #define FBVDD_PWR_EN GPP_A19
25 #define FBVDD_PG GPP_E4
26 #define GPU_PERST_L GPP_B3
27 #define GPU_ALLRAILS_PG GPP_E5
29 #define DEFAULT_PG_TIMEOUT_US 20000
31 #define VGAR_BYTE_OFFSET 5
33 /* Maximum size of PCI config space to save. */
34 #define GPU_CONFIG_SAVE_SPACE_BYTES 0x100
36 static bool gpu_powered_on;
38 struct power_rail_sequence {
39 const char *name;
41 /* This is the GPIO (output) connected to the VR's enable pin. */
42 gpio_t pwr_en_gpio;
43 bool pwr_en_active_low;
45 /* This is the GPIO (input) connected to the VR's power-good pin. */
46 gpio_t pg_gpio;
48 /* Delay after sequencing this rail. */
49 unsigned int delay_ms;
52 /* In GCOFF exit order (i.e., power-on order) */
53 static struct power_rail_sequence gpu_on_seq[] = {
54 { "GPU 1.2V", GPU_1V2_PWR_EN, false, GPU_1V2_PG, },
55 { "GPU 1.8V", GPU_1V8_PWR_EN, false, GPU_1V8_PG, },
56 { "GPU 3.3V", GPU_3V3_PWR_EN, false, GPU_3V3_PG, },
57 { "NVVDD+MSVDD", NVVDD_PWR_EN, false, NVVDD_PG, },
58 { "PEXVDD", PEXVDD_PWR_EN, false, PEXVDD_PG, },
59 { "FBVDD", FBVDD_PWR_EN, false, FBVDD_PG, },
62 /* In GCOFF entry order (i.e., power-off order) */
63 static struct power_rail_sequence gpu_off_seq[] = {
64 { "FBVDD", FBVDD_PWR_EN, false, FBVDD_PG, 0,},
65 { "PEXVDD", PEXVDD_PWR_EN, false, PEXVDD_PG, 2,},
66 { "NVVDD+MSVDD", NVVDD_PWR_EN, false, NVVDD_PG, 2,},
67 { "GPU 3.3V", GPU_3V3_PWR_EN, false, GPU_3V3_PG, 4,},
68 { "GPU 1.8V", GPU_1V8_PWR_EN, false, GPU_1V8_PG, 0,},
69 { "GPU 1.2V", GPU_1V2_PWR_EN, false, GPU_1V2_PG, 0,},
72 enum rail_state {
73 RAIL_OFF = 0,
74 RAIL_ON = 1,
77 /* Assert the VR's enable pin, and wait until the VR's power-good is asserted. */
78 static bool sequence_rail(const struct power_rail_sequence *seq, enum rail_state state)
80 enum rail_state pwr_en_state = state;
81 bool result;
83 if (seq->pwr_en_active_low)
84 pwr_en_state = !pwr_en_state;
86 gpio_output(seq->pwr_en_gpio, pwr_en_state);
87 result = wait_us(DEFAULT_PG_TIMEOUT_US, gpio_get(seq->pg_gpio) == state) > 0;
88 if (seq->delay_ms)
89 mdelay(seq->delay_ms);
91 return result;
94 static void dgpu_power_sequence_off(void)
96 /* Assert reset and clear power-good */
97 gpio_output(GPU_PERST_L, 0);
99 /* Inform the GPU that the power is no longer good. */
100 gpio_output(GPU_ALLRAILS_PG, 0);
102 for (size_t i = 0; i < ARRAY_SIZE(gpu_off_seq); i++) {
103 if (!sequence_rail(&gpu_off_seq[i], RAIL_OFF)) {
104 printk(BIOS_ERR, "Failed to disable %s rail, continuing!\n",
105 gpu_off_seq[i].name);
110 static void dgpu_power_sequence_on(void)
112 /* Assert PERST# */
113 gpio_output(GPU_PERST_L, 0);
115 for (size_t i = 0; i < ARRAY_SIZE(gpu_on_seq); i++) {
116 if (!sequence_rail(&gpu_on_seq[i], RAIL_ON)) {
117 printk(BIOS_ERR, "Failed to enable %s rail, sequencing back down!\n",
118 gpu_on_seq[i].name);
120 /* If an error occurred, then perform the power-off sequence and
121 return early to avoid setting GPU_ALLRAILS_PG and PERST_L. */
122 dgpu_power_sequence_off();
123 return;
127 /* Set power-good and release PERST# */
128 gpio_output(GPU_ALLRAILS_PG, 1);
129 mdelay(1);
130 gpio_output(GPU_PERST_L, 1);
132 printk(BIOS_INFO, "Sequenced GPU successfully\n");
133 mdelay(1);
135 gpu_powered_on = true;
138 void variant_init(void)
140 if (acpi_is_wakeup_s3())
141 return;
143 dgpu_power_sequence_on();
147 * Pass the specific GPIO names
149 void variant_fill_ssdt(const struct device *dev)
151 const int nvvdd_pg_gpio = NVVDD_PG;
152 const int gpu_1v8_en_gpio = GPU_1V8_PWR_EN;
153 acpigen_write_scope("\\_SB.PCI0.PEG0.PEGP");
154 acpigen_write_method("_INI", 0);
155 acpigen_write_store_int_to_namestr(nvvdd_pg_gpio, "NVPG");
156 acpigen_write_store_int_to_namestr(gpu_1v8_en_gpio, "GPEN");
157 acpigen_write_method_end();
158 acpigen_write_scope_end();
161 void variant_finalize(void)
164 * Currently the `pch_pirq_init()` function in lpc_lib.c will program
165 * PIRQ IRQs for all PCI devices discovered during enumeration. This may
166 * not be correct for all devices, and causes strange behavior with the
167 * Nvidia dGPU; it will start out with IRQ 11 and then after a
168 * suspend/resume cycle, it will get programmed back to 16, so the Linux
169 * kernel must be doing some IRQ sanitization at some point. To fix
170 * this anomaly, explicitly program the IRQ to 16 (which we know is what
171 * IRQ it will eventually take).
173 const struct device *dgpu = DEV_PTR(dgpu);
174 pci_write_config8(dgpu, PCI_INTERRUPT_LINE, 16);