]>
Commit | Line | Data |
---|---|---|
61cc9339 SG |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Generation of ACPI (Advanced Configuration and Power Interface) tables | |
4 | * | |
5 | * Copyright 2019 Google LLC | |
6 | * Mostly taken from coreboot | |
7 | */ | |
8 | ||
9 | #define LOG_CATEGORY LOGC_ACPI | |
10 | ||
11 | #include <common.h> | |
12 | #include <dm.h> | |
7e148f2e | 13 | #include <log.h> |
29df8452 | 14 | #include <uuid.h> |
61cc9339 | 15 | #include <acpi/acpigen.h> |
f8054dd8 | 16 | #include <acpi/acpi_device.h> |
d7d631df | 17 | #include <acpi/acpi_table.h> |
61cc9339 SG |
18 | #include <dm/acpi.h> |
19 | ||
15403289 SG |
20 | /* CPU path format */ |
21 | #define ACPI_CPU_STRING "\\_PR.CP%02d" | |
22 | ||
61cc9339 SG |
23 | u8 *acpigen_get_current(struct acpi_ctx *ctx) |
24 | { | |
25 | return ctx->current; | |
26 | } | |
27 | ||
28 | void acpigen_emit_byte(struct acpi_ctx *ctx, uint data) | |
29 | { | |
30 | *(u8 *)ctx->current++ = data; | |
31 | } | |
32 | ||
33 | void acpigen_emit_word(struct acpi_ctx *ctx, uint data) | |
34 | { | |
35 | acpigen_emit_byte(ctx, data & 0xff); | |
36 | acpigen_emit_byte(ctx, (data >> 8) & 0xff); | |
37 | } | |
38 | ||
39 | void acpigen_emit_dword(struct acpi_ctx *ctx, uint data) | |
40 | { | |
41 | /* Output the value in little-endian format */ | |
42 | acpigen_emit_byte(ctx, data & 0xff); | |
43 | acpigen_emit_byte(ctx, (data >> 8) & 0xff); | |
44 | acpigen_emit_byte(ctx, (data >> 16) & 0xff); | |
45 | acpigen_emit_byte(ctx, (data >> 24) & 0xff); | |
46 | } | |
7fb8da4c | 47 | |
7e148f2e SG |
48 | /* |
49 | * Maximum length for an ACPI object generated by this code, | |
50 | * | |
51 | * If you need to change this, change acpigen_write_len_f(ctx) and | |
52 | * acpigen_pop_len(ctx) | |
53 | */ | |
54 | #define ACPIGEN_MAXLEN 0xfffff | |
55 | ||
56 | void acpigen_write_len_f(struct acpi_ctx *ctx) | |
57 | { | |
58 | assert(ctx->ltop < (ACPIGEN_LENSTACK_SIZE - 1)); | |
59 | ctx->len_stack[ctx->ltop++] = ctx->current; | |
60 | acpigen_emit_byte(ctx, 0); | |
61 | acpigen_emit_byte(ctx, 0); | |
62 | acpigen_emit_byte(ctx, 0); | |
63 | } | |
64 | ||
65 | void acpigen_pop_len(struct acpi_ctx *ctx) | |
66 | { | |
67 | int len; | |
68 | char *p; | |
69 | ||
70 | assert(ctx->ltop > 0); | |
71 | p = ctx->len_stack[--ctx->ltop]; | |
72 | len = ctx->current - (void *)p; | |
73 | assert(len <= ACPIGEN_MAXLEN); | |
74 | /* generate store length for 0xfffff max */ | |
75 | p[0] = ACPI_PKG_LEN_3_BYTES | (len & 0xf); | |
76 | p[1] = len >> 4 & 0xff; | |
77 | p[2] = len >> 12 & 0xff; | |
78 | } | |
79 | ||
9c70e7e5 SG |
80 | void acpigen_emit_ext_op(struct acpi_ctx *ctx, uint op) |
81 | { | |
82 | acpigen_emit_byte(ctx, EXT_OP_PREFIX); | |
83 | acpigen_emit_byte(ctx, op); | |
84 | } | |
85 | ||
03967ce2 SG |
86 | char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el) |
87 | { | |
88 | char *p; | |
89 | ||
90 | acpigen_emit_byte(ctx, PACKAGE_OP); | |
91 | acpigen_write_len_f(ctx); | |
92 | p = ctx->current; | |
93 | acpigen_emit_byte(ctx, nr_el); | |
94 | ||
95 | return p; | |
96 | } | |
97 | ||
83b2bd5a SG |
98 | void acpigen_write_byte(struct acpi_ctx *ctx, unsigned int data) |
99 | { | |
100 | acpigen_emit_byte(ctx, BYTE_PREFIX); | |
101 | acpigen_emit_byte(ctx, data & 0xff); | |
102 | } | |
103 | ||
104 | void acpigen_write_word(struct acpi_ctx *ctx, unsigned int data) | |
105 | { | |
106 | acpigen_emit_byte(ctx, WORD_PREFIX); | |
107 | acpigen_emit_word(ctx, data); | |
108 | } | |
109 | ||
110 | void acpigen_write_dword(struct acpi_ctx *ctx, unsigned int data) | |
111 | { | |
112 | acpigen_emit_byte(ctx, DWORD_PREFIX); | |
113 | acpigen_emit_dword(ctx, data); | |
114 | } | |
115 | ||
116 | void acpigen_write_qword(struct acpi_ctx *ctx, u64 data) | |
117 | { | |
118 | acpigen_emit_byte(ctx, QWORD_PREFIX); | |
119 | acpigen_emit_dword(ctx, data & 0xffffffff); | |
120 | acpigen_emit_dword(ctx, (data >> 32) & 0xffffffff); | |
121 | } | |
122 | ||
123 | void acpigen_write_zero(struct acpi_ctx *ctx) | |
124 | { | |
125 | acpigen_emit_byte(ctx, ZERO_OP); | |
126 | } | |
127 | ||
128 | void acpigen_write_one(struct acpi_ctx *ctx) | |
129 | { | |
130 | acpigen_emit_byte(ctx, ONE_OP); | |
131 | } | |
132 | ||
133 | void acpigen_write_integer(struct acpi_ctx *ctx, u64 data) | |
134 | { | |
135 | if (data == 0) | |
136 | acpigen_write_zero(ctx); | |
137 | else if (data == 1) | |
138 | acpigen_write_one(ctx); | |
139 | else if (data <= 0xff) | |
140 | acpigen_write_byte(ctx, (unsigned char)data); | |
141 | else if (data <= 0xffff) | |
142 | acpigen_write_word(ctx, (unsigned int)data); | |
143 | else if (data <= 0xffffffff) | |
144 | acpigen_write_dword(ctx, (unsigned int)data); | |
145 | else | |
146 | acpigen_write_qword(ctx, data); | |
147 | } | |
148 | ||
bb6772c3 SG |
149 | void acpigen_write_name_zero(struct acpi_ctx *ctx, const char *name) |
150 | { | |
151 | acpigen_write_name(ctx, name); | |
152 | acpigen_write_zero(ctx); | |
153 | } | |
154 | ||
155 | void acpigen_write_name_one(struct acpi_ctx *ctx, const char *name) | |
156 | { | |
157 | acpigen_write_name(ctx, name); | |
158 | acpigen_write_one(ctx); | |
159 | } | |
160 | ||
161 | void acpigen_write_name_byte(struct acpi_ctx *ctx, const char *name, uint val) | |
162 | { | |
163 | acpigen_write_name(ctx, name); | |
164 | acpigen_write_byte(ctx, val); | |
165 | } | |
166 | ||
167 | void acpigen_write_name_word(struct acpi_ctx *ctx, const char *name, uint val) | |
168 | { | |
169 | acpigen_write_name(ctx, name); | |
170 | acpigen_write_word(ctx, val); | |
171 | } | |
172 | ||
173 | void acpigen_write_name_dword(struct acpi_ctx *ctx, const char *name, uint val) | |
174 | { | |
175 | acpigen_write_name(ctx, name); | |
176 | acpigen_write_dword(ctx, val); | |
177 | } | |
178 | ||
179 | void acpigen_write_name_qword(struct acpi_ctx *ctx, const char *name, u64 val) | |
180 | { | |
181 | acpigen_write_name(ctx, name); | |
182 | acpigen_write_qword(ctx, val); | |
183 | } | |
184 | ||
185 | void acpigen_write_name_integer(struct acpi_ctx *ctx, const char *name, u64 val) | |
186 | { | |
187 | acpigen_write_name(ctx, name); | |
188 | acpigen_write_integer(ctx, val); | |
189 | } | |
190 | ||
191 | void acpigen_write_name_string(struct acpi_ctx *ctx, const char *name, | |
192 | const char *string) | |
193 | { | |
194 | acpigen_write_name(ctx, name); | |
195 | acpigen_write_string(ctx, string); | |
196 | } | |
197 | ||
7fb8da4c SG |
198 | void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size) |
199 | { | |
200 | int i; | |
201 | ||
202 | for (i = 0; i < size; i++) | |
203 | acpigen_emit_byte(ctx, data[i]); | |
204 | } | |
205 | ||
206 | void acpigen_emit_string(struct acpi_ctx *ctx, const char *str) | |
207 | { | |
208 | acpigen_emit_stream(ctx, str, str ? strlen(str) : 0); | |
209 | acpigen_emit_byte(ctx, '\0'); | |
210 | } | |
3df33bda SG |
211 | |
212 | void acpigen_write_string(struct acpi_ctx *ctx, const char *str) | |
213 | { | |
214 | acpigen_emit_byte(ctx, STRING_PREFIX); | |
215 | acpigen_emit_string(ctx, str); | |
216 | } | |
7aed90d4 SG |
217 | |
218 | /* | |
219 | * The naming conventions for ACPI namespace names are a bit tricky as | |
220 | * each element has to be 4 chars wide ("All names are a fixed 32 bits.") | |
221 | * and "By convention, when an ASL compiler pads a name shorter than 4 | |
222 | * characters, it is done so with trailing underscores ('_')". | |
223 | * | |
224 | * Check sections 5.3, 20.2.2 and 20.4 of ACPI spec 6.3 for details. | |
225 | */ | |
226 | static void acpigen_emit_simple_namestring(struct acpi_ctx *ctx, | |
227 | const char *name) | |
228 | { | |
229 | const char *ptr; | |
230 | int i; | |
231 | ||
232 | for (i = 0, ptr = name; i < 4; i++) { | |
233 | if (!*ptr || *ptr == '.') | |
234 | acpigen_emit_byte(ctx, '_'); | |
235 | else | |
236 | acpigen_emit_byte(ctx, *ptr++); | |
237 | } | |
238 | } | |
239 | ||
240 | static void acpigen_emit_double_namestring(struct acpi_ctx *ctx, | |
241 | const char *name, int dotpos) | |
242 | { | |
243 | acpigen_emit_byte(ctx, DUAL_NAME_PREFIX); | |
244 | acpigen_emit_simple_namestring(ctx, name); | |
245 | acpigen_emit_simple_namestring(ctx, &name[dotpos + 1]); | |
246 | } | |
247 | ||
248 | static void acpigen_emit_multi_namestring(struct acpi_ctx *ctx, | |
249 | const char *name) | |
250 | { | |
251 | unsigned char *pathlen; | |
252 | int count = 0; | |
253 | ||
254 | acpigen_emit_byte(ctx, MULTI_NAME_PREFIX); | |
255 | pathlen = ctx->current; | |
256 | acpigen_emit_byte(ctx, 0); | |
257 | ||
258 | while (*name) { | |
259 | acpigen_emit_simple_namestring(ctx, name); | |
260 | /* find end or next entity */ | |
261 | while (*name != '.' && *name) | |
262 | name++; | |
263 | /* forward to next */ | |
264 | if (*name == '.') | |
265 | name++; | |
266 | count++; | |
267 | } | |
268 | ||
269 | *pathlen = count; | |
270 | } | |
271 | ||
272 | void acpigen_emit_namestring(struct acpi_ctx *ctx, const char *namepath) | |
273 | { | |
274 | int dotcount; | |
275 | int dotpos; | |
276 | int i; | |
277 | ||
278 | /* We can start with a '\' */ | |
279 | if (*namepath == '\\') { | |
280 | acpigen_emit_byte(ctx, '\\'); | |
281 | namepath++; | |
282 | } | |
283 | ||
284 | /* And there can be any number of '^' */ | |
285 | while (*namepath == '^') { | |
286 | acpigen_emit_byte(ctx, '^'); | |
287 | namepath++; | |
288 | } | |
289 | ||
290 | for (i = 0, dotcount = 0; namepath[i]; i++) { | |
291 | if (namepath[i] == '.') { | |
292 | dotcount++; | |
293 | dotpos = i; | |
294 | } | |
295 | } | |
296 | ||
297 | /* If we have only \\ or only ^* then we need to add a null name */ | |
298 | if (!*namepath) | |
299 | acpigen_emit_byte(ctx, ZERO_OP); | |
300 | else if (dotcount == 0) | |
301 | acpigen_emit_simple_namestring(ctx, namepath); | |
302 | else if (dotcount == 1) | |
303 | acpigen_emit_double_namestring(ctx, namepath, dotpos); | |
304 | else | |
305 | acpigen_emit_multi_namestring(ctx, namepath); | |
306 | } | |
307 | ||
308 | void acpigen_write_name(struct acpi_ctx *ctx, const char *namepath) | |
309 | { | |
310 | acpigen_emit_byte(ctx, NAME_OP); | |
311 | acpigen_emit_namestring(ctx, namepath); | |
312 | } | |
29df8452 | 313 | |
82659cc9 SG |
314 | void acpigen_write_scope(struct acpi_ctx *ctx, const char *scope) |
315 | { | |
316 | acpigen_emit_byte(ctx, SCOPE_OP); | |
317 | acpigen_write_len_f(ctx); | |
318 | acpigen_emit_namestring(ctx, scope); | |
319 | } | |
320 | ||
9c70e7e5 SG |
321 | static void acpigen_write_method_internal(struct acpi_ctx *ctx, |
322 | const char *name, uint flags) | |
323 | { | |
324 | acpigen_emit_byte(ctx, METHOD_OP); | |
325 | acpigen_write_len_f(ctx); | |
326 | acpigen_emit_namestring(ctx, name); | |
327 | acpigen_emit_byte(ctx, flags); | |
328 | } | |
329 | ||
330 | /* Method (name, nargs, NotSerialized) */ | |
331 | void acpigen_write_method(struct acpi_ctx *ctx, const char *name, int nargs) | |
332 | { | |
333 | acpigen_write_method_internal(ctx, name, | |
334 | nargs & ACPI_METHOD_NARGS_MASK); | |
335 | } | |
336 | ||
337 | /* Method (name, nargs, Serialized) */ | |
338 | void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name, | |
339 | int nargs) | |
340 | { | |
341 | acpigen_write_method_internal(ctx, name, | |
342 | (nargs & ACPI_METHOD_NARGS_MASK) | | |
343 | ACPI_METHOD_SERIALIZED_MASK); | |
344 | } | |
345 | ||
15403289 SG |
346 | void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex, |
347 | u32 pblock_addr, uint pblock_len) | |
348 | { | |
349 | /* | |
350 | * Processor (\_PR.CPnn, cpuindex, pblock_addr, pblock_len) | |
351 | * { | |
352 | */ | |
353 | char pscope[16]; | |
354 | ||
355 | acpigen_emit_ext_op(ctx, PROCESSOR_OP); | |
356 | acpigen_write_len_f(ctx); | |
357 | ||
358 | snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, cpuindex); | |
359 | acpigen_emit_namestring(ctx, pscope); | |
360 | acpigen_emit_byte(ctx, cpuindex); | |
361 | acpigen_emit_dword(ctx, pblock_addr); | |
362 | acpigen_emit_byte(ctx, pblock_len); | |
363 | } | |
364 | ||
365 | void acpigen_write_processor_package(struct acpi_ctx *ctx, | |
366 | const char *const name, | |
367 | const uint first_core, | |
368 | const uint core_count) | |
369 | { | |
370 | uint i; | |
371 | char pscope[16]; | |
372 | ||
373 | acpigen_write_name(ctx, name); | |
374 | acpigen_write_package(ctx, core_count); | |
375 | for (i = first_core; i < first_core + core_count; ++i) { | |
376 | snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, i); | |
377 | acpigen_emit_namestring(ctx, pscope); | |
378 | } | |
379 | acpigen_pop_len(ctx); | |
380 | } | |
381 | ||
382 | void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores) | |
383 | { | |
384 | int core_id; | |
385 | ||
386 | acpigen_write_method(ctx, "\\_PR.CNOT", 1); | |
387 | for (core_id = 0; core_id < num_cores; core_id++) { | |
388 | char buffer[30]; | |
389 | ||
390 | snprintf(buffer, sizeof(buffer), ACPI_CPU_STRING, core_id); | |
391 | acpigen_emit_byte(ctx, NOTIFY_OP); | |
392 | acpigen_emit_namestring(ctx, buffer); | |
393 | acpigen_emit_byte(ctx, ARG0_OP); | |
394 | } | |
395 | acpigen_pop_len(ctx); | |
396 | } | |
397 | ||
91c2f9c3 SG |
398 | void acpigen_write_device(struct acpi_ctx *ctx, const char *name) |
399 | { | |
400 | acpigen_emit_ext_op(ctx, DEVICE_OP); | |
401 | acpigen_write_len_f(ctx); | |
402 | acpigen_emit_namestring(ctx, name); | |
403 | } | |
404 | ||
9c70e7e5 SG |
405 | void acpigen_write_sta(struct acpi_ctx *ctx, uint status) |
406 | { | |
407 | /* Method (_STA, 0, NotSerialized) { Return (status) } */ | |
408 | acpigen_write_method(ctx, "_STA", 0); | |
409 | acpigen_emit_byte(ctx, RETURN_OP); | |
410 | acpigen_write_byte(ctx, status); | |
411 | acpigen_pop_len(ctx); | |
412 | } | |
413 | ||
d7d631df SG |
414 | static void acpigen_write_register(struct acpi_ctx *ctx, |
415 | const struct acpi_gen_regaddr *addr) | |
416 | { | |
417 | /* See ACPI v6.3 section 6.4.3.7: Generic Register Descriptor */ | |
418 | acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_REGISTER); | |
419 | acpigen_emit_byte(ctx, 0x0c); /* Register Length 7:0 */ | |
420 | acpigen_emit_byte(ctx, 0x00); /* Register Length 15:8 */ | |
421 | acpigen_emit_byte(ctx, addr->space_id); | |
422 | acpigen_emit_byte(ctx, addr->bit_width); | |
423 | acpigen_emit_byte(ctx, addr->bit_offset); | |
424 | acpigen_emit_byte(ctx, addr->access_size); | |
425 | acpigen_emit_dword(ctx, addr->addrl); | |
426 | acpigen_emit_dword(ctx, addr->addrh); | |
427 | } | |
428 | ||
429 | void acpigen_write_resourcetemplate_header(struct acpi_ctx *ctx) | |
430 | { | |
431 | /* | |
432 | * A ResourceTemplate() is a Buffer() with a | |
433 | * (Byte|Word|DWord) containing the length, followed by one or more | |
434 | * resource items, terminated by the end tag. | |
435 | * (small item 0xf, len 1) | |
436 | */ | |
437 | acpigen_emit_byte(ctx, BUFFER_OP); | |
438 | acpigen_write_len_f(ctx); | |
439 | acpigen_emit_byte(ctx, WORD_PREFIX); | |
440 | ctx->len_stack[ctx->ltop++] = ctx->current; | |
441 | ||
442 | /* | |
443 | * Add two dummy bytes for the ACPI word (keep aligned with the | |
444 | * calculation in acpigen_write_resourcetemplate_footer() below) | |
445 | */ | |
446 | acpigen_emit_byte(ctx, 0x00); | |
447 | acpigen_emit_byte(ctx, 0x00); | |
448 | } | |
449 | ||
450 | void acpigen_write_resourcetemplate_footer(struct acpi_ctx *ctx) | |
451 | { | |
452 | char *p = ctx->len_stack[--ctx->ltop]; | |
453 | int len; | |
454 | /* | |
455 | * See ACPI v6.3 section 6.4.2.9: End Tag | |
456 | * 0x79 <checksum> | |
457 | * 0x00 is treated as a good checksum according to the spec | |
458 | * and is what iasl generates. | |
459 | */ | |
460 | acpigen_emit_byte(ctx, ACPI_END_TAG); | |
461 | acpigen_emit_byte(ctx, 0x00); | |
462 | ||
463 | /* | |
464 | * Start counting past the 2-bytes length added in | |
465 | * acpigen_write_resourcetemplate_header() above | |
466 | */ | |
467 | len = (char *)ctx->current - (p + 2); | |
468 | ||
469 | /* patch len word */ | |
470 | p[0] = len & 0xff; | |
471 | p[1] = (len >> 8) & 0xff; | |
472 | ||
473 | acpigen_pop_len(ctx); | |
474 | } | |
475 | ||
476 | void acpigen_write_register_resource(struct acpi_ctx *ctx, | |
477 | const struct acpi_gen_regaddr *addr) | |
478 | { | |
479 | acpigen_write_resourcetemplate_header(ctx); | |
480 | acpigen_write_register(ctx, addr); | |
481 | acpigen_write_resourcetemplate_footer(ctx); | |
482 | } | |
483 | ||
350c7f52 SG |
484 | void acpigen_write_ppc(struct acpi_ctx *ctx, uint num_pstates) |
485 | { | |
486 | /* | |
487 | * Method (_PPC, 0, NotSerialized) | |
488 | * { | |
489 | * Return (num_pstates) | |
490 | * } | |
491 | */ | |
492 | acpigen_write_method(ctx, "_PPC", 0); | |
493 | acpigen_emit_byte(ctx, RETURN_OP); | |
494 | acpigen_write_byte(ctx, num_pstates); | |
495 | acpigen_pop_len(ctx); | |
496 | } | |
497 | ||
498 | /* | |
499 | * Generates a func with max supported P-states saved | |
500 | * in the variable PPCM. | |
501 | */ | |
502 | void acpigen_write_ppc_nvs(struct acpi_ctx *ctx) | |
503 | { | |
504 | /* | |
505 | * Method (_PPC, 0, NotSerialized) | |
506 | * { | |
507 | * Return (PPCM) | |
508 | * } | |
509 | */ | |
510 | acpigen_write_method(ctx, "_PPC", 0); | |
511 | acpigen_emit_byte(ctx, RETURN_OP); | |
512 | acpigen_emit_namestring(ctx, "PPCM"); | |
513 | acpigen_pop_len(ctx); | |
514 | } | |
515 | ||
516 | void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit) | |
517 | { | |
518 | /* | |
519 | * // Sample _TPC method | |
520 | * Method (_TPC, 0, NotSerialized) | |
521 | * { | |
522 | * Return (\TLVL) | |
523 | * } | |
524 | */ | |
525 | acpigen_write_method(ctx, "_TPC", 0); | |
526 | acpigen_emit_byte(ctx, RETURN_OP); | |
527 | acpigen_emit_namestring(ctx, gnvs_tpc_limit); | |
528 | acpigen_pop_len(ctx); | |
529 | } | |
530 | ||
e0a896b8 SG |
531 | void acpigen_write_prw(struct acpi_ctx *ctx, uint wake, uint level) |
532 | { | |
533 | /* Name (_PRW, Package () { wake, level } */ | |
534 | acpigen_write_name(ctx, "_PRW"); | |
535 | acpigen_write_package(ctx, 2); | |
536 | acpigen_write_integer(ctx, wake); | |
537 | acpigen_write_integer(ctx, level); | |
538 | acpigen_pop_len(ctx); | |
539 | } | |
540 | ||
350c7f52 SG |
541 | void acpigen_write_pss_package(struct acpi_ctx *ctx, u32 core_freq, u32 power, |
542 | u32 trans_lat, u32 busm_lat, u32 control, | |
543 | u32 status) | |
544 | { | |
545 | acpigen_write_package(ctx, 6); | |
546 | acpigen_write_dword(ctx, core_freq); | |
547 | acpigen_write_dword(ctx, power); | |
548 | acpigen_write_dword(ctx, trans_lat); | |
549 | acpigen_write_dword(ctx, busm_lat); | |
550 | acpigen_write_dword(ctx, control); | |
551 | acpigen_write_dword(ctx, status); | |
552 | acpigen_pop_len(ctx); | |
553 | ||
554 | log_debug("PSS: %uMHz power %u control 0x%x status 0x%x\n", | |
555 | core_freq, power, control, status); | |
556 | } | |
557 | ||
558 | void acpigen_write_psd_package(struct acpi_ctx *ctx, uint domain, uint numprocs, | |
559 | enum psd_coord coordtype) | |
560 | { | |
561 | acpigen_write_name(ctx, "_PSD"); | |
562 | acpigen_write_package(ctx, 1); | |
563 | acpigen_write_package(ctx, 5); | |
564 | acpigen_write_byte(ctx, 5); // 5 values | |
565 | acpigen_write_byte(ctx, 0); // revision 0 | |
566 | acpigen_write_dword(ctx, domain); | |
567 | acpigen_write_dword(ctx, coordtype); | |
568 | acpigen_write_dword(ctx, numprocs); | |
569 | acpigen_pop_len(ctx); | |
570 | acpigen_pop_len(ctx); | |
571 | } | |
572 | ||
573 | static void acpigen_write_cst_package_entry(struct acpi_ctx *ctx, | |
574 | const struct acpi_cstate *cstate) | |
575 | { | |
576 | acpigen_write_package(ctx, 4); | |
577 | acpigen_write_register_resource(ctx, &cstate->resource); | |
578 | acpigen_write_dword(ctx, cstate->ctype); | |
579 | acpigen_write_dword(ctx, cstate->latency); | |
580 | acpigen_write_dword(ctx, cstate->power); | |
581 | acpigen_pop_len(ctx); | |
582 | } | |
583 | ||
584 | void acpigen_write_cst_package(struct acpi_ctx *ctx, | |
585 | const struct acpi_cstate *cstate, int nentries) | |
586 | { | |
587 | int i; | |
588 | ||
589 | acpigen_write_name(ctx, "_CST"); | |
590 | acpigen_write_package(ctx, nentries + 1); | |
591 | acpigen_write_dword(ctx, nentries); | |
592 | ||
593 | for (i = 0; i < nentries; i++) | |
594 | acpigen_write_cst_package_entry(ctx, cstate + i); | |
595 | ||
596 | acpigen_pop_len(ctx); | |
597 | } | |
598 | ||
599 | void acpigen_write_csd_package(struct acpi_ctx *ctx, uint domain, uint numprocs, | |
600 | enum csd_coord coordtype, uint index) | |
601 | { | |
602 | acpigen_write_name(ctx, "_CSD"); | |
603 | acpigen_write_package(ctx, 1); | |
604 | acpigen_write_package(ctx, 6); | |
605 | acpigen_write_byte(ctx, 6); // 6 values | |
606 | acpigen_write_byte(ctx, 0); // revision 0 | |
607 | acpigen_write_dword(ctx, domain); | |
608 | acpigen_write_dword(ctx, coordtype); | |
609 | acpigen_write_dword(ctx, numprocs); | |
610 | acpigen_write_dword(ctx, index); | |
611 | acpigen_pop_len(ctx); | |
612 | acpigen_pop_len(ctx); | |
613 | } | |
614 | ||
615 | void acpigen_write_tss_package(struct acpi_ctx *ctx, | |
616 | struct acpi_tstate *entry, int nentries) | |
617 | { | |
618 | /* | |
619 | * Sample _TSS package with 100% and 50% duty cycles | |
620 | * Name (_TSS, Package (0x02) | |
621 | * { | |
622 | * Package(){100, 1000, 0, 0x00, 0) | |
623 | * Package(){50, 520, 0, 0x18, 0) | |
624 | * }) | |
625 | */ | |
626 | struct acpi_tstate *tstate = entry; | |
627 | int i; | |
628 | ||
629 | acpigen_write_name(ctx, "_TSS"); | |
630 | acpigen_write_package(ctx, nentries); | |
631 | ||
632 | for (i = 0; i < nentries; i++) { | |
633 | acpigen_write_package(ctx, 5); | |
634 | acpigen_write_dword(ctx, tstate->percent); | |
635 | acpigen_write_dword(ctx, tstate->power); | |
636 | acpigen_write_dword(ctx, tstate->latency); | |
637 | acpigen_write_dword(ctx, tstate->control); | |
638 | acpigen_write_dword(ctx, tstate->status); | |
639 | acpigen_pop_len(ctx); | |
640 | tstate++; | |
641 | } | |
642 | ||
643 | acpigen_pop_len(ctx); | |
644 | } | |
645 | ||
646 | void acpigen_write_tsd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs, | |
647 | enum psd_coord coordtype) | |
648 | { | |
649 | acpigen_write_name(ctx, "_TSD"); | |
650 | acpigen_write_package(ctx, 1); | |
651 | acpigen_write_package(ctx, 5); | |
652 | acpigen_write_byte(ctx, 5); // 5 values | |
653 | acpigen_write_byte(ctx, 0); // revision 0 | |
654 | acpigen_write_dword(ctx, domain); | |
655 | acpigen_write_dword(ctx, coordtype); | |
656 | acpigen_write_dword(ctx, numprocs); | |
657 | acpigen_pop_len(ctx); | |
658 | acpigen_pop_len(ctx); | |
659 | } | |
660 | ||
29df8452 SG |
661 | /* |
662 | * ToUUID(uuid) | |
663 | * | |
664 | * ACPI 6.3 Section 19.6.142 table 19-438 defines a special output order for the | |
665 | * bytes that make up a UUID Buffer object: | |
666 | * | |
667 | * UUID byte order for input to this function: | |
668 | * aabbccdd-eeff-gghh-iijj-kkllmmnnoopp | |
669 | * | |
670 | * UUID byte order output by this function: | |
671 | * ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp | |
672 | */ | |
673 | int acpigen_write_uuid(struct acpi_ctx *ctx, const char *uuid) | |
674 | { | |
675 | u8 buf[UUID_BIN_LEN]; | |
676 | int ret; | |
677 | ||
678 | /* Parse UUID string into bytes */ | |
679 | ret = uuid_str_to_bin(uuid, buf, UUID_STR_FORMAT_GUID); | |
680 | if (ret) | |
681 | return log_msg_ret("bad hex", -EINVAL); | |
682 | ||
683 | /* BufferOp */ | |
684 | acpigen_emit_byte(ctx, BUFFER_OP); | |
685 | acpigen_write_len_f(ctx); | |
686 | ||
687 | /* Buffer length in bytes */ | |
688 | acpigen_write_word(ctx, UUID_BIN_LEN); | |
689 | ||
690 | /* Output UUID in expected order */ | |
691 | acpigen_emit_stream(ctx, (char *)buf, UUID_BIN_LEN); | |
692 | ||
693 | acpigen_pop_len(ctx); | |
694 | ||
695 | return 0; | |
696 | } | |
9c70e7e5 | 697 | |
f9189d5a SG |
698 | void acpigen_write_power_res(struct acpi_ctx *ctx, const char *name, uint level, |
699 | uint order, const char *const dev_states[], | |
700 | size_t dev_states_count) | |
701 | { | |
702 | size_t i; | |
703 | ||
704 | for (i = 0; i < dev_states_count; i++) { | |
705 | acpigen_write_name(ctx, dev_states[i]); | |
706 | acpigen_write_package(ctx, 1); | |
707 | acpigen_emit_simple_namestring(ctx, name); | |
708 | acpigen_pop_len(ctx); /* Package */ | |
709 | } | |
710 | ||
711 | acpigen_emit_ext_op(ctx, POWER_RES_OP); | |
712 | ||
713 | acpigen_write_len_f(ctx); | |
714 | ||
715 | acpigen_emit_simple_namestring(ctx, name); | |
716 | acpigen_emit_byte(ctx, level); | |
717 | acpigen_emit_word(ctx, order); | |
718 | } | |
719 | ||
9c70e7e5 SG |
720 | /* Sleep (ms) */ |
721 | void acpigen_write_sleep(struct acpi_ctx *ctx, u64 sleep_ms) | |
722 | { | |
723 | acpigen_emit_ext_op(ctx, SLEEP_OP); | |
724 | acpigen_write_integer(ctx, sleep_ms); | |
725 | } | |
726 | ||
727 | void acpigen_write_store(struct acpi_ctx *ctx) | |
728 | { | |
729 | acpigen_emit_byte(ctx, STORE_OP); | |
730 | } | |
731 | ||
732 | /* Or (arg1, arg2, res) */ | |
733 | void acpigen_write_or(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res) | |
734 | { | |
735 | acpigen_emit_byte(ctx, OR_OP); | |
736 | acpigen_emit_byte(ctx, arg1); | |
737 | acpigen_emit_byte(ctx, arg2); | |
738 | acpigen_emit_byte(ctx, res); | |
739 | } | |
740 | ||
741 | /* And (arg1, arg2, res) */ | |
742 | void acpigen_write_and(struct acpi_ctx *ctx, u8 arg1, u8 arg2, u8 res) | |
743 | { | |
744 | acpigen_emit_byte(ctx, AND_OP); | |
745 | acpigen_emit_byte(ctx, arg1); | |
746 | acpigen_emit_byte(ctx, arg2); | |
747 | acpigen_emit_byte(ctx, res); | |
748 | } | |
749 | ||
750 | /* Not (arg, res) */ | |
751 | void acpigen_write_not(struct acpi_ctx *ctx, u8 arg, u8 res) | |
752 | { | |
753 | acpigen_emit_byte(ctx, NOT_OP); | |
754 | acpigen_emit_byte(ctx, arg); | |
755 | acpigen_emit_byte(ctx, res); | |
756 | } | |
757 | ||
758 | /* Store (str, DEBUG) */ | |
759 | void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str) | |
760 | { | |
761 | acpigen_write_store(ctx); | |
762 | acpigen_write_string(ctx, str); | |
763 | acpigen_emit_ext_op(ctx, DEBUG_OP); | |
764 | } | |
f8054dd8 | 765 | |
da7cff33 SG |
766 | void acpigen_write_if(struct acpi_ctx *ctx) |
767 | { | |
768 | acpigen_emit_byte(ctx, IF_OP); | |
769 | acpigen_write_len_f(ctx); | |
770 | } | |
771 | ||
772 | void acpigen_write_if_lequal_op_int(struct acpi_ctx *ctx, uint op, u64 val) | |
773 | { | |
774 | acpigen_write_if(ctx); | |
775 | acpigen_emit_byte(ctx, LEQUAL_OP); | |
776 | acpigen_emit_byte(ctx, op); | |
777 | acpigen_write_integer(ctx, val); | |
778 | } | |
779 | ||
780 | void acpigen_write_else(struct acpi_ctx *ctx) | |
781 | { | |
782 | acpigen_emit_byte(ctx, ELSE_OP); | |
783 | acpigen_write_len_f(ctx); | |
784 | } | |
785 | ||
786 | void acpigen_write_to_buffer(struct acpi_ctx *ctx, uint src, uint dst) | |
787 | { | |
788 | acpigen_emit_byte(ctx, TO_BUFFER_OP); | |
789 | acpigen_emit_byte(ctx, src); | |
790 | acpigen_emit_byte(ctx, dst); | |
791 | } | |
792 | ||
793 | void acpigen_write_to_integer(struct acpi_ctx *ctx, uint src, uint dst) | |
794 | { | |
795 | acpigen_emit_byte(ctx, TO_INTEGER_OP); | |
796 | acpigen_emit_byte(ctx, src); | |
797 | acpigen_emit_byte(ctx, dst); | |
798 | } | |
799 | ||
800 | void acpigen_write_byte_buffer(struct acpi_ctx *ctx, u8 *arr, size_t size) | |
801 | { | |
802 | size_t i; | |
803 | ||
804 | acpigen_emit_byte(ctx, BUFFER_OP); | |
805 | acpigen_write_len_f(ctx); | |
806 | acpigen_write_integer(ctx, size); | |
807 | ||
808 | for (i = 0; i < size; i++) | |
809 | acpigen_emit_byte(ctx, arr[i]); | |
810 | ||
811 | acpigen_pop_len(ctx); | |
812 | } | |
813 | ||
814 | void acpigen_write_return_byte_buffer(struct acpi_ctx *ctx, u8 *arr, | |
815 | size_t size) | |
816 | { | |
817 | acpigen_emit_byte(ctx, RETURN_OP); | |
818 | acpigen_write_byte_buffer(ctx, arr, size); | |
819 | } | |
820 | ||
821 | void acpigen_write_return_singleton_buffer(struct acpi_ctx *ctx, uint arg) | |
822 | { | |
823 | u8 buf = arg; | |
824 | ||
825 | acpigen_write_return_byte_buffer(ctx, &buf, 1); | |
826 | } | |
827 | ||
828 | void acpigen_write_return_byte(struct acpi_ctx *ctx, uint arg) | |
829 | { | |
830 | acpigen_emit_byte(ctx, RETURN_OP); | |
831 | acpigen_write_byte(ctx, arg); | |
832 | } | |
833 | ||
88490e19 SG |
834 | void acpigen_write_dsm_start(struct acpi_ctx *ctx) |
835 | { | |
836 | /* Method (_DSM, 4, Serialized) */ | |
837 | acpigen_write_method_serialized(ctx, "_DSM", 4); | |
838 | ||
839 | /* ToBuffer (Arg0, Local0) */ | |
840 | acpigen_write_to_buffer(ctx, ARG0_OP, LOCAL0_OP); | |
841 | } | |
842 | ||
843 | int acpigen_write_dsm_uuid_start(struct acpi_ctx *ctx, const char *uuid) | |
844 | { | |
845 | int ret; | |
846 | ||
847 | /* If (LEqual (Local0, ToUUID(uuid))) */ | |
848 | acpigen_write_if(ctx); | |
849 | acpigen_emit_byte(ctx, LEQUAL_OP); | |
850 | acpigen_emit_byte(ctx, LOCAL0_OP); | |
851 | ret = acpigen_write_uuid(ctx, uuid); | |
852 | if (ret) | |
853 | return log_msg_ret("uuid", ret); | |
854 | ||
855 | /* ToInteger (Arg2, Local1) */ | |
856 | acpigen_write_to_integer(ctx, ARG2_OP, LOCAL1_OP); | |
857 | ||
858 | return 0; | |
859 | } | |
860 | ||
861 | void acpigen_write_dsm_uuid_start_cond(struct acpi_ctx *ctx, int seq) | |
862 | { | |
863 | /* If (LEqual (Local1, i)) */ | |
864 | acpigen_write_if_lequal_op_int(ctx, LOCAL1_OP, seq); | |
865 | } | |
866 | ||
867 | void acpigen_write_dsm_uuid_end_cond(struct acpi_ctx *ctx) | |
868 | { | |
869 | acpigen_pop_len(ctx); /* If */ | |
870 | } | |
871 | ||
872 | void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx) | |
873 | { | |
874 | /* Default case: Return (Buffer (One) { 0x0 }) */ | |
875 | acpigen_write_return_singleton_buffer(ctx, 0x0); | |
876 | ||
877 | acpigen_pop_len(ctx); /* If (LEqual (Local0, ToUUID(uuid))) */ | |
878 | } | |
879 | ||
880 | void acpigen_write_dsm_end(struct acpi_ctx *ctx) | |
881 | { | |
882 | /* Return (Buffer (One) { 0x0 }) */ | |
883 | acpigen_write_return_singleton_buffer(ctx, 0x0); | |
884 | ||
885 | acpigen_pop_len(ctx); /* Method _DSM */ | |
886 | } | |
887 | ||
f8054dd8 SG |
888 | /** |
889 | * acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5 | |
890 | * | |
891 | * Store (\_SB.GPC0 (addr), Local5) | |
892 | * | |
893 | * \_SB.GPC0 is used to read cfg0 value from dw0. It is typically defined in | |
894 | * the board's gpiolib.asl | |
895 | * | |
896 | * The value needs to be stored in a local variable so that it can be used in | |
897 | * expressions in the ACPI code. | |
898 | * | |
899 | * @ctx: ACPI context pointer | |
900 | * @dw0_read: Name to use to read dw0, e.g. "\\_SB.GPC0" | |
901 | * @addr: GPIO pin configuration register address | |
902 | * | |
903 | */ | |
904 | static void acpigen_get_dw0_in_local5(struct acpi_ctx *ctx, | |
905 | const char *dw0_read, ulong addr) | |
906 | { | |
907 | acpigen_write_store(ctx); | |
908 | acpigen_emit_namestring(ctx, dw0_read); | |
909 | acpigen_write_integer(ctx, addr); | |
910 | acpigen_emit_byte(ctx, LOCAL5_OP); | |
911 | } | |
912 | ||
913 | /** | |
914 | * acpigen_set_gpio_val() - Emit code to set value of TX GPIO to on/off | |
915 | * | |
916 | * @ctx: ACPI context pointer | |
917 | * @dw0_read: Method name to use to read dw0, e.g. "\\_SB.GPC0" | |
918 | * @dw0_write: Method name to use to read dw0, e.g. "\\_SB.SPC0" | |
919 | * @gpio_num: GPIO number to adjust | |
920 | * @vaL: true to set on, false to set off | |
921 | */ | |
922 | static int acpigen_set_gpio_val(struct acpi_ctx *ctx, u32 tx_state_val, | |
923 | const char *dw0_read, const char *dw0_write, | |
924 | struct acpi_gpio *gpio, bool val) | |
925 | { | |
926 | acpigen_get_dw0_in_local5(ctx, dw0_read, gpio->pin0_addr); | |
927 | ||
928 | /* Store (0x40, Local0) */ | |
929 | acpigen_write_store(ctx); | |
930 | acpigen_write_integer(ctx, tx_state_val); | |
931 | acpigen_emit_byte(ctx, LOCAL0_OP); | |
932 | ||
933 | if (val) { | |
934 | /* Or (Local5, PAD_CFG0_TX_STATE, Local5) */ | |
935 | acpigen_write_or(ctx, LOCAL5_OP, LOCAL0_OP, LOCAL5_OP); | |
936 | } else { | |
937 | /* Not (PAD_CFG0_TX_STATE, Local6) */ | |
938 | acpigen_write_not(ctx, LOCAL0_OP, LOCAL6_OP); | |
939 | ||
940 | /* And (Local5, Local6, Local5) */ | |
941 | acpigen_write_and(ctx, LOCAL5_OP, LOCAL6_OP, LOCAL5_OP); | |
942 | } | |
943 | ||
944 | /* | |
945 | * \_SB.SPC0 (addr, Local5) | |
946 | * \_SB.SPC0 is used to write cfg0 value in dw0. It is defined in | |
947 | * gpiolib.asl. | |
948 | */ | |
949 | acpigen_emit_namestring(ctx, dw0_write); | |
950 | acpigen_write_integer(ctx, gpio->pin0_addr); | |
951 | acpigen_emit_byte(ctx, LOCAL5_OP); | |
952 | ||
953 | return 0; | |
954 | } | |
955 | ||
956 | int acpigen_set_enable_tx_gpio(struct acpi_ctx *ctx, u32 tx_state_val, | |
957 | const char *dw0_read, const char *dw0_write, | |
958 | struct acpi_gpio *gpio, bool enable) | |
959 | { | |
960 | bool set; | |
961 | int ret; | |
962 | ||
963 | set = gpio->polarity == ACPI_GPIO_ACTIVE_HIGH ? enable : !enable; | |
964 | ret = acpigen_set_gpio_val(ctx, tx_state_val, dw0_read, dw0_write, gpio, | |
965 | set); | |
966 | if (ret) | |
967 | return log_msg_ret("call", ret); | |
968 | ||
969 | return 0; | |
970 | } |