1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <device/device.h>
4 #include <device/pnp.h>
5 #include <acpi/acpigen.h>
6 #include <console/console.h>
8 static void generic_set_resources(struct device
*dev
)
16 assign_resources(dev
->link_list
);
18 for (res
= dev
->resource_list
; res
; res
= res
->next
) {
19 if (!(res
->flags
& IORESOURCE_ASSIGNED
))
22 res
->flags
|= IORESOURCE_STORED
;
23 report_resource_stored(dev
, res
, "");
27 static void generic_read_resources(struct device
*dev
)
29 struct resource
*res
= new_resource(dev
, 0);
30 res
->base
= dev
->path
.pnp
.port
;
32 res
->flags
= IORESOURCE_IO
| IORESOURCE_ASSIGNED
| IORESOURCE_FIXED
;
35 #if CONFIG(HAVE_ACPI_TABLES)
36 static void generic_ssdt(const struct device
*dev
)
38 const char *scope
= acpi_device_scope(dev
);
39 const char *name
= acpi_device_name(dev
);
41 if (!scope
|| !name
) {
42 printk(BIOS_ERR
, "%s: Missing ACPI path/scope\n", dev_path(dev
));
47 acpigen_write_scope(scope
);
48 acpigen_write_device(name
);
50 printk(BIOS_DEBUG
, "%s.%s: %s\n", scope
, name
, dev_path(dev
));
52 acpigen_write_name_string("_HID", "PNP0C02");
53 acpigen_write_name_string("_DDN", dev_name(dev
));
55 /* OperationRegion("IOID", SYSTEMIO, port, 2) */
56 struct opregion opreg
= OPREGION("IOID", SYSTEMIO
, dev
->path
.pnp
.port
, 2);
57 acpigen_write_opregion(&opreg
);
59 struct fieldlist l
[] = {
61 FIELDLIST_NAMESTR("INDX", 8),
62 FIELDLIST_NAMESTR("DATA", 8),
65 /* Field (IOID, AnyAcc, NoLock, Preserve)
71 acpigen_write_field(opreg
.name
, l
, ARRAY_SIZE(l
), FIELD_BYTEACC
| FIELD_NOLOCK
|
74 struct fieldlist i
[] = {
75 FIELDLIST_OFFSET(0x07),
76 FIELDLIST_NAMESTR("LDN", 8),
77 FIELDLIST_OFFSET(0x21),
78 FIELDLIST_NAMESTR("SCF1", 8),
79 FIELDLIST_NAMESTR("SCF2", 8),
80 FIELDLIST_NAMESTR("SCF3", 8),
81 FIELDLIST_NAMESTR("SCF4", 8),
82 FIELDLIST_NAMESTR("SCF5", 8),
83 FIELDLIST_NAMESTR("SCF6", 8),
84 FIELDLIST_NAMESTR("SCF7", 8),
85 FIELDLIST_OFFSET(0x29),
86 FIELDLIST_NAMESTR("CKCF", 8),
87 FIELDLIST_OFFSET(0x2F),
88 FIELDLIST_NAMESTR("SCFF", 8),
89 FIELDLIST_OFFSET(0x30),
90 FIELDLIST_NAMESTR("ACT0", 1),
91 FIELDLIST_NAMESTR("ACT1", 1),
92 FIELDLIST_NAMESTR("ACT2", 1),
93 FIELDLIST_NAMESTR("ACT3", 1),
94 FIELDLIST_NAMESTR("ACT4", 1),
95 FIELDLIST_NAMESTR("ACT5", 1),
96 FIELDLIST_NAMESTR("ACT6", 1),
97 FIELDLIST_NAMESTR("ACT7", 1),
98 FIELDLIST_OFFSET(0x60),
99 FIELDLIST_NAMESTR("IOH0", 8),
100 FIELDLIST_NAMESTR("IOL0", 8),
101 FIELDLIST_NAMESTR("IOH1", 8),
102 FIELDLIST_NAMESTR("IOL1", 8),
103 FIELDLIST_NAMESTR("IOH2", 8),
104 FIELDLIST_NAMESTR("IOL2", 8),
105 FIELDLIST_NAMESTR("IOH3", 8),
106 FIELDLIST_NAMESTR("IOL3", 8),
107 FIELDLIST_OFFSET(0x70),
108 /* Interrupt level 0 (IRQ number) */
109 FIELDLIST_NAMESTR("ITL0", 4),
110 FIELDLIST_OFFSET(0x71),
111 /* Interrupt type 0 */
112 FIELDLIST_NAMESTR("ITT0", 2),
113 FIELDLIST_OFFSET(0x72),
114 /* Interrupt level 1 (IRQ number) */
115 FIELDLIST_NAMESTR("ITL1", 4),
116 FIELDLIST_OFFSET(0x73),
117 /* Interrupt type 1 */
118 FIELDLIST_NAMESTR("ITT1", 2),
119 FIELDLIST_OFFSET(0x74),
120 FIELDLIST_NAMESTR("DMCH", 8),
121 FIELDLIST_OFFSET(0xE0),
122 FIELDLIST_NAMESTR("RGE0", 8),
123 FIELDLIST_NAMESTR("RGE1", 8),
124 FIELDLIST_NAMESTR("RGE2", 8),
125 FIELDLIST_NAMESTR("RGE3", 8),
126 FIELDLIST_NAMESTR("RGE4", 8),
127 FIELDLIST_NAMESTR("RGE5", 8),
128 FIELDLIST_NAMESTR("RGE6", 8),
129 FIELDLIST_NAMESTR("RGE7", 8),
130 FIELDLIST_NAMESTR("RGE8", 8),
131 FIELDLIST_NAMESTR("RGE9", 8),
132 FIELDLIST_NAMESTR("RGEA", 8),
133 FIELDLIST_OFFSET(0xF0),
134 FIELDLIST_NAMESTR("OPT0", 8),
135 FIELDLIST_NAMESTR("OPT1", 8),
136 FIELDLIST_NAMESTR("OPT2", 8),
137 FIELDLIST_NAMESTR("OPT3", 8),
138 FIELDLIST_NAMESTR("OPT4", 8),
139 FIELDLIST_NAMESTR("OPT5", 8),
140 FIELDLIST_NAMESTR("OPT6", 8),
141 FIELDLIST_NAMESTR("OPT7", 8),
142 FIELDLIST_NAMESTR("OPT8", 8),
143 FIELDLIST_NAMESTR("OPT9", 8),
146 acpigen_write_indexfield("INDX", "DATA", i
, ARRAY_SIZE(i
), FIELD_BYTEACC
|
147 FIELD_NOLOCK
| FIELD_PRESERVE
);
149 const char *mutex
= "MTX0";
151 acpigen_write_mutex(mutex
, 0);
153 acpigen_write_name_integer("BLDN", 0);
155 /* Acquire mutex - Enter config mode */
156 acpigen_write_method("AMTX", 0);
158 acpigen_write_acquire(mutex
, 0xffff);
160 /* Pick one of the children as the generic SIO doesn't have config mode */
161 if (dev
->link_list
&& dev
->link_list
->children
)
162 pnp_ssdt_enter_conf_mode(dev
->link_list
->children
, "^INDX", "^DATA");
165 acpigen_write_store();
166 acpigen_emit_namestring("^LDN");
167 acpigen_emit_namestring("^BLDN");
169 acpigen_pop_len(); /* Method */
171 /* Release mutex - Exit config mode */
172 acpigen_write_method("RMTX", 0);
175 acpigen_write_store();
176 acpigen_emit_namestring("^BLDN");
177 acpigen_emit_namestring("^LDN");
179 /* Pick one of the children as the generic SIO doesn't have config mode */
180 if (dev
->link_list
&& dev
->link_list
->children
)
181 pnp_ssdt_exit_conf_mode(dev
->link_list
->children
, "^INDX", "^DATA");
183 acpigen_write_release(mutex
);
185 acpigen_pop_len(); /* Method */
188 acpigen_write_method("SLDN", 1);
190 /* Local0 = Arg0 & 0xff */
191 acpigen_emit_byte(AND_OP
);
192 acpigen_write_integer(0xff);
193 acpigen_emit_byte(ARG0_OP
);
194 acpigen_emit_byte(LOCAL0_OP
);
196 /* LDN = LOCAL0_OP */
197 acpigen_write_store();
198 acpigen_emit_byte(LOCAL0_OP
);
199 acpigen_emit_namestring("^LDN");
201 acpigen_pop_len(); /* Method */
203 /* Disable a LDN/VLDN */
204 acpigen_write_method("DLDN", 1);
207 acpigen_emit_namestring("AMTX");
210 acpigen_emit_namestring("SLDN");
211 acpigen_emit_byte(ARG0_OP
);
213 /* Local0 = Arg0 >> 8 */
214 acpigen_emit_byte(SHIFT_RIGHT_OP
);
215 acpigen_emit_byte(ARG0_OP
);
216 acpigen_write_integer(8);
217 acpigen_emit_byte(LOCAL0_OP
);
219 /* Local0 = Local0 & 0x7 */
220 acpigen_emit_byte(AND_OP
);
221 acpigen_write_integer(0x7);
222 acpigen_emit_byte(LOCAL0_OP
);
223 acpigen_emit_byte(LOCAL0_OP
);
225 for (int j
= 0; j
< 8; j
++) {
226 char act
[6] = "^ACT0";
229 /* If (Local0 == j) { */
230 acpigen_write_if_lequal_op_int(LOCAL0_OP
, j
);
233 acpigen_write_store();
234 acpigen_emit_byte(ZERO_OP
);
235 acpigen_emit_namestring(act
);
237 acpigen_pop_len(); /* } */
241 acpigen_emit_namestring("RMTX");
243 acpigen_pop_len(); /* Method */
245 /* Query LDN enable state. Returns 1 if LDN/VLDN is enabled. */
246 acpigen_write_method("QLDN", 1);
248 acpigen_emit_namestring("AMTX");
251 acpigen_emit_namestring("SLDN");
252 acpigen_emit_byte(ARG0_OP
);
254 /* Local0 = Arg0 >> 8 */
255 acpigen_emit_byte(SHIFT_RIGHT_OP
);
256 acpigen_emit_byte(ARG0_OP
);
257 acpigen_write_integer(8);
258 acpigen_emit_byte(LOCAL0_OP
);
260 /* Local0 = Local0 & 0x7 */
261 acpigen_emit_byte(AND_OP
);
262 acpigen_write_integer(0x7);
263 acpigen_emit_byte(LOCAL0_OP
);
264 acpigen_emit_byte(LOCAL0_OP
);
266 for (int j
= 0; j
< 8; j
++) {
267 char act
[6] = "^ACT0";
269 /* If (Local0 == j) { */
270 acpigen_write_if_lequal_op_int(LOCAL0_OP
, j
);
272 /* Local1 = ACT[j] */
273 acpigen_write_store();
274 acpigen_emit_namestring(act
);
275 acpigen_emit_byte(LOCAL1_OP
);
277 acpigen_pop_len(); /* } */
281 acpigen_emit_namestring("RMTX");
283 /* Return (Local1) */
284 acpigen_emit_byte(RETURN_OP
);
285 acpigen_emit_byte(LOCAL1_OP
);
287 acpigen_pop_len(); /* Method */
289 acpigen_pop_len(); /* Device */
290 acpigen_pop_len(); /* Scope */
293 static const char *generic_acpi_name(const struct device
*dev
)
299 static struct device_operations ops
= {
300 .read_resources
= generic_read_resources
,
301 .set_resources
= generic_set_resources
,
302 .scan_bus
= scan_static_bus
,
303 #if CONFIG(HAVE_ACPI_TABLES)
304 .acpi_fill_ssdt
= generic_ssdt
,
305 .acpi_name
= generic_acpi_name
,
309 static void enable_dev(struct device
*dev
)
311 if (dev
->path
.type
!= DEVICE_PATH_PNP
)
312 printk(BIOS_ERR
, "%s: Unsupported device type\n", dev_path(dev
));
313 else if (!dev
->path
.pnp
.port
)
314 printk(BIOS_ERR
, "%s: Base address not set\n", dev_path(dev
));
320 struct chip_operations superio_common_ops
= {
321 CHIP_NAME("Generic Super I/O")
322 .enable_dev
= enable_dev
,