blob: e5bbdab2fb22cc0b0efa8abcc20267f8486f40ce [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +01003
4#include <string.h>
5#include <arch/acpi.h>
6#include <arch/acpigen.h>
7#include <device/device.h>
8#include <device/pci.h>
Elyes HAOUAS4b7202e2019-03-16 10:02:31 +01009
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010010#include "pciehp.h"
11
12void intel_acpi_pcie_hotplug_generator(u8 *hotplug_map, int port_number)
13{
14 int port;
15 int have_hotplug = 0;
16
17 for (port = 0; port < port_number; port++) {
18 if (hotplug_map[port]) {
19 have_hotplug = 1;
20 }
21 }
22
23 if (!have_hotplug) {
24 return;
25 }
26
27 for (port = 0; port < port_number; port++) {
28 if (hotplug_map[port]) {
29 char scope_name[] = "\\_SB.PCI0.RP0x";
30 scope_name[sizeof("\\_SB.PCI0.RP0x") - 2] = '1' + port;
31 acpigen_write_scope(scope_name);
32
33 /*
34 Device (SLOT)
35 {
Elyes HAOUASb0f19882018-06-09 11:59:00 +020036 Name (_ADR, 0x00)
37 Method (_RMV, 0, NotSerialized)
38 {
39 Return (0x01)
40 }
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010041 }
42 */
43
44 acpigen_write_device("SLOT");
45
46 acpigen_write_name_byte("_ADR", 0x00);
47
48 acpigen_write_method("_RMV", 0);
49 /* ReturnOp */
50 acpigen_emit_byte (0xa4);
51 /* One */
52 acpigen_emit_byte (0x01);
53 acpigen_pop_len();
54 acpigen_pop_len();
55 acpigen_pop_len();
56 }
57 }
58
59 /* Method (_L01, 0, NotSerialized)
60 {
61 If (\_SB.PCI0.RP04.HPCS)
62 {
63 Sleep (100)
64 Store (0x01, \_SB.PCI0.RP04.HPCS)
65 If (\_SB.PCI0.RP04.PDC)
66 {
67 Store (0x01, \_SB.PCI0.RP04.PDC)
68 Notify (\_SB.PCI0.RP04, 0x00)
69 }
70 }
71 }
72
73 */
74 acpigen_write_scope("\\_GPE");
75 acpigen_write_method("_L01", 0);
76 for (port = 0; port < port_number; port++) {
77 if (hotplug_map[port]) {
78 char reg_name[] = "\\_SB.PCI0.RP0x.HPCS";
79 reg_name[sizeof("\\_SB.PCI0.RP0x") - 2] = '1' + port;
80 acpigen_emit_byte(0xa0); /* IfOp. */
81 acpigen_write_len_f();
82 acpigen_emit_namestring(reg_name);
83
84 /* Sleep (100) */
85 acpigen_emit_byte(0x5b); /* SleepOp. */
86 acpigen_emit_byte(0x22);
87 acpigen_write_byte(100);
88
89 /* Store (0x01, \_SB.PCI0.RP04.HPCS) */
90 acpigen_emit_byte(0x70);
91 acpigen_emit_byte(0x01);
92 acpigen_emit_namestring(reg_name);
93
94 memcpy(reg_name + sizeof("\\_SB.PCI0.RP0x.") - 1, "PDC", 4);
95
96 /* If (\_SB.PCI0.RP04.PDC) */
97 acpigen_emit_byte(0xa0); /* IfOp. */
98 acpigen_write_len_f();
99 acpigen_emit_namestring(reg_name);
100
101 /* Store (0x01, \_SB.PCI0.RP04.PDC) */
102 acpigen_emit_byte(0x70);
103 acpigen_emit_byte(0x01);
104 acpigen_emit_namestring(reg_name);
105
106 reg_name[sizeof("\\_SB.PCI0.RP0x") - 1] = '\0';
107
108 /* Notify(\_SB.PCI0.RP04, 0x00) */
109 acpigen_emit_byte(0x86);
110 acpigen_emit_namestring(reg_name);
111 acpigen_emit_byte(0x00);
112 acpigen_pop_len();
113 acpigen_pop_len();
114 }
115 }
116 acpigen_pop_len();
117 acpigen_pop_len();
118
119}
120
121static void slot_dev_read_resources(struct device *dev)
122{
123 struct resource *resource;
124
125 resource = new_resource(dev, 0x10);
126 resource->size = 1 << 23;
127 resource->align = 22;
128 resource->gran = 22;
129 resource->limit = 0xffffffff;
130 resource->flags |= IORESOURCE_MEM;
131
132 resource = new_resource(dev, 0x14);
133 resource->size = 1 << 23;
134 resource->align = 22;
135 resource->gran = 22;
136 resource->limit = 0xffffffff;
137 resource->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
138
139 resource = new_resource(dev, 0x18);
140 resource->size = 1 << 12;
141 resource->align = 12;
142 resource->gran = 12;
143 resource->limit = 0xffff;
144 resource->flags |= IORESOURCE_IO;
145}
146
147static struct device_operations slot_dev_ops = {
148 .read_resources = slot_dev_read_resources,
149};
150
151/* Add a dummy device to reserve I/O space for hotpluggable devices. */
152void intel_acpi_pcie_hotplug_scan_slot(struct bus *bus)
153{
154 struct device *slot;
155 struct device_path slot_path = { .type = DEVICE_PATH_NONE };
156 slot = alloc_dev(bus, &slot_path);
157 slot->ops = &slot_dev_ops;
158}