blob: 349dffd0377be3db423999e088af7ca11cc1b28a [file] [log] [blame]
Raul E Rangel6b4b4a82021-05-26 16:58:30 -06001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <acpi/acpi_device.h>
4#include <acpi/acpigen.h>
5#include <acpi/acpigen_pci.h>
6#include <assert.h>
7#include <console/console.h>
8#include <device/device.h>
9#include <device/pci.h>
10#include <device/pci_ids.h>
11#include <device/pci_ops.h>
12#include "chip.h"
13
14/*
15 * This UUID and the resulting ACPI Device Property is defined by the
16 * Power Management for Storage Hardware Devices:
17 *
18 * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro
19 */
20#define PCIE_RTD3_STORAGE_UUID "5025030F-842F-4AB4-A561-99A5189762D0"
21#define PCIE_RTD3_STORAGE_PROPERTY "StorageD3Enable"
22
23/*
24 * Writes the ACPI power resources for a PCI device so it can enter D3Cold.
25 *
26 * If the device is a storage class, then the StorageD3Enable _DSD will
27 * also be added.
28 *
29 * e.g.,
30 *
31 * Scope (\_SB.PCI0.GP14)
32 * {
33 * Device (NVME)
34 * {
35 * Name (_PR0, Package (0x01) // _PR0: Power Resources for D0
36 * {
37 * PRIC
38 * })
39 * Name (_PR3, Package (0x01) // _PR3: Power Resources for D3hot
40 * {
41 * PRIC
42 * })
43 * PowerResource (PRIC, 0x00, 0x0000)
44 * {
45 * Method (_STA, 0, NotSerialized) // _STA: Status
46 * {
47 * ...
48 * }
49 *
50 * Method (_ON, 0, Serialized) // _ON_: Power On
51 * {
52 * ...
53 * }
54 *
55 * Method (_OFF, 0, Serialized) // _OFF: Power Off
56 * {
57 * ...
58 * }
59 * }
60 *
61 * Name (_ADR, 0x0000000000000000) // _ADR: Address
62 * Method (_STA, 0, NotSerialized) // _STA: Status
63 * {
64 * Return (0x0F)
65 * }
66 *
67 * Name (_DSD, Package (0x02) // _DSD: Device-Specific Data
68 * {
69 * ToUUID ("5025030f-842f-4ab4-a561-99a5189762d0"),
70 * Package (0x01)
71 * {
72 * Package (0x02)
73 * {
74 * "StorageD3Enable",
75 * One
76 * }
77 * }
78 * })
79 * }
80 * }
81 */
82static void pcie_rtd3_device_acpi_fill_ssdt(const struct device *dev)
83{
84 struct acpi_dp *dsd, *pkg;
85 const struct drivers_pcie_rtd3_device_config *config = config_of(dev);
86 /* Copy the GPIOs to avoid discards 'const' qualifier error */
87 struct acpi_gpio reset_gpio = config->reset_gpio;
88 struct acpi_gpio enable_gpio = config->enable_gpio;
89 const struct acpi_power_res_params power_res_params = {
90 .reset_gpio = &reset_gpio,
91 .reset_delay_ms = config->reset_delay_ms,
92 .reset_off_delay_ms = config->reset_off_delay_ms,
93 .enable_gpio = &enable_gpio,
94 .enable_delay_ms = config->enable_delay_ms,
95 .enable_off_delay_ms = config->enable_off_delay_ms,
96 .use_gpio_for_status = true,
97 };
98 const char *scope = acpi_device_scope(dev);
99 const char *name = acpi_device_name(dev);
100
101 assert(name);
102 assert(scope);
103
104 printk(BIOS_INFO, "%s.%s: Enable RTD3 for %s (%s)\n", scope, name, dev_path(dev),
105 dev->chip_ops->name);
106
107 acpigen_write_scope(scope);
108 acpigen_write_device(acpi_device_name(dev));
109
110 acpi_device_add_power_res(&power_res_params);
111
112 acpigen_write_ADR_pci_device(dev);
113 acpigen_write_STA(acpi_device_status(dev));
114
115 /* Storage devices won't enter D3 without this property */
116 if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) {
117 dsd = acpi_dp_new_table("_DSD");
118 pkg = acpi_dp_new_table(PCIE_RTD3_STORAGE_UUID);
119 acpi_dp_add_integer(pkg, PCIE_RTD3_STORAGE_PROPERTY, 1);
120 acpi_dp_add_package(dsd, pkg);
121 acpi_dp_write(dsd);
122
123 printk(BIOS_INFO, "%s.%s: Added StorageD3Enable property\n", scope, name);
124 }
125
126 acpigen_write_device_end();
127 acpigen_write_scope_end();
128
129 /* Call the default PCI acpi_fill_ssdt */
130 pci_rom_ssdt(dev);
131}
132
133static const char *pcie_rtd3_device_acpi_name(const struct device *dev)
134{
135 const struct drivers_pcie_rtd3_device_config *config = config_of(dev);
136
137 return config->name;
138}
139
140static struct device_operations pcie_rtd3_device_ops = {
141 .read_resources = pci_dev_read_resources,
142 .set_resources = pci_dev_set_resources,
143 .enable_resources = pci_dev_enable_resources,
144 .init = pci_dev_init,
145 .ops_pci = &pci_dev_ops_pci,
146 .write_acpi_tables = pci_rom_write_acpi_tables,
147 .acpi_fill_ssdt = pcie_rtd3_device_acpi_fill_ssdt,
148 .acpi_name = pcie_rtd3_device_acpi_name,
149};
150
151static void pcie_rtd3_device_enable(struct device *dev)
152{
153 struct drivers_pcie_rtd3_device_config *config = dev ? dev->chip_info : NULL;
154
155 if (!config)
156 return;
157
158 if (dev->path.type != DEVICE_PATH_PCI) {
159 printk(BIOS_ERR, "%s: Invalid device type\n", dev_path(dev));
160 return;
161 }
162
163 dev->ops = &pcie_rtd3_device_ops;
164}
165
166struct chip_operations drivers_pcie_rtd3_device_ops = {
167 CHIP_NAME("PCIe Device w/ Runtime D3")
168 .enable_dev = pcie_rtd3_device_enable
169};