blob: 64ec7343e1fde9965c22b271a755359a5b09e3f6 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Rudolf Marek293b5f52009-02-01 18:35:15 +00002
Paul Menzel0f4c0e22013-02-22 12:33:08 +01003/* How much nesting do we support? */
Rudolf Marek293b5f52009-02-01 18:35:15 +00004#define ACPIGEN_LENSTACK_SIZE 10
5
Felix Held575ee132023-11-13 14:50:35 +01006/* If you need to change this, change acpigen_pop_len too */
7#define ACPIGEN_RSVD_PKGLEN_BYTES 3
Rudolf Marek293b5f52009-02-01 18:35:15 +00008
Duncan Laurie3829f232016-05-09 11:08:46 -07009#include <lib.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000010#include <string.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070011#include <acpi/acpigen.h>
Elyes HAOUAScd4fe0f2019-03-29 17:12:15 +010012#include <assert.h>
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -060013#include <commonlib/helpers.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000014#include <console/console.h>
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +000015#include <device/device.h>
Duncan Laurie08a942f2020-04-29 12:13:14 -070016#include <device/soundwire.h>
Elyes HAOUAScdd2f632021-02-11 19:37:11 +010017#include <types.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000018
19static char *gencurrent;
20
21char *len_stack[ACPIGEN_LENSTACK_SIZE];
22int ltop = 0;
23
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +010024void acpigen_write_len_f(void)
Rudolf Marek293b5f52009-02-01 18:35:15 +000025{
26 ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1))
Paul Menzel0f4c0e22013-02-22 12:33:08 +010027 len_stack[ltop++] = gencurrent;
Felix Held575ee132023-11-13 14:50:35 +010028 /* Reserve ACPIGEN_RSVD_PKGLEN_BYTES bytes for PkgLength. The actual byte values will
29 be written later in the corresponding acpigen_pop_len call. */
30 for (size_t i = 0; i < ACPIGEN_RSVD_PKGLEN_BYTES; i++)
31 acpigen_emit_byte(0);
Rudolf Marek293b5f52009-02-01 18:35:15 +000032}
33
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010034void acpigen_pop_len(void)
35{
Felix Helda6f74592023-11-10 19:57:27 +010036 size_t len;
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010037 ASSERT(ltop > 0)
38 char *p = len_stack[--ltop];
39 len = gencurrent - p;
Felix Held575ee132023-11-13 14:50:35 +010040 const size_t payload_len = len - ACPIGEN_RSVD_PKGLEN_BYTES;
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010041
Felix Helda6f74592023-11-10 19:57:27 +010042 if (len <= 0x3f + 2) {
43 /* PkgLength of up to 0x3f can be encoded in one PkgLength byte instead of the
44 reserved 3 bytes. Since only 1 PkgLength byte will be written, the payload
45 data needs to be moved by 2 bytes */
Felix Held575ee132023-11-13 14:50:35 +010046 memmove(&p[ACPIGEN_RSVD_PKGLEN_BYTES - 2],
47 &p[ACPIGEN_RSVD_PKGLEN_BYTES], payload_len);
Felix Helda6f74592023-11-10 19:57:27 +010048 /* Adjust the PkgLength to take into account that we only use 1 of the 3
49 reserved bytes */
50 len -= 2;
51 /* The two most significant bits of PkgLength get the value of 0 to indicate
52 there are no additional PkgLength bytes. In this case the single PkgLength
53 byte encodes the length in its lower 6 bits */
54 p[0] = len;
55 /* Adjust pointer for next ACPI bytecode byte */
56 acpigen_set_current(p + len);
57 } else if (len <= 0xfff + 1) {
58 /* PkgLength of up to 0xfff can be encoded in 2 PkgLength bytes instead of the
59 reserved 3 bytes. Since only 2 PkgLength bytes will be written, the payload
60 data needs to be moved by 1 byte */
Felix Held575ee132023-11-13 14:50:35 +010061 memmove(&p[ACPIGEN_RSVD_PKGLEN_BYTES - 1],
62 &p[ACPIGEN_RSVD_PKGLEN_BYTES], payload_len);
Felix Helda6f74592023-11-10 19:57:27 +010063 /* Adjust the PkgLength to take into account that we only use 2 of the 3
64 reserved bytes */
65 len -= 1;
66 /* The two most significant bits of PkgLength get the value of 1 to indicate
67 there's a second PkgLength byte. The lower 4 bits of the first PkgLength
68 byte and the second PkgLength byte encode the length */
69 p[0] = (0x1 << 6 | (len & 0xf));
70 p[1] = (len >> 4 & 0xff);
71 /* Adjust pointer for next ACPI bytecode byte */
72 acpigen_set_current(p + len);
73 } else if (len <= 0xfffff) {
74 /* PkgLength of up to 0xfffff can be encoded in 3 PkgLength bytes. Since this
75 is the amount of reserved bytes, no need to move the payload in this case */
76 /* The two most significant bits of PkgLength get the value of 2 to indicate
77 there are two more PkgLength bytes following the first one. The lower 4 bits
78 of the first PkgLength byte and the two following PkgLength bytes encode the
79 length */
80 p[0] = (0x2 << 6 | (len & 0xf));
81 p[1] = (len >> 4 & 0xff);
82 p[2] = (len >> 12 & 0xff);
83 /* No need to adjust pointer for next ACPI bytecode byte */
84 } else {
85 /* The case of PkgLength up to 0xfffffff isn't supported at the moment */
86 printk(BIOS_ERR, "%s: package length exceeds maximum of 0xfffff.\n", __func__);
87 }
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010088}
89
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000090void acpigen_set_current(char *curr)
91{
92 gencurrent = curr;
Rudolf Marek293b5f52009-02-01 18:35:15 +000093}
94
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000095char *acpigen_get_current(void)
96{
97 return gencurrent;
Rudolf Marek293b5f52009-02-01 18:35:15 +000098}
99
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100100void acpigen_emit_byte(unsigned char b)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000101{
102 (*gencurrent++) = b;
Rudolf Marek293b5f52009-02-01 18:35:15 +0000103}
104
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700105void acpigen_emit_ext_op(uint8_t op)
106{
107 acpigen_emit_byte(EXT_OP_PREFIX);
108 acpigen_emit_byte(op);
109}
110
Duncan Laurie9ccae752016-05-09 07:43:19 -0700111void acpigen_emit_word(unsigned int data)
112{
113 acpigen_emit_byte(data & 0xff);
114 acpigen_emit_byte((data >> 8) & 0xff);
115}
116
117void acpigen_emit_dword(unsigned int data)
118{
119 acpigen_emit_byte(data & 0xff);
120 acpigen_emit_byte((data >> 8) & 0xff);
121 acpigen_emit_byte((data >> 16) & 0xff);
122 acpigen_emit_byte((data >> 24) & 0xff);
123}
124
Duncan Laurie85d80272016-07-02 19:53:54 -0700125char *acpigen_write_package(int nr_el)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000126{
Duncan Laurie85d80272016-07-02 19:53:54 -0700127 char *p;
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700128 acpigen_emit_byte(PACKAGE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100129 acpigen_write_len_f();
Duncan Laurie85d80272016-07-02 19:53:54 -0700130 p = acpigen_get_current();
Rudolf Marek293b5f52009-02-01 18:35:15 +0000131 acpigen_emit_byte(nr_el);
Duncan Laurie85d80272016-07-02 19:53:54 -0700132 return p;
Rudolf Marek293b5f52009-02-01 18:35:15 +0000133}
134
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100135void acpigen_write_byte(unsigned int data)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000136{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700137 acpigen_emit_byte(BYTE_PREFIX);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000138 acpigen_emit_byte(data & 0xff);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000139}
140
Duncan Laurie9ccae752016-05-09 07:43:19 -0700141void acpigen_write_word(unsigned int data)
142{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700143 acpigen_emit_byte(WORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700144 acpigen_emit_word(data);
145}
146
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100147void acpigen_write_dword(unsigned int data)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000148{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700149 acpigen_emit_byte(DWORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700150 acpigen_emit_dword(data);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000151}
152
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100153void acpigen_write_qword(uint64_t data)
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000154{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700155 acpigen_emit_byte(QWORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700156 acpigen_emit_dword(data & 0xffffffff);
157 acpigen_emit_dword((data >> 32) & 0xffffffff);
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000158}
159
Duncan Laurief7c38762016-05-09 08:20:38 -0700160void acpigen_write_zero(void)
161{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700162 acpigen_emit_byte(ZERO_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700163}
164
165void acpigen_write_one(void)
166{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700167 acpigen_emit_byte(ONE_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700168}
169
170void acpigen_write_ones(void)
171{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700172 acpigen_emit_byte(ONES_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700173}
174
175void acpigen_write_integer(uint64_t data)
176{
177 if (data == 0)
178 acpigen_write_zero();
179 else if (data == 1)
180 acpigen_write_one();
181 else if (data <= 0xff)
182 acpigen_write_byte((unsigned char)data);
183 else if (data <= 0xffff)
184 acpigen_write_word((unsigned int)data);
185 else if (data <= 0xffffffff)
186 acpigen_write_dword((unsigned int)data);
187 else
188 acpigen_write_qword(data);
189}
190
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100191void acpigen_write_name_byte(const char *name, uint8_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000192{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100193 acpigen_write_name(name);
194 acpigen_write_byte(val);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000195}
196
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100197void acpigen_write_name_dword(const char *name, uint32_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000198{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100199 acpigen_write_name(name);
200 acpigen_write_dword(val);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000201}
202
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100203void acpigen_write_name_qword(const char *name, uint64_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000204{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100205 acpigen_write_name(name);
206 acpigen_write_qword(val);
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000207}
208
Duncan Laurief7c38762016-05-09 08:20:38 -0700209void acpigen_write_name_integer(const char *name, uint64_t val)
210{
211 acpigen_write_name(name);
212 acpigen_write_integer(val);
213}
214
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700215void acpigen_write_name_string(const char *name, const char *string)
216{
217 acpigen_write_name(name);
218 acpigen_write_string(string);
219}
220
Patrick Rudolph389c8272019-12-17 13:54:41 +0100221void acpigen_write_name_unicode(const char *name, const char *string)
222{
223 const size_t len = strlen(string) + 1;
224 acpigen_write_name(name);
225 acpigen_emit_byte(BUFFER_OP);
226 acpigen_write_len_f();
Matt DeVillierd4d40c62023-11-09 15:04:58 -0600227 acpigen_write_integer(2 * len);
Patrick Rudolph389c8272019-12-17 13:54:41 +0100228 for (size_t i = 0; i < len; i++) {
Arthur Heymans62ea7a82023-06-22 20:39:31 +0200229 const signed char c = string[i];
Patrick Rudolph389c8272019-12-17 13:54:41 +0100230 /* Simple ASCII to UTF-16 conversion, replace non ASCII characters */
231 acpigen_emit_word(c >= 0 ? c : '?');
232 }
233 acpigen_pop_len();
234}
235
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100236void acpigen_emit_stream(const char *data, int size)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000237{
Rudolf Marek293b5f52009-02-01 18:35:15 +0000238 int i;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700239 for (i = 0; i < size; i++)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000240 acpigen_emit_byte(data[i]);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000241}
242
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700243void acpigen_emit_string(const char *string)
244{
Jonathan Neuschäfer0ba307f2016-05-17 17:40:09 +0200245 acpigen_emit_stream(string, string ? strlen(string) : 0);
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700246 acpigen_emit_byte('\0'); /* NUL */
247}
248
249void acpigen_write_string(const char *string)
250{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700251 acpigen_emit_byte(STRING_PREFIX);
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700252 acpigen_emit_string(string);
253}
254
Duncan Laurie37319032016-05-26 12:47:05 -0700255void acpigen_write_coreboot_hid(enum coreboot_acpi_ids id)
256{
Joel Kitching3ab36b842018-03-08 12:09:32 +0800257 char hid[9]; /* BOOTxxxx */
Duncan Laurie37319032016-05-26 12:47:05 -0700258
Duncan Laurie02fdb3e2016-09-22 14:08:33 -0700259 snprintf(hid, sizeof(hid), "%.4s%04X", COREBOOT_ACPI_ID, id);
Duncan Laurie37319032016-05-26 12:47:05 -0700260 acpigen_write_name_string("_HID", hid);
261}
262
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100263/*
264 * The naming conventions for ACPI namespace names are a bit tricky as
Martin Roth0cd338e2016-07-29 14:07:30 -0600265 * each element has to be 4 chars wide ("All names are a fixed 32 bits.")
266 * and "By convention, when an ASL compiler pads a name shorter than 4
267 * characters, it is done so with trailing underscores ('_')".
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100268 *
269 * Check sections 5.3, 18.2.2 and 18.4 of ACPI spec 3.0 for details.
270 */
Rudolf Marek3310d752009-06-21 20:26:13 +0000271
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700272static void acpigen_emit_simple_namestring(const char *name)
273{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100274 int i;
Rudolf Marek3310d752009-06-21 20:26:13 +0000275 char ud[] = "____";
276 for (i = 0; i < 4; i++) {
277 if ((name[i] == '\0') || (name[i] == '.')) {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100278 acpigen_emit_stream(ud, 4 - i);
Rudolf Marek3310d752009-06-21 20:26:13 +0000279 break;
Rudolf Marek3310d752009-06-21 20:26:13 +0000280 }
Lee Leahy0b5678f2017-03-16 16:01:40 -0700281 acpigen_emit_byte(name[i]);
Rudolf Marek3310d752009-06-21 20:26:13 +0000282 }
Rudolf Marek3310d752009-06-21 20:26:13 +0000283}
284
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700285static void acpigen_emit_double_namestring(const char *name, int dotpos)
286{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700287 acpigen_emit_byte(DUAL_NAME_PREFIX);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100288 acpigen_emit_simple_namestring(name);
289 acpigen_emit_simple_namestring(&name[dotpos + 1]);
Rudolf Marek3310d752009-06-21 20:26:13 +0000290}
291
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700292static void acpigen_emit_multi_namestring(const char *name)
293{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100294 int count = 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000295 unsigned char *pathlen;
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700296 acpigen_emit_byte(MULTI_NAME_PREFIX);
297 acpigen_emit_byte(ZERO_OP);
Elyes Haouas3141fbad2022-11-18 15:22:32 +0100298 pathlen = ((unsigned char *)acpigen_get_current()) - 1;
Rudolf Marek3310d752009-06-21 20:26:13 +0000299
300 while (name[0] != '\0') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100301 acpigen_emit_simple_namestring(name);
Rudolf Marek3310d752009-06-21 20:26:13 +0000302 /* find end or next entity */
303 while ((name[0] != '.') && (name[0] != '\0'))
304 name++;
305 /* forward to next */
306 if (name[0] == '.')
307 name++;
308 count++;
309 }
310
311 pathlen[0] = count;
Rudolf Marek3310d752009-06-21 20:26:13 +0000312}
313
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700314void acpigen_emit_namestring(const char *namepath)
315{
Rudolf Marek3310d752009-06-21 20:26:13 +0000316 int dotcount = 0, i;
Myles Watson3fe6b702009-10-09 20:13:43 +0000317 int dotpos = 0;
Rudolf Marek3310d752009-06-21 20:26:13 +0000318
Ronak Kanabar7c0f0072020-11-30 15:40:51 +0530319 /* Check for NULL pointer */
320 if (!namepath)
321 return;
322
Ronald G. Minnichbe738eb2013-03-07 11:05:28 -0600323 /* We can start with a '\'. */
Rudolf Marek3310d752009-06-21 20:26:13 +0000324 if (namepath[0] == '\\') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100325 acpigen_emit_byte('\\');
Rudolf Marek3310d752009-06-21 20:26:13 +0000326 namepath++;
327 }
328
Ronald G. Minnichbe738eb2013-03-07 11:05:28 -0600329 /* And there can be any number of '^' */
Rudolf Marek3310d752009-06-21 20:26:13 +0000330 while (namepath[0] == '^') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100331 acpigen_emit_byte('^');
Rudolf Marek3310d752009-06-21 20:26:13 +0000332 namepath++;
333 }
334
Vladimir Serbinenkod942ed92014-08-30 20:44:37 +0200335 /* If we have only \\ or only ^...^. Then we need to put a null
336 name (0x00). */
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200337 if (namepath[0] == '\0') {
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700338 acpigen_emit_byte(ZERO_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100339 return;
Vladimir Serbinenkod942ed92014-08-30 20:44:37 +0200340 }
Rudolf Marek3310d752009-06-21 20:26:13 +0000341
342 i = 0;
343 while (namepath[i] != '\0') {
344 if (namepath[i] == '.') {
345 dotcount++;
346 dotpos = i;
347 }
348 i++;
349 }
350
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700351 if (dotcount == 0)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100352 acpigen_emit_simple_namestring(namepath);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700353 else if (dotcount == 1)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100354 acpigen_emit_double_namestring(namepath, dotpos);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700355 else
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100356 acpigen_emit_multi_namestring(namepath);
Rudolf Marek3310d752009-06-21 20:26:13 +0000357}
358
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100359void acpigen_write_name(const char *name)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000360{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700361 acpigen_emit_byte(NAME_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100362 acpigen_emit_namestring(name);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000363}
364
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100365void acpigen_write_scope(const char *name)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000366{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700367 acpigen_emit_byte(SCOPE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100368 acpigen_write_len_f();
369 acpigen_emit_namestring(name);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000370}
Rudolf Marekf997b552009-02-14 15:40:23 +0000371
Duncan Laurie2fe74712020-06-01 17:36:56 -0700372void acpigen_get_package_op_element(uint8_t package_op, unsigned int element, uint8_t dest_op)
373{
Duncan Laurieec2e3e42020-11-03 15:19:08 -0800374 /* <dest_op> = DeRefOf (<package_op>[<element>]) */
Duncan Laurie2fe74712020-06-01 17:36:56 -0700375 acpigen_write_store();
376 acpigen_emit_byte(DEREF_OP);
377 acpigen_emit_byte(INDEX_OP);
378 acpigen_emit_byte(package_op);
379 acpigen_write_integer(element);
380 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
381 acpigen_emit_byte(dest_op);
382}
383
Duncan Laurieec2e3e42020-11-03 15:19:08 -0800384void acpigen_set_package_op_element_int(uint8_t package_op, unsigned int element, uint64_t src)
385{
386 /* DeRefOf (<package>[<element>]) = <src> */
387 acpigen_write_store();
388 acpigen_write_integer(src);
389 acpigen_emit_byte(DEREF_OP);
390 acpigen_emit_byte(INDEX_OP);
391 acpigen_emit_byte(package_op);
392 acpigen_write_integer(element);
393 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
394}
395
396void acpigen_get_package_element(const char *package, unsigned int element, uint8_t dest_op)
397{
398 /* <dest_op> = <package>[<element>] */
399 acpigen_write_store();
400 acpigen_emit_byte(INDEX_OP);
401 acpigen_emit_namestring(package);
402 acpigen_write_integer(element);
403 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
404 acpigen_emit_byte(dest_op);
405}
406
407void acpigen_set_package_element_int(const char *package, unsigned int element, uint64_t src)
408{
409 /* <package>[<element>] = <src> */
410 acpigen_write_store();
411 acpigen_write_integer(src);
412 acpigen_emit_byte(INDEX_OP);
413 acpigen_emit_namestring(package);
414 acpigen_write_integer(element);
415 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
416}
417
418void acpigen_set_package_element_namestr(const char *package, unsigned int element,
419 const char *src)
420{
421 /* <package>[<element>] = <src> */
422 acpigen_write_store();
423 acpigen_emit_namestring(src);
424 acpigen_emit_byte(INDEX_OP);
425 acpigen_emit_namestring(package);
426 acpigen_write_integer(element);
427 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
428}
429
Felix Heldb57b12f2023-01-24 19:31:00 +0100430void acpigen_write_processor_namestring(unsigned int cpu_index)
431{
432 char buffer[16];
Felix Heldf0a8b042023-05-12 15:55:06 +0200433 snprintf(buffer, sizeof(buffer), "\\_SB." CONFIG_ACPI_CPU_STRING, cpu_index);
Felix Heldb57b12f2023-01-24 19:31:00 +0100434 acpigen_emit_namestring(buffer);
435}
436
Elyes Haouas9c824912023-01-28 09:13:17 +0100437/* Processor() operator is deprecated as of ACPI 6.0, use Device() instead. */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100438void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
Rudolf Marekf997b552009-02-14 15:40:23 +0000439{
440/*
Christian Walterbe3979c2019-12-18 15:07:59 +0100441 Processor (\_SB.CPcpuindex, cpuindex, pblock_addr, pblock_len)
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200442 {
Rudolf Marekf997b552009-02-14 15:40:23 +0000443*/
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700444 acpigen_emit_ext_op(PROCESSOR_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100445 acpigen_write_len_f();
Felix Heldb57b12f2023-01-24 19:31:00 +0100446 acpigen_write_processor_namestring(cpuindex);
Rudolf Marekf997b552009-02-14 15:40:23 +0000447 acpigen_emit_byte(cpuindex);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700448 acpigen_emit_dword(pblock_addr);
Rudolf Marekf997b552009-02-14 15:40:23 +0000449 acpigen_emit_byte(pblock_len);
Rudolf Marekf997b552009-02-14 15:40:23 +0000450}
451
Felix Held32bba182023-01-28 03:37:21 +0100452void acpigen_write_processor_device(unsigned int cpu_index)
453{
454 acpigen_emit_ext_op(DEVICE_OP);
455 acpigen_write_len_f();
456 acpigen_write_processor_namestring(cpu_index);
457 acpigen_write_name_string("_HID", "ACPI0007");
458 acpigen_write_name_integer("_UID", cpu_index);
459}
460
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100461void acpigen_write_processor_package(const char *const name, const unsigned int first_core,
Nico Huber4d211ac2017-09-01 21:14:36 +0200462 const unsigned int core_count)
463{
464 unsigned int i;
Nico Huber4d211ac2017-09-01 21:14:36 +0200465
466 acpigen_write_name(name);
467 acpigen_write_package(core_count);
Felix Heldb57b12f2023-01-24 19:31:00 +0100468
469 for (i = first_core; i < first_core + core_count; ++i)
470 acpigen_write_processor_namestring(i);
471
Nico Huber4d211ac2017-09-01 21:14:36 +0200472 acpigen_pop_len();
473}
474
Arthur Heymans8f055272018-11-28 13:18:57 +0100475/* Method to notify all CPU cores */
476void acpigen_write_processor_cnot(const unsigned int number_of_cores)
477{
478 int core_id;
479
Christian Walterbe3979c2019-12-18 15:07:59 +0100480 acpigen_write_method("\\_SB.CNOT", 1);
Arthur Heymans8f055272018-11-28 13:18:57 +0100481 for (core_id = 0; core_id < number_of_cores; core_id++) {
Arthur Heymans8f055272018-11-28 13:18:57 +0100482 acpigen_emit_byte(NOTIFY_OP);
Felix Heldb57b12f2023-01-24 19:31:00 +0100483 acpigen_write_processor_namestring(core_id);
Arthur Heymans8f055272018-11-28 13:18:57 +0100484 acpigen_emit_byte(ARG0_OP);
485 }
486 acpigen_pop_len();
487}
488
Naresh G Solanki8535c662016-10-25 00:51:24 +0530489/*
490 * Generate ACPI AML code for OperationRegion
491 * Arg0: Pointer to struct opregion opreg = OPREGION(rname, space, offset, len)
492 * where rname is region name, space is region space, offset is region offset &
493 * len is region length.
494 * OperationRegion(regionname, regionspace, regionoffset, regionlength)
495 */
Duncan Laurie35029602020-10-09 17:50:25 +0000496void acpigen_write_opregion(const struct opregion *opreg)
Naresh G Solanki8535c662016-10-25 00:51:24 +0530497{
498 /* OpregionOp */
499 acpigen_emit_ext_op(OPREGION_OP);
500 /* NameString 4 chars only */
501 acpigen_emit_simple_namestring(opreg->name);
502 /* RegionSpace */
503 acpigen_emit_byte(opreg->regionspace);
504 /* RegionOffset & RegionLen, it can be byte word or double word */
505 acpigen_write_integer(opreg->regionoffset);
506 acpigen_write_integer(opreg->regionlen);
507}
508
Patrick Rudolph32bae492019-08-08 12:47:30 +0200509/*
510 * Generate ACPI AML code for Mutex
511 * Arg0: Pointer to name of mutex
512 * Arg1: Initial value of mutex
513 */
514void acpigen_write_mutex(const char *name, const uint8_t flags)
515{
516 /* MutexOp */
517 acpigen_emit_ext_op(MUTEX_OP);
Paweł Anikieled3b6882023-10-13 11:24:19 +0000518 acpigen_emit_namestring(name);
Patrick Rudolph32bae492019-08-08 12:47:30 +0200519 acpigen_emit_byte(flags);
520}
521
522void acpigen_write_acquire(const char *name, const uint16_t val)
523{
524 /* AcquireOp */
525 acpigen_emit_ext_op(ACQUIRE_OP);
Paweł Anikieled3b6882023-10-13 11:24:19 +0000526 acpigen_emit_namestring(name);
Patrick Rudolph32bae492019-08-08 12:47:30 +0200527 acpigen_emit_word(val);
528}
529
530void acpigen_write_release(const char *name)
531{
532 /* ReleaseOp */
533 acpigen_emit_ext_op(RELEASE_OP);
Paweł Anikieled3b6882023-10-13 11:24:19 +0000534 acpigen_emit_namestring(name);
Patrick Rudolph32bae492019-08-08 12:47:30 +0200535}
536
Patrick Rudolph894977b2017-07-01 16:15:05 +0200537static void acpigen_write_field_length(uint32_t len)
538{
539 uint8_t i, j;
540 uint8_t emit[4];
541
542 i = 1;
543 if (len < 0x40) {
544 emit[0] = len & 0x3F;
545 } else {
546 emit[0] = len & 0xF;
547 len >>= 4;
548 while (len) {
549 emit[i] = len & 0xFF;
550 i++;
551 len >>= 8;
552 }
553 }
554 /* Update bit 7:6 : Number of bytes followed by emit[0] */
555 emit[0] |= (i - 1) << 6;
556
557 for (j = 0; j < i; j++)
558 acpigen_emit_byte(emit[j]);
559}
560
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100561static void acpigen_write_field_offset(uint32_t offset, uint32_t current_bit_pos)
Naresh G Solanki8535c662016-10-25 00:51:24 +0530562{
563 uint32_t diff_bits;
Naresh G Solanki8535c662016-10-25 00:51:24 +0530564
565 if (offset < current_bit_pos) {
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100566 printk(BIOS_WARNING, "%s: Cannot move offset backward", __func__);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530567 return;
568 }
569
570 diff_bits = offset - current_bit_pos;
571 /* Upper limit */
572 if (diff_bits > 0xFFFFFFF) {
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100573 printk(BIOS_WARNING, "%s: Offset very large to encode", __func__);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530574 return;
575 }
576
Naresh G Solanki8535c662016-10-25 00:51:24 +0530577 acpigen_emit_byte(0);
Patrick Rudolph894977b2017-07-01 16:15:05 +0200578 acpigen_write_field_length(diff_bits);
579}
580
Michael Niewöhner060dc7b2022-05-13 00:04:19 +0200581void acpigen_write_field_name(const char *name, uint32_t size)
Patrick Rudolph894977b2017-07-01 16:15:05 +0200582{
583 acpigen_emit_simple_namestring(name);
584 acpigen_write_field_length(size);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530585}
586
Duncan Laurie095bbf92020-09-30 23:09:29 +0000587static void acpigen_write_field_reserved(uint32_t size)
588{
589 acpigen_emit_byte(0);
590 acpigen_write_field_length(size);
591}
592
Naresh G Solanki8535c662016-10-25 00:51:24 +0530593/*
594 * Generate ACPI AML code for Field
595 * Arg0: region name
596 * Arg1: Pointer to struct fieldlist.
597 * Arg2: no. of entries in Arg1
598 * Arg3: flags which indicate filed access type, lock rule & update rule.
599 * Example with fieldlist
600 * struct fieldlist l[] = {
601 * FIELDLIST_OFFSET(0x84),
602 * FIELDLIST_NAMESTR("PMCS", 2),
Duncan Laurie095bbf92020-09-30 23:09:29 +0000603 * FIELDLIST_RESERVED(6),
Naresh G Solanki8535c662016-10-25 00:51:24 +0530604 * };
Elyes HAOUASa342f392018-10-17 10:56:26 +0200605 * acpigen_write_field("UART", l, ARRAY_SIZE(l), FIELD_ANYACC | FIELD_NOLOCK |
Naresh G Solanki8535c662016-10-25 00:51:24 +0530606 * FIELD_PRESERVE);
607 * Output:
608 * Field (UART, AnyAcc, NoLock, Preserve)
609 * {
610 * Offset (0x84),
Duncan Laurie095bbf92020-09-30 23:09:29 +0000611 * PMCS, 2,
612 * , 6,
Naresh G Solanki8535c662016-10-25 00:51:24 +0530613 * }
614 */
Furquan Shaikhf9392992020-04-27 23:18:12 -0700615void acpigen_write_field(const char *name, const struct fieldlist *l, size_t count,
Naresh G Solanki8535c662016-10-25 00:51:24 +0530616 uint8_t flags)
617{
618 uint16_t i;
619 uint32_t current_bit_pos = 0;
620
621 /* FieldOp */
622 acpigen_emit_ext_op(FIELD_OP);
623 /* Package Length */
624 acpigen_write_len_f();
625 /* NameString 4 chars only */
626 acpigen_emit_simple_namestring(name);
627 /* Field Flag */
628 acpigen_emit_byte(flags);
629
630 for (i = 0; i < count; i++) {
631 switch (l[i].type) {
632 case NAME_STRING:
Patrick Rudolph894977b2017-07-01 16:15:05 +0200633 acpigen_write_field_name(l[i].name, l[i].bits);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530634 current_bit_pos += l[i].bits;
635 break;
Duncan Laurie095bbf92020-09-30 23:09:29 +0000636 case RESERVED:
637 acpigen_write_field_reserved(l[i].bits);
638 current_bit_pos += l[i].bits;
639 break;
Naresh G Solanki8535c662016-10-25 00:51:24 +0530640 case OFFSET:
641 acpigen_write_field_offset(l[i].bits, current_bit_pos);
642 current_bit_pos = l[i].bits;
643 break;
644 default:
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100645 printk(BIOS_ERR, "%s: Invalid field type 0x%X\n", __func__, l[i].type);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530646 break;
647 }
648 }
649 acpigen_pop_len();
650}
651
Patrick Rudolph34846ad2019-05-22 11:59:23 +0200652/*
653 * Generate ACPI AML code for IndexField
654 * Arg0: region name
655 * Arg1: Pointer to struct fieldlist.
656 * Arg2: no. of entries in Arg1
657 * Arg3: flags which indicate filed access type, lock rule & update rule.
658 * Example with fieldlist
659 * struct fieldlist l[] = {
660 * FIELDLIST_OFFSET(0x84),
661 * FIELDLIST_NAMESTR("PMCS", 2),
662 * };
663 * acpigen_write_field("IDX", "DATA" l, ARRAY_SIZE(l), FIELD_ANYACC |
664 * FIELD_NOLOCK |
665 * FIELD_PRESERVE);
666 * Output:
667 * IndexField (IDX, DATA, AnyAcc, NoLock, Preserve)
668 * {
669 * Offset (0x84),
670 * PMCS, 2
671 * }
672 */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100673void acpigen_write_indexfield(const char *idx, const char *data, struct fieldlist *l,
674 size_t count, uint8_t flags)
Patrick Rudolph34846ad2019-05-22 11:59:23 +0200675{
676 uint16_t i;
677 uint32_t current_bit_pos = 0;
678
679 /* FieldOp */
680 acpigen_emit_ext_op(INDEX_FIELD_OP);
681 /* Package Length */
682 acpigen_write_len_f();
683 /* NameString 4 chars only */
684 acpigen_emit_simple_namestring(idx);
685 /* NameString 4 chars only */
686 acpigen_emit_simple_namestring(data);
687 /* Field Flag */
688 acpigen_emit_byte(flags);
689
690 for (i = 0; i < count; i++) {
691 switch (l[i].type) {
692 case NAME_STRING:
693 acpigen_write_field_name(l[i].name, l[i].bits);
694 current_bit_pos += l[i].bits;
695 break;
696 case OFFSET:
697 acpigen_write_field_offset(l[i].bits, current_bit_pos);
698 current_bit_pos = l[i].bits;
699 break;
700 default:
Elyes Haouas1f5e1b42022-02-17 17:44:07 +0100701 printk(BIOS_ERR, "%s: Invalid field type 0x%X\n", __func__, l[i].type);
Patrick Rudolph34846ad2019-05-22 11:59:23 +0200702 break;
703 }
704 }
705 acpigen_pop_len();
706}
707
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100708void acpigen_write_empty_PCT(void)
Rudolf Marekf997b552009-02-14 15:40:23 +0000709{
710/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200711 Name (_PCT, Package (0x02)
712 {
713 ResourceTemplate ()
714 {
715 Register (FFixedHW,
716 0x00, // Bit Width
717 0x00, // Bit Offset
718 0x0000000000000000, // Address
719 ,)
720 },
Rudolf Marekf997b552009-02-14 15:40:23 +0000721
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200722 ResourceTemplate ()
723 {
724 Register (FFixedHW,
725 0x00, // Bit Width
726 0x00, // Bit Offset
727 0x0000000000000000, // Address
728 ,)
729 }
730 })
Rudolf Marekf997b552009-02-14 15:40:23 +0000731*/
732 static char stream[] = {
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700733 /* 00000030 "0._PCT.," */
734 0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C,
735 /* 00000038 "........" */
736 0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00,
737 /* 00000040 "........" */
738 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
739 /* 00000048 "....y..." */
740 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14,
741 /* 00000050 "........" */
742 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00,
743 /* 00000058 "........" */
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Rudolf Marekf997b552009-02-14 15:40:23 +0000745 0x00, 0x79, 0x00
746 };
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100747 acpigen_emit_stream(stream, ARRAY_SIZE(stream));
Rudolf Marekf997b552009-02-14 15:40:23 +0000748}
749
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300750void acpigen_write_PTC(uint8_t duty_width, uint8_t duty_offset, uint16_t p_cnt)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200751{
752/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200753 Name (_PTC, Package (0x02)
754 {
755 ResourceTemplate ()
756 {
757 Register (FFixedHW,
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300758 0x00, // Duty Width
759 0x00, // Duty Offset
760 0x0000000000000000, // P_CNT IO Address
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200761 ,)
762 },
Stefan Reinauer39205c62012-04-27 21:49:28 +0200763
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200764 ResourceTemplate ()
765 {
766 Register (FFixedHW,
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300767 0x00, // Duty Width
768 0x00, // Duty Offset
769 0x0000000000000000, // P_CNT IO Address
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200770 ,)
771 }
772 })
Stefan Reinauer39205c62012-04-27 21:49:28 +0200773*/
Stefan Reinauer39205c62012-04-27 21:49:28 +0200774 acpi_addr_t addr = {
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300775 .bit_width = duty_width,
776 .bit_offset = duty_offset,
Elyes HAOUAS721cb8a2020-06-23 09:13:42 +0200777 .access_size = ACPI_ACCESS_SIZE_UNDEFINED,
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300778 .addrl = p_cnt,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100779 .addrh = 0,
Stefan Reinauer39205c62012-04-27 21:49:28 +0200780 };
781
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300782 if (addr.addrl != 0)
783 addr.space_id = ACPI_ADDRESS_SPACE_IO;
784 else
785 addr.space_id = ACPI_ADDRESS_SPACE_FIXED;
786
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100787 acpigen_write_name("_PTC");
788 acpigen_write_package(2);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200789
790 /* ControlRegister */
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700791 acpigen_write_register_resource(&addr);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200792
793 /* StatusRegister */
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700794 acpigen_write_register_resource(&addr);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200795
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100796 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200797}
798
Kyösti Mälkkiddc37d62023-04-17 12:11:03 +0300799void acpigen_write_empty_PTC(void)
800{
801 acpigen_write_PTC(0, 0, 0);
802}
803
Furquan Shaikhfcc7a042016-10-20 23:12:38 -0700804static void __acpigen_write_method(const char *name, uint8_t flags)
Vladimir Serbinenko80fb8ed2014-11-05 10:28:28 +0100805{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700806 acpigen_emit_byte(METHOD_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100807 acpigen_write_len_f();
808 acpigen_emit_namestring(name);
Furquan Shaikhfcc7a042016-10-20 23:12:38 -0700809 acpigen_emit_byte(flags);
810}
811
812/* Method (name, nargs, NotSerialized) */
813void acpigen_write_method(const char *name, int nargs)
814{
815 __acpigen_write_method(name, (nargs & 7));
816}
817
818/* Method (name, nargs, Serialized) */
819void acpigen_write_method_serialized(const char *name, int nargs)
820{
821 __acpigen_write_method(name, (nargs & 7) | (1 << 3));
Vladimir Serbinenko80fb8ed2014-11-05 10:28:28 +0100822}
823
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100824void acpigen_write_device(const char *name)
Vladimir Serbinenko663be6e2014-11-05 21:29:45 +0100825{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700826 acpigen_emit_ext_op(DEVICE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100827 acpigen_write_len_f();
828 acpigen_emit_namestring(name);
Vladimir Serbinenko663be6e2014-11-05 21:29:45 +0100829}
830
Raul E Rangel052c9632021-05-12 17:01:30 -0600831void acpigen_write_thermal_zone(const char *name)
832{
833 acpigen_emit_ext_op(THERMAL_ZONE_OP);
834 acpigen_write_len_f();
835 acpigen_emit_namestring(name);
836}
837
Duncan Laurieabe2de82016-05-09 11:08:46 -0700838void acpigen_write_STA(uint8_t status)
839{
840 /*
841 * Method (_STA, 0, NotSerialized) { Return (status) }
842 */
843 acpigen_write_method("_STA", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700844 acpigen_emit_byte(RETURN_OP);
Duncan Laurieabe2de82016-05-09 11:08:46 -0700845 acpigen_write_byte(status);
846 acpigen_pop_len();
847}
848
Sugnan Prabhu S4f77f612020-06-10 09:51:02 +0530849void acpigen_write_STA_ext(const char *namestring)
850{
851 /*
852 * Method (_STA, 0, NotSerialized) { Return (ext_val) }
853 */
854 acpigen_write_method("_STA", 0);
855 acpigen_emit_byte(RETURN_OP);
856 acpigen_emit_namestring(namestring);
857 acpigen_pop_len();
858}
859
Felix Held2d4112f2023-05-04 23:00:06 +0200860void acpigen_write_BBN(uint8_t base_bus_number)
861{
862 /*
863 * Method (_BBN, 0, NotSerialized) { Return (status) }
864 */
865 acpigen_write_method("_BBN", 0);
866 acpigen_emit_byte(RETURN_OP);
867 acpigen_write_byte(base_bus_number);
868 acpigen_pop_len();
869}
870
Raul E Rangelc7048322021-04-19 15:58:25 -0600871void acpigen_write_LPI_package(u64 level, const struct acpi_lpi_state *states, u16 nentries)
872{
873 /*
874 * Name (_LPI, Package (0x06) // _LPI: Low Power Idle States
875 * {
876 * 0x0000,
877 * 0x0000000000000000,
878 * 0x0003,
879 * Package (0x0A)
880 * {
881 * 0x00000002,
882 * 0x00000001,
883 * 0x00000001,
884 * 0x00000000,
885 * 0x00000000,
886 * 0x00000000,
887 * ResourceTemplate ()
888 * {
889 * Register (FFixedHW,
890 * 0x02, // Bit Width
891 * 0x02, // Bit Offset
892 * 0x0000000000000000, // Address
893 * ,)
894 * },
895 *
896 * ResourceTemplate ()
897 * {
898 * Register (SystemMemory,
899 * 0x00, // Bit Width
900 * 0x00, // Bit Offset
901 * 0x0000000000000000, // Address
902 * ,)
903 * },
904 *
905 * ResourceTemplate ()
906 * {
907 * Register (SystemMemory,
908 * 0x00, // Bit Width
909 * 0x00, // Bit Offset
910 * 0x0000000000000000, // Address
911 * ,)
912 * },
913 *
914 * "C1"
915 * },
916 * ...
917 * }
918 */
919
920 acpigen_write_name("_LPI");
921 acpigen_write_package(3 + nentries);
922 acpigen_write_word(0); /* Revision */
923 acpigen_write_qword(level);
924 acpigen_write_word(nentries);
925
926 for (size_t i = 0; i < nentries; i++, states++) {
927 acpigen_write_package(0xA);
928 acpigen_write_dword(states->min_residency_us);
929 acpigen_write_dword(states->worst_case_wakeup_latency_us);
930 acpigen_write_dword(states->flags);
931 acpigen_write_dword(states->arch_context_lost_flags);
932 acpigen_write_dword(states->residency_counter_frequency_hz);
933 acpigen_write_dword(states->enabled_parent_state);
934 acpigen_write_register_resource(&states->entry_method);
935 acpigen_write_register_resource(&states->residency_counter_register);
936 acpigen_write_register_resource(&states->usage_counter_register);
937 acpigen_write_string(states->state_name);
938 acpigen_pop_len();
939 }
940 acpigen_pop_len();
941}
942
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100943/*
944 * Generates a func with max supported P-states.
945 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100946void acpigen_write_PPC(u8 nr)
Rudolf Marekf997b552009-02-14 15:40:23 +0000947{
948/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200949 Method (_PPC, 0, NotSerialized)
950 {
951 Return (nr)
952 }
Rudolf Marekf997b552009-02-14 15:40:23 +0000953*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100954 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700955 acpigen_emit_byte(RETURN_OP);
Rudolf Marekf997b552009-02-14 15:40:23 +0000956 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100957 acpigen_write_byte(nr);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100958 acpigen_pop_len();
Rudolf Marekf997b552009-02-14 15:40:23 +0000959}
960
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100961/*
962 * Generates a func with max supported P-states saved
963 * in the variable PPCM.
964 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100965void acpigen_write_PPC_NVS(void)
Duncan Laurie0eefa002012-07-16 12:11:53 -0700966{
967/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200968 Method (_PPC, 0, NotSerialized)
969 {
970 Return (PPCM)
971 }
Duncan Laurie0eefa002012-07-16 12:11:53 -0700972*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100973 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700974 acpigen_emit_byte(RETURN_OP);
Duncan Laurie0eefa002012-07-16 12:11:53 -0700975 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100976 acpigen_emit_namestring("PPCM");
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100977 acpigen_pop_len();
Duncan Laurie0eefa002012-07-16 12:11:53 -0700978}
979
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100980void acpigen_write_TPC(const char *gnvs_tpc_limit)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200981{
982/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200983 // Sample _TPC method
984 Method (_TPC, 0, NotSerialized)
985 {
986 Return (\TLVL)
987 }
988*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100989 acpigen_write_method("_TPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700990 acpigen_emit_byte(RETURN_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100991 acpigen_emit_namestring(gnvs_tpc_limit);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100992 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200993}
994
Duncan Laurieabe2de82016-05-09 11:08:46 -0700995void acpigen_write_PRW(u32 wake, u32 level)
996{
997 /*
998 * Name (_PRW, Package () { wake, level }
999 */
1000 acpigen_write_name("_PRW");
1001 acpigen_write_package(2);
1002 acpigen_write_integer(wake);
1003 acpigen_write_integer(level);
1004 acpigen_pop_len();
1005}
1006
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001007void acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, u32 busmLat, u32 control,
1008 u32 status)
Rudolf Marekf997b552009-02-14 15:40:23 +00001009{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001010 acpigen_write_package(6);
1011 acpigen_write_dword(coreFreq);
1012 acpigen_write_dword(power);
1013 acpigen_write_dword(transLat);
1014 acpigen_write_dword(busmLat);
1015 acpigen_write_dword(control);
1016 acpigen_write_dword(status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001017 acpigen_pop_len();
Stefan Reinauerd4bacf92012-05-02 16:38:47 -07001018
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001019 printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n", coreFreq, power,
1020 control, status);
Rudolf Marekf997b552009-02-14 15:40:23 +00001021}
Patrick Georgidf444bf2009-04-21 20:34:36 +00001022
Jason Gleneskca36aed2020-09-15 21:01:57 -07001023void acpigen_write_pss_object(const struct acpi_sw_pstate *pstate_values, size_t nentries)
1024{
1025 size_t pstate;
1026
1027 acpigen_write_name("_PSS");
1028 acpigen_write_package(nentries);
1029 for (pstate = 0; pstate < nentries; pstate++) {
1030 acpigen_write_PSS_package(
1031 pstate_values->core_freq, pstate_values->power,
1032 pstate_values->transition_latency, pstate_values->bus_master_latency,
1033 pstate_values->control_value, pstate_values->status_value);
1034 pstate_values++;
1035 }
1036
1037 acpigen_pop_len();
1038}
1039
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001040void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Patrick Georgidf444bf2009-04-21 20:34:36 +00001041{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001042 acpigen_write_name("_PSD");
1043 acpigen_write_package(1);
1044 acpigen_write_package(5);
1045 acpigen_write_byte(5); // 5 values
1046 acpigen_write_byte(0); // revision 0
1047 acpigen_write_dword(domain);
1048 acpigen_write_dword(coordtype);
1049 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001050 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001051 acpigen_pop_len();
Patrick Georgidf444bf2009-04-21 20:34:36 +00001052}
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001053
Angel Ponsd2794ce2021-10-17 12:59:43 +02001054void acpigen_write_CST_package_entry(const acpi_cstate_t *cstate)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001055{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001056 acpigen_write_package(4);
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001057 acpigen_write_register_resource(&cstate->resource);
Jason Glenesk201acca2020-09-11 12:36:15 -07001058 acpigen_write_byte(cstate->ctype);
1059 acpigen_write_word(cstate->latency);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001060 acpigen_write_dword(cstate->power);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001061 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +02001062}
1063
Angel Ponsd2794ce2021-10-17 12:59:43 +02001064void acpigen_write_CST_package(const acpi_cstate_t *cstate, int nentries)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001065{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001066 int i;
1067 acpigen_write_name("_CST");
1068 acpigen_write_package(nentries+1);
Jason Glenesk201acca2020-09-11 12:36:15 -07001069 acpigen_write_integer(nentries);
Sven Schnelle0b86c762011-10-21 21:46:47 +02001070
1071 for (i = 0; i < nentries; i++)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001072 acpigen_write_CST_package_entry(cstate + i);
Sven Schnelle0b86c762011-10-21 21:46:47 +02001073
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001074 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +02001075}
1076
Lee Leahy6f80ccc2017-03-16 15:18:22 -07001077void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype,
1078 u32 index)
Timothy Pearson83abd812015-06-08 19:35:06 -05001079{
1080 acpigen_write_name("_CSD");
1081 acpigen_write_package(1);
1082 acpigen_write_package(6);
Jason Glenesk201acca2020-09-11 12:36:15 -07001083 acpigen_write_integer(6); // 6 values
Timothy Pearson83abd812015-06-08 19:35:06 -05001084 acpigen_write_byte(0); // revision 0
1085 acpigen_write_dword(domain);
1086 acpigen_write_dword(coordtype);
1087 acpigen_write_dword(numprocs);
1088 acpigen_write_dword(index);
1089 acpigen_pop_len();
1090 acpigen_pop_len();
1091}
1092
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001093void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
Stefan Reinauer39205c62012-04-27 21:49:28 +02001094{
1095/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +02001096 Sample _TSS package with 100% and 50% duty cycles
1097 Name (_TSS, Package (0x02)
1098 {
1099 Package(){100, 1000, 0, 0x00, 0)
1100 Package(){50, 520, 0, 0x18, 0)
1101 })
1102*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001103 int i;
Stefan Reinauer39205c62012-04-27 21:49:28 +02001104 acpi_tstate_t *tstate = tstate_list;
1105
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001106 acpigen_write_name("_TSS");
1107 acpigen_write_package(entries);
Stefan Reinauer39205c62012-04-27 21:49:28 +02001108
1109 for (i = 0; i < entries; i++) {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001110 acpigen_write_package(5);
1111 acpigen_write_dword(tstate->percent);
1112 acpigen_write_dword(tstate->power);
1113 acpigen_write_dword(tstate->latency);
1114 acpigen_write_dword(tstate->control);
1115 acpigen_write_dword(tstate->status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001116 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001117 tstate++;
Stefan Reinauer39205c62012-04-27 21:49:28 +02001118 }
1119
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001120 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001121}
1122
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001123void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Stefan Reinauer39205c62012-04-27 21:49:28 +02001124{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001125 acpigen_write_name("_TSD");
1126 acpigen_write_package(1);
1127 acpigen_write_package(5);
1128 acpigen_write_byte(5); // 5 values
1129 acpigen_write_byte(0); // revision 0
1130 acpigen_write_dword(domain);
1131 acpigen_write_dword(coordtype);
1132 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001133 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001134 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001135}
1136
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001137void acpigen_write_mem32fixed(int readwrite, u32 base, u32 size)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001138{
1139 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001140 * ACPI 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001141 * Byte 0:
1142 * Bit7 : 1 => big item
1143 * Bit6-0: 0000110 (0x6) => 32-bit fixed memory
1144 */
1145 acpigen_emit_byte(0x86);
1146 /* Byte 1+2: length (0x0009) */
1147 acpigen_emit_byte(0x09);
1148 acpigen_emit_byte(0x00);
1149 /* bit1-7 are ignored */
1150 acpigen_emit_byte(readwrite ? 0x01 : 0x00);
Duncan Laurie9ccae752016-05-09 07:43:19 -07001151 acpigen_emit_dword(base);
1152 acpigen_emit_dword(size);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001153}
1154
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001155static void acpigen_write_register(const acpi_addr_t *addr)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001156{
Stefan Reinauer4cc8c702012-04-27 21:34:16 +02001157 acpigen_emit_byte(0x82); /* Register Descriptor */
1158 acpigen_emit_byte(0x0c); /* Register Length 7:0 */
1159 acpigen_emit_byte(0x00); /* Register Length 15:8 */
1160 acpigen_emit_byte(addr->space_id); /* Address Space ID */
1161 acpigen_emit_byte(addr->bit_width); /* Register Bit Width */
1162 acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +01001163 acpigen_emit_byte(addr->access_size); /* Register Access Size */
Duncan Laurie9ccae752016-05-09 07:43:19 -07001164 acpigen_emit_dword(addr->addrl); /* Register Address Low */
1165 acpigen_emit_dword(addr->addrh); /* Register Address High */
Sven Schnelle0b86c762011-10-21 21:46:47 +02001166}
1167
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001168void acpigen_write_register_resource(const acpi_addr_t *addr)
1169{
1170 acpigen_write_resourcetemplate_header();
1171 acpigen_write_register(addr);
1172 acpigen_write_resourcetemplate_footer();
1173}
1174
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001175void acpigen_write_irq(u16 mask)
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001176{
1177 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001178 * ACPI 3.0b section 6.4.2.1: IRQ Descriptor
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001179 * Byte 0:
1180 * Bit7 : 0 => small item
1181 * Bit6-3: 0100 (0x4) => IRQ port descriptor
1182 * Bit2-0: 010 (0x2) => 2 Bytes long
1183 */
1184 acpigen_emit_byte(0x22);
1185 acpigen_emit_byte(mask & 0xff);
1186 acpigen_emit_byte((mask >> 8) & 0xff);
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001187}
1188
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001189void acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001190{
1191 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001192 * ACPI 4.0 section 6.4.2.6: I/O Port Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001193 * Byte 0:
1194 * Bit7 : 0 => small item
1195 * Bit6-3: 1000 (0x8) => I/O port descriptor
1196 * Bit2-0: 111 (0x7) => 7 Bytes long
1197 */
1198 acpigen_emit_byte(0x47);
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001199 /* Does the device decode all 16 or just 10 bits? */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001200 /* bit1-7 are ignored */
1201 acpigen_emit_byte(decode16 ? 0x01 : 0x00);
1202 /* minimum base address the device may be configured for */
1203 acpigen_emit_byte(min & 0xff);
1204 acpigen_emit_byte((min >> 8) & 0xff);
1205 /* maximum base address the device may be configured for */
1206 acpigen_emit_byte(max & 0xff);
1207 acpigen_emit_byte((max >> 8) & 0xff);
1208 /* alignment for min base */
1209 acpigen_emit_byte(align & 0xff);
1210 acpigen_emit_byte(len & 0xff);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001211}
1212
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001213void acpigen_write_resourcetemplate_header(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001214{
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001215 /*
1216 * A ResourceTemplate() is a Buffer() with a
1217 * (Byte|Word|DWord) containing the length, followed by one or more
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001218 * resource items, terminated by the end tag.
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001219 * (small item 0xf, len 1)
1220 */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001221 acpigen_emit_byte(BUFFER_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001222 acpigen_write_len_f();
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001223 acpigen_emit_byte(WORD_PREFIX);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001224 len_stack[ltop++] = acpigen_get_current();
Nico Huber7d89ce32017-04-14 00:08:18 +02001225 /* Add 2 dummy bytes for the ACPI word (keep aligned with
Elyes HAOUAS6716bab2020-01-09 21:29:25 +01001226 the calculation in acpigen_write_resourcetemplate() below). */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001227 acpigen_emit_byte(0x00);
1228 acpigen_emit_byte(0x00);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001229}
1230
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001231void acpigen_write_resourcetemplate_footer(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001232{
1233 char *p = len_stack[--ltop];
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001234 int len;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001235 /*
1236 * end tag (acpi 4.0 Section 6.4.2.8)
1237 * 0x79 <checksum>
1238 * 0x00 is treated as a good checksum according to the spec
1239 * and is what iasl generates.
1240 */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001241 acpigen_emit_byte(0x79);
1242 acpigen_emit_byte(0x00);
1243
Nico Huber7d89ce32017-04-14 00:08:18 +02001244 /* Start counting past the 2-bytes length added in
1245 acpigen_write_resourcetemplate() above. */
1246 len = acpigen_get_current() - (p + 2);
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001247
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001248 /* patch len word */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001249 p[0] = len & 0xff;
1250 p[1] = (len >> 8) & 0xff;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001251 /* patch len field */
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001252 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001253}
1254
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001255static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, struct resource *res)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001256{
1257 acpigen_write_mem32fixed(0, res->base, res->size);
1258}
1259
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001260static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, struct resource *res)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001261{
1262 resource_t base = res->base;
1263 resource_t size = res->size;
1264 while (size > 0) {
1265 resource_t sz = size > 255 ? 255 : size;
1266 acpigen_write_io16(base, base, 0, sz, 1);
1267 size -= sz;
1268 base += sz;
1269 }
1270}
1271
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001272void acpigen_write_mainboard_resource_template(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001273{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001274 acpigen_write_resourcetemplate_header();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001275
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001276 /* Add reserved memory ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001277 search_global_resources(
1278 IORESOURCE_MEM | IORESOURCE_RESERVE,
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001279 IORESOURCE_MEM | IORESOURCE_RESERVE,
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001280 acpigen_add_mainboard_rsvd_mem32, 0);
1281
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001282 /* Add reserved io ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001283 search_global_resources(
1284 IORESOURCE_IO | IORESOURCE_RESERVE,
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001285 IORESOURCE_IO | IORESOURCE_RESERVE,
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001286 acpigen_add_mainboard_rsvd_io, 0);
1287
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001288 acpigen_write_resourcetemplate_footer();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001289}
1290
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001291void acpigen_write_mainboard_resources(const char *scope, const char *name)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001292{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001293 acpigen_write_scope(scope);
1294 acpigen_write_name(name);
1295 acpigen_write_mainboard_resource_template();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001296 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001297}
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001298
1299static int hex2bin(const char c)
1300{
1301 if (c >= 'A' && c <= 'F')
1302 return c - 'A' + 10;
1303 if (c >= 'a' && c <= 'f')
1304 return c - 'a' + 10;
1305 return c - '0';
1306}
1307
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001308void acpigen_emit_eisaid(const char *eisaid)
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001309{
1310 u32 compact = 0;
1311
1312 /* Clamping individual values would be better but
1313 there is a disagreement over what is a valid
1314 EISA id, so accept anything and don't clamp,
1315 parent code should create a valid EISAid.
1316 */
1317 compact |= (eisaid[0] - 'A' + 1) << 26;
1318 compact |= (eisaid[1] - 'A' + 1) << 21;
1319 compact |= (eisaid[2] - 'A' + 1) << 16;
1320 compact |= hex2bin(eisaid[3]) << 12;
1321 compact |= hex2bin(eisaid[4]) << 8;
1322 compact |= hex2bin(eisaid[5]) << 4;
1323 compact |= hex2bin(eisaid[6]);
1324
1325 acpigen_emit_byte(0xc);
1326 acpigen_emit_byte((compact >> 24) & 0xff);
1327 acpigen_emit_byte((compact >> 16) & 0xff);
1328 acpigen_emit_byte((compact >> 8) & 0xff);
1329 acpigen_emit_byte(compact & 0xff);
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001330}
Duncan Laurie3829f232016-05-09 11:08:46 -07001331
1332/*
1333 * ToUUID(uuid)
1334 *
1335 * ACPI 6.1 Section 19.6.136 table 19-385 defines a special output
1336 * order for the bytes that make up a UUID Buffer object.
1337 * UUID byte order for input:
1338 * aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
1339 * UUID byte order for output:
1340 * ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
1341 */
1342#define UUID_LEN 16
1343void acpigen_write_uuid(const char *uuid)
1344{
1345 uint8_t buf[UUID_LEN];
1346 size_t i, order[UUID_LEN] = { 3, 2, 1, 0, 5, 4, 7, 6,
1347 8, 9, 10, 11, 12, 13, 14, 15 };
1348
1349 /* Parse UUID string into bytes */
1350 if (hexstrtobin(uuid, buf, UUID_LEN) < UUID_LEN)
1351 return;
1352
1353 /* BufferOp */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001354 acpigen_emit_byte(BUFFER_OP);
Duncan Laurie3829f232016-05-09 11:08:46 -07001355 acpigen_write_len_f();
1356
1357 /* Buffer length in bytes */
1358 acpigen_write_word(UUID_LEN);
1359
1360 /* Output UUID in expected order */
1361 for (i = 0; i < UUID_LEN; i++)
1362 acpigen_emit_byte(buf[order[i]]);
1363
1364 acpigen_pop_len();
1365}
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001366
1367/*
1368 * Name (_PRx, Package(One) { name })
1369 * ...
1370 * PowerResource (name, level, order)
1371 */
1372void acpigen_write_power_res(const char *name, uint8_t level, uint16_t order,
Furquan Shaikhdc782752020-04-30 22:49:39 -07001373 const char * const dev_states[], size_t dev_states_count)
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001374{
Elyes HAOUAScca6e002019-06-26 12:12:00 +02001375 size_t i;
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001376 for (i = 0; i < dev_states_count; i++) {
1377 acpigen_write_name(dev_states[i]);
1378 acpigen_write_package(1);
1379 acpigen_emit_simple_namestring(name);
1380 acpigen_pop_len(); /* Package */
1381 }
1382
1383 acpigen_emit_ext_op(POWER_RES_OP);
1384
1385 acpigen_write_len_f();
1386
1387 acpigen_emit_simple_namestring(name);
1388 acpigen_emit_byte(level);
1389 acpigen_emit_word(order);
1390}
1391
1392/* Sleep (ms) */
1393void acpigen_write_sleep(uint64_t sleep_ms)
1394{
1395 acpigen_emit_ext_op(SLEEP_OP);
1396 acpigen_write_integer(sleep_ms);
1397}
1398
1399void acpigen_write_store(void)
1400{
1401 acpigen_emit_byte(STORE_OP);
1402}
1403
1404/* Store (src, dst) */
1405void acpigen_write_store_ops(uint8_t src, uint8_t dst)
1406{
1407 acpigen_write_store();
1408 acpigen_emit_byte(src);
1409 acpigen_emit_byte(dst);
1410}
1411
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001412/* Store (src, "namestr") */
1413void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst)
1414{
1415 acpigen_write_store();
1416 acpigen_emit_byte(src);
1417 acpigen_emit_namestring(dst);
1418}
1419
Duncan Laurie8e391d32020-09-30 23:17:41 +00001420/* Store (src, "namestr") */
1421void acpigen_write_store_int_to_namestr(uint64_t src, const char *dst)
1422{
1423 acpigen_write_store();
1424 acpigen_write_integer(src);
1425 acpigen_emit_namestring(dst);
1426}
1427
Cliff Huang24f3dc82023-02-04 21:11:51 -08001428/* Store ("namestr", dst) */
1429void acpigen_write_store_namestr_to_op(const char *src, uint8_t dst)
1430{
1431 acpigen_write_store();
1432 acpigen_emit_namestring(src);
1433 acpigen_emit_byte(dst);
1434}
1435
Duncan Laurie8e391d32020-09-30 23:17:41 +00001436/* Store (src, dst) */
1437void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
1438{
1439 acpigen_write_store();
1440 acpigen_write_integer(src);
1441 acpigen_emit_byte(dst);
1442}
1443
Felix Held178cf352023-02-09 16:29:46 +01001444/* Store ("namestr", "namestr") */
1445void acpigen_write_store_namestr_to_namestr(const char *src, const char *dst)
1446{
1447 acpigen_write_store();
1448 acpigen_emit_namestring(src);
1449 acpigen_emit_namestring(dst);
1450}
1451
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001452/* Or (arg1, arg2, res) */
1453void acpigen_write_or(uint8_t arg1, uint8_t arg2, uint8_t res)
1454{
1455 acpigen_emit_byte(OR_OP);
1456 acpigen_emit_byte(arg1);
1457 acpigen_emit_byte(arg2);
1458 acpigen_emit_byte(res);
1459}
1460
Rajat Jain310623b2020-02-26 11:02:53 -08001461/* Xor (arg1, arg2, res) */
1462void acpigen_write_xor(uint8_t arg1, uint8_t arg2, uint8_t res)
1463{
1464 acpigen_emit_byte(XOR_OP);
1465 acpigen_emit_byte(arg1);
1466 acpigen_emit_byte(arg2);
1467 acpigen_emit_byte(res);
1468}
1469
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001470/* And (arg1, arg2, res) */
1471void acpigen_write_and(uint8_t arg1, uint8_t arg2, uint8_t res)
1472{
1473 acpigen_emit_byte(AND_OP);
1474 acpigen_emit_byte(arg1);
1475 acpigen_emit_byte(arg2);
1476 acpigen_emit_byte(res);
1477}
1478
1479/* Not (arg, res) */
1480void acpigen_write_not(uint8_t arg, uint8_t res)
1481{
1482 acpigen_emit_byte(NOT_OP);
1483 acpigen_emit_byte(arg);
1484 acpigen_emit_byte(res);
1485}
1486
Cliff Huange6083082023-01-19 21:18:23 -08001487/* Concatenate (str, src_res, dest_res) */
1488void acpigen_concatenate_string_op(const char *str, uint8_t src_res, uint8_t dest_res)
1489{
1490 acpigen_emit_byte(CONCATENATE_OP);
1491 acpigen_write_string(str);
1492 acpigen_emit_byte(src_res);
1493 acpigen_emit_byte(dest_res);
1494}
1495
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001496/* Store (str, DEBUG) */
1497void acpigen_write_debug_string(const char *str)
1498{
1499 acpigen_write_store();
1500 acpigen_write_string(str);
1501 acpigen_emit_ext_op(DEBUG_OP);
1502}
1503
1504/* Store (val, DEBUG) */
1505void acpigen_write_debug_integer(uint64_t val)
1506{
1507 acpigen_write_store();
1508 acpigen_write_integer(val);
1509 acpigen_emit_ext_op(DEBUG_OP);
1510}
1511
1512/* Store (op, DEBUG) */
1513void acpigen_write_debug_op(uint8_t op)
1514{
1515 acpigen_write_store();
1516 acpigen_emit_byte(op);
1517 acpigen_emit_ext_op(DEBUG_OP);
1518}
1519
Duncan Laurieec2e3e42020-11-03 15:19:08 -08001520/* Store (str, DEBUG) */
1521void acpigen_write_debug_namestr(const char *str)
1522{
1523 acpigen_write_store();
1524 acpigen_emit_namestring(str);
1525 acpigen_emit_ext_op(DEBUG_OP);
1526}
1527
Cliff Huange6083082023-01-19 21:18:23 -08001528/* Concatenate (str1, res, tmp_res)
1529 Store(tmp_res, DEBUG) */
1530void acpigen_write_debug_concatenate_string_op(const char *str, uint8_t res,
1531 uint8_t tmp_res)
1532{
1533 acpigen_concatenate_string_op(str, res, tmp_res);
1534 acpigen_write_debug_op(tmp_res);
1535}
1536
Cliff Huang063a1b82023-02-18 00:17:26 -08001537static void acpigen_tx_byte(unsigned char byte, void *data)
1538{
1539 acpigen_emit_byte(byte);
1540}
1541
1542/* Store("formatted string", DEBUG) */
1543void acpigen_write_debug_sprintf(const char *fmt, ...)
1544{
1545 va_list args;
1546
1547 acpigen_write_store();
1548
1549 acpigen_emit_byte(STRING_PREFIX);
1550 va_start(args, fmt);
1551 vtxprintf(acpigen_tx_byte, fmt, args, NULL);
1552 va_end(args);
1553 acpigen_emit_byte('\0');
1554
1555 acpigen_emit_ext_op(DEBUG_OP);
1556}
1557
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001558void acpigen_write_if(void)
1559{
1560 acpigen_emit_byte(IF_OP);
1561 acpigen_write_len_f();
1562}
1563
1564/* If (And (arg1, arg2)) */
1565void acpigen_write_if_and(uint8_t arg1, uint8_t arg2)
1566{
1567 acpigen_write_if();
1568 acpigen_emit_byte(AND_OP);
1569 acpigen_emit_byte(arg1);
1570 acpigen_emit_byte(arg2);
1571}
1572
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001573/*
Duncan Laurie2fe74712020-06-01 17:36:56 -07001574 * Generates ACPI code for checking if operand1 and operand2 are equal.
1575 * Both operand1 and operand2 are ACPI ops.
1576 *
1577 * If (Lequal (op,1 op2))
1578 */
1579void acpigen_write_if_lequal_op_op(uint8_t op1, uint8_t op2)
1580{
1581 acpigen_write_if();
1582 acpigen_emit_byte(LEQUAL_OP);
1583 acpigen_emit_byte(op1);
1584 acpigen_emit_byte(op2);
1585}
1586
1587/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001588 * Generates ACPI code for checking if operand1 is greater than operand2.
1589 * Both operand1 and operand2 are ACPI ops.
1590 *
1591 * If (Lgreater (op1 op2))
1592 */
1593void acpigen_write_if_lgreater_op_op(uint8_t op1, uint8_t op2)
1594{
1595 acpigen_write_if();
1596 acpigen_emit_byte(LGREATER_OP);
1597 acpigen_emit_byte(op1);
1598 acpigen_emit_byte(op2);
1599}
1600
1601/*
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001602 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1603 * operand1 is ACPI op and operand2 is an integer.
1604 *
1605 * If (Lequal (op, val))
1606 */
1607void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001608{
1609 acpigen_write_if();
1610 acpigen_emit_byte(LEQUAL_OP);
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001611 acpigen_emit_byte(op);
1612 acpigen_write_integer(val);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001613}
1614
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001615/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001616 * Generates ACPI code for checking if operand is greater than the value, where,
1617 * operand is ACPI op and val is an integer.
1618 *
1619 * If (Lgreater (op, val))
1620 */
1621void acpigen_write_if_lgreater_op_int(uint8_t op, uint64_t val)
1622{
1623 acpigen_write_if();
1624 acpigen_emit_byte(LGREATER_OP);
1625 acpigen_emit_byte(op);
1626 acpigen_write_integer(val);
1627}
1628
1629/*
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001630 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1631 * operand1 is namestring and operand2 is an integer.
1632 *
1633 * If (Lequal ("namestr", val))
1634 */
1635void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val)
1636{
1637 acpigen_write_if();
1638 acpigen_emit_byte(LEQUAL_OP);
1639 acpigen_emit_namestring(namestr);
1640 acpigen_write_integer(val);
1641}
1642
Tim Wawrzynczakc4ca2f62021-07-01 11:18:50 -06001643/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001644 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1645 * operand1 is namestring and operand2 is an integer.
1646 *
1647 * If (Lgreater ("namestr", val))
1648 */
1649void acpigen_write_if_lgreater_namestr_int(const char *namestr, uint64_t val)
1650{
1651 acpigen_write_if();
1652 acpigen_emit_byte(LGREATER_OP);
1653 acpigen_emit_namestring(namestr);
1654 acpigen_write_integer(val);
1655}
1656
1657/*
Tim Wawrzynczakc4ca2f62021-07-01 11:18:50 -06001658 * Generates ACPI code to check at runtime if an object named `namestring`
1659 * exists, and leaves the If scope open to continue execute code when this
1660 * is true. NOTE: Requires matching acpigen_write_if_end().
1661 *
1662 * If (CondRefOf (NAME))
1663 */
1664void acpigen_write_if_cond_ref_of(const char *namestring)
1665{
1666 acpigen_write_if();
1667 acpigen_emit_ext_op(COND_REFOF_OP);
1668 acpigen_emit_namestring(namestring);
1669 acpigen_emit_byte(ZERO_OP); /* ignore COND_REFOF_OP destination */
1670}
1671
Jakub Czapiga61fcb7e2021-02-19 11:44:22 +01001672/* Closes previously opened if statement and generates ACPI code for else statement. */
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001673void acpigen_write_else(void)
1674{
Jakub Czapiga61fcb7e2021-02-19 11:44:22 +01001675 acpigen_pop_len();
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001676 acpigen_emit_byte(ELSE_OP);
1677 acpigen_write_len_f();
1678}
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001679
Duncan Laurie36858202020-10-06 21:01:51 +00001680void acpigen_write_shiftleft_op_int(uint8_t src_result, uint64_t count)
1681{
1682 acpigen_emit_byte(SHIFT_LEFT_OP);
1683 acpigen_emit_byte(src_result);
1684 acpigen_write_integer(count);
1685 acpigen_emit_byte(ZERO_OP);
1686}
1687
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001688void acpigen_write_to_buffer(uint8_t src, uint8_t dst)
1689{
1690 acpigen_emit_byte(TO_BUFFER_OP);
1691 acpigen_emit_byte(src);
1692 acpigen_emit_byte(dst);
1693}
1694
1695void acpigen_write_to_integer(uint8_t src, uint8_t dst)
1696{
1697 acpigen_emit_byte(TO_INTEGER_OP);
1698 acpigen_emit_byte(src);
1699 acpigen_emit_byte(dst);
1700}
1701
Aaron Durbin80bc0912020-08-19 23:17:42 -06001702void acpigen_write_to_integer_from_namestring(const char *source, uint8_t dst_op)
1703{
1704 acpigen_emit_byte(TO_INTEGER_OP);
1705 acpigen_emit_namestring(source);
1706 acpigen_emit_byte(dst_op);
1707}
1708
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301709void acpigen_write_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001710{
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301711 size_t i;
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001712
1713 acpigen_emit_byte(BUFFER_OP);
1714 acpigen_write_len_f();
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301715 acpigen_write_integer(size);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001716
1717 for (i = 0; i < size; i++)
1718 acpigen_emit_byte(arr[i]);
1719
1720 acpigen_pop_len();
1721}
1722
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301723void acpigen_write_return_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001724{
1725 acpigen_emit_byte(RETURN_OP);
1726 acpigen_write_byte_buffer(arr, size);
1727}
1728
1729void acpigen_write_return_singleton_buffer(uint8_t arg)
1730{
1731 acpigen_write_return_byte_buffer(&arg, 1);
1732}
1733
Duncan Laurie2fe74712020-06-01 17:36:56 -07001734void acpigen_write_return_op(uint8_t arg)
1735{
1736 acpigen_emit_byte(RETURN_OP);
1737 acpigen_emit_byte(arg);
1738}
1739
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001740void acpigen_write_return_byte(uint8_t arg)
1741{
1742 acpigen_emit_byte(RETURN_OP);
1743 acpigen_write_byte(arg);
1744}
1745
Naresh G Solanki05abe432016-11-17 00:16:29 +05301746void acpigen_write_return_integer(uint64_t arg)
1747{
1748 acpigen_emit_byte(RETURN_OP);
1749 acpigen_write_integer(arg);
1750}
1751
Duncan Laurieec2e3e42020-11-03 15:19:08 -08001752void acpigen_write_return_namestr(const char *arg)
1753{
1754 acpigen_emit_byte(RETURN_OP);
1755 acpigen_emit_namestring(arg);
1756}
1757
Naresh G Solanki05abe432016-11-17 00:16:29 +05301758void acpigen_write_return_string(const char *arg)
1759{
1760 acpigen_emit_byte(RETURN_OP);
1761 acpigen_write_string(arg);
1762}
1763
Duncan Lauriebeb2af42018-05-07 14:26:59 -07001764void acpigen_write_upc(enum acpi_upc_type type)
1765{
1766 acpigen_write_name("_UPC");
1767 acpigen_write_package(4);
1768 /* Connectable */
1769 acpigen_write_byte(type == UPC_TYPE_UNUSED ? 0 : 0xff);
1770 /* Type */
1771 acpigen_write_byte(type);
1772 /* Reserved0 */
1773 acpigen_write_zero();
1774 /* Reserved1 */
1775 acpigen_write_zero();
1776 acpigen_pop_len();
1777}
1778
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001779void acpigen_write_pld(const struct acpi_pld *pld)
1780{
1781 uint8_t buf[20];
1782
1783 if (acpi_pld_to_buffer(pld, buf, ARRAY_SIZE(buf)) < 0)
1784 return;
1785
1786 acpigen_write_name("_PLD");
Matt Delco4929f432019-01-30 11:40:44 -08001787 acpigen_write_package(1);
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001788 acpigen_write_byte_buffer(buf, ARRAY_SIZE(buf));
Matt Delco4929f432019-01-30 11:40:44 -08001789 acpigen_pop_len();
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001790}
1791
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001792void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *), size_t count, void *arg)
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301793{
1794 struct dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg);
1795 acpigen_write_dsm_uuid_arr(&id, 1);
1796}
1797
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001798/*
1799 * Create a supported functions bitmask
1800 * bit 0: other functions than 0 are supported
1801 * bits 1-x: function x supported
1802 */
Arthur Heymans9c1f78d2023-06-22 21:04:06 +02001803/* On GCC aarch64 the compiler is worried about alloca() having unbounded stack usage. */
1804#if defined(__GNUC__) && !defined(__clang__)
1805#pragma GCC diagnostic ignored "-Wstack-usage="
1806#endif
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001807static void acpigen_dsm_uuid_enum_functions(const struct dsm_uuid *id)
1808{
1809 const size_t bytes = DIV_ROUND_UP(id->count, BITS_PER_BYTE);
1810 uint8_t *buffer = alloca(bytes);
1811 bool set = false;
1812 size_t cb_idx = 0;
1813
1814 memset(buffer, 0, bytes);
1815
1816 for (size_t i = 0; i < bytes; i++) {
1817 for (size_t j = 0; j < BITS_PER_BYTE; j++) {
1818 if (cb_idx >= id->count)
1819 break;
1820
1821 if (id->callbacks[cb_idx++]) {
1822 set = true;
1823 buffer[i] |= BIT(j);
1824 }
1825 }
1826 }
1827
1828 if (set)
1829 buffer[0] |= BIT(0);
1830
1831 acpigen_write_return_byte_buffer(buffer, bytes);
1832}
1833
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301834static void acpigen_write_dsm_uuid(struct dsm_uuid *id)
1835{
1836 size_t i;
1837
1838 /* If (LEqual (Local0, ToUUID(uuid))) */
1839 acpigen_write_if();
1840 acpigen_emit_byte(LEQUAL_OP);
1841 acpigen_emit_byte(LOCAL0_OP);
1842 acpigen_write_uuid(id->uuid);
1843
1844 /* ToInteger (Arg2, Local1) */
1845 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
1846
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001847 /* If (LEqual(Local1, 0)) */
1848 {
1849 acpigen_write_if_lequal_op_int(LOCAL1_OP, 0);
1850 if (id->callbacks[0])
1851 id->callbacks[0](id->arg);
1852 else if (id->count)
1853 acpigen_dsm_uuid_enum_functions(id);
1854 acpigen_write_if_end();
1855 }
1856
1857 for (i = 1; i < id->count; i++) {
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301858 /* If (LEqual (Local1, i)) */
1859 acpigen_write_if_lequal_op_int(LOCAL1_OP, i);
1860
1861 /* Callback to write if handler. */
1862 if (id->callbacks[i])
1863 id->callbacks[i](id->arg);
1864
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001865 acpigen_write_if_end(); /* If */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301866 }
1867
1868 /* Default case: Return (Buffer (One) { 0x0 }) */
1869 acpigen_write_return_singleton_buffer(0x0);
1870
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001871 acpigen_write_if_end(); /* If (LEqual (Local0, ToUUID(uuid))) */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301872
1873}
1874
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001875/*
1876 * Generate ACPI AML code for _DSM method.
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301877 * This function takes as input array of uuid for the device, set of callbacks
1878 * and argument to pass into the callbacks. Callbacks should ensure that Local0
1879 * and Local1 are left untouched. Use of Local2-Local7 is permitted in
1880 * callbacks.
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001881 *
1882 * Arguments passed into _DSM method:
1883 * Arg0 = UUID
1884 * Arg1 = Revision
1885 * Arg2 = Function index
1886 * Arg3 = Function specific arguments
1887 *
1888 * AML code generated would look like:
1889 * Method (_DSM, 4, Serialized) {
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301890 * ToBuffer (Arg0, Local0)
1891 * If (LEqual (Local0, ToUUID(uuid))) {
1892 * ToInteger (Arg2, Local1)
1893 * If (LEqual (Local1, 0)) {
1894 * <acpigen by callback[0]>
1895 * }
1896 * ...
1897 * If (LEqual (Local1, n)) {
1898 * <acpigen by callback[n]>
1899 * }
1900 * Return (Buffer (One) { 0x0 })
1901 * }
1902 * ...
1903 * If (LEqual (Local0, ToUUID(uuidn))) {
1904 * ...
1905 * }
1906 * Return (Buffer (One) { 0x0 })
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001907 * }
1908 */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301909void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count)
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001910{
1911 size_t i;
1912
1913 /* Method (_DSM, 4, Serialized) */
1914 acpigen_write_method_serialized("_DSM", 0x4);
1915
1916 /* ToBuffer (Arg0, Local0) */
1917 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
1918
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001919 for (i = 0; i < count; i++)
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301920 acpigen_write_dsm_uuid(&ids[i]);
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001921
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301922 /* Return (Buffer (One) { 0x0 }) */
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001923 acpigen_write_return_singleton_buffer(0x0);
1924
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001925 acpigen_pop_len(); /* Method _DSM */
1926}
1927
Matt Delcob425bc82018-08-13 13:36:27 -07001928void acpigen_write_CPPC_package(const struct cppc_config *config)
1929{
1930 u32 i;
1931 u32 max;
1932 switch (config->version) {
1933 case 1:
1934 max = CPPC_MAX_FIELDS_VER_1;
1935 break;
1936 case 2:
1937 max = CPPC_MAX_FIELDS_VER_2;
1938 break;
1939 case 3:
1940 max = CPPC_MAX_FIELDS_VER_3;
1941 break;
1942 default:
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001943 printk(BIOS_ERR, "CPPC version %u is not implemented\n", config->version);
Matt Delcob425bc82018-08-13 13:36:27 -07001944 return;
1945 }
1946 acpigen_write_name(CPPC_PACKAGE_NAME);
1947
1948 /* Adding 2 to account for length and version fields */
1949 acpigen_write_package(max + 2);
1950 acpigen_write_dword(max + 2);
1951
1952 acpigen_write_byte(config->version);
1953
1954 for (i = 0; i < max; ++i) {
Michael Niewöhner38107fa2021-10-05 22:22:21 +02001955 const cppc_entry_t *entry = &config->entries[i];
1956 if (entry->type == CPPC_TYPE_DWORD)
1957 acpigen_write_dword(entry->dword);
1958 else
1959 acpigen_write_register_resource(&entry->reg);
Matt Delcob425bc82018-08-13 13:36:27 -07001960 }
1961 acpigen_pop_len();
1962}
1963
1964void acpigen_write_CPPC_method(void)
1965{
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001966 char pscope[16];
Felix Heldf0a8b042023-05-12 15:55:06 +02001967 snprintf(pscope, sizeof(pscope),
1968 "\\_SB." CONFIG_ACPI_CPU_STRING "." CPPC_PACKAGE_NAME, 0);
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001969
Matt Delcob425bc82018-08-13 13:36:27 -07001970 acpigen_write_method("_CPC", 0);
1971 acpigen_emit_byte(RETURN_OP);
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001972 acpigen_emit_namestring(pscope);
Matt Delcob425bc82018-08-13 13:36:27 -07001973 acpigen_pop_len();
1974}
1975
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001976/*
1977 * Generate ACPI AML code for _ROM method.
1978 * This function takes as input ROM data and ROM length.
1979 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001980 * The ACPI spec isn't clear about what should happen at the end of the
1981 * ROM. Tests showed that it shouldn't truncate, but fill the remaining
1982 * bytes in the returned buffer with zeros.
1983 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001984 * Arguments passed into _DSM method:
1985 * Arg0 = Offset in Bytes
1986 * Arg1 = Bytes to return
1987 *
1988 * Example:
1989 * acpigen_write_rom(0xdeadbeef, 0x10000)
1990 *
1991 * AML code generated would look like:
1992 * Method (_ROM, 2, NotSerialized) {
1993 *
1994 * OperationRegion("ROMS", SYSTEMMEMORY, 0xdeadbeef, 0x10000)
1995 * Field (ROMS, AnyAcc, NoLock, Preserve)
1996 * {
1997 * Offset (0),
1998 * RBF0, 0x80000
1999 * }
2000 *
2001 * Store (Arg0, Local0)
2002 * Store (Arg1, Local1)
2003 *
2004 * If (LGreater (Local1, 0x1000))
2005 * {
2006 * Store (0x1000, Local1)
2007 * }
2008 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002009 * Store (Local1, Local3)
2010 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002011 * If (LGreater (Local0, 0x10000))
2012 * {
2013 * Return(Buffer(Local1){0})
2014 * }
2015 *
2016 * If (LGreater (Local0, 0x0f000))
2017 * {
2018 * Subtract (0x10000, Local0, Local2)
2019 * If (LGreater (Local1, Local2))
2020 * {
2021 * Store (Local2, Local1)
2022 * }
2023 * }
2024 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002025 * Name (ROM1, Buffer (Local3) {0})
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002026 *
2027 * Multiply (Local0, 0x08, Local0)
2028 * Multiply (Local1, 0x08, Local1)
2029 *
2030 * CreateField (RBF0, Local0, Local1, TMPB)
2031 * Store (TMPB, ROM1)
2032 * Return (ROM1)
2033 * }
2034 */
2035
2036void acpigen_write_rom(void *bios, const size_t length)
2037{
2038 ASSERT(bios)
2039 ASSERT(length)
2040
Jonathan Neuschäfer6b0102d2018-09-12 12:26:45 +02002041 /* Method (_ROM, 2, Serialized) */
Marc Jones24462e62018-08-15 23:57:28 -06002042 acpigen_write_method_serialized("_ROM", 2);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002043
2044 /* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002045 struct opregion opreg = OPREGION("ROMS", SYSTEMMEMORY, (uintptr_t)bios, length);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002046 acpigen_write_opregion(&opreg);
2047
2048 struct fieldlist l[] = {
2049 FIELDLIST_OFFSET(0),
2050 FIELDLIST_NAMESTR("RBF0", 8 * length),
2051 };
2052
2053 /* Field (ROMS, AnyAcc, NoLock, Preserve)
2054 * {
2055 * Offset (0),
2056 * RBF0, 0x80000
2057 * } */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002058 acpigen_write_field(opreg.name, l, 2, FIELD_ANYACC | FIELD_NOLOCK | FIELD_PRESERVE);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002059
2060 /* Store (Arg0, Local0) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002061 acpigen_write_store_ops(ARG0_OP, LOCAL0_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002062
2063 /* Store (Arg1, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002064 acpigen_write_store_ops(ARG1_OP, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002065
2066 /* ACPI SPEC requires to return at maximum 4KiB */
2067 /* If (LGreater (Local1, 0x1000)) */
Felix Held383a06e2023-02-09 16:25:38 +01002068 acpigen_write_if_lgreater_op_int(LOCAL1_OP, 0x1000);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002069
2070 /* Store (0x1000, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002071 acpigen_write_store_int_to_op(0x1000, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002072
2073 /* Pop if */
2074 acpigen_pop_len();
2075
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002076 /* Store (Local1, Local3) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002077 acpigen_write_store_ops(LOCAL1_OP, LOCAL3_OP);
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002078
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002079 /* If (LGreater (Local0, length)) */
Felix Held383a06e2023-02-09 16:25:38 +01002080 acpigen_write_if_lgreater_op_int(LOCAL0_OP, length);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002081
2082 /* Return(Buffer(Local1){0}) */
2083 acpigen_emit_byte(RETURN_OP);
2084 acpigen_emit_byte(BUFFER_OP);
2085 acpigen_write_len_f();
2086 acpigen_emit_byte(LOCAL1_OP);
2087 acpigen_emit_byte(0);
2088 acpigen_pop_len();
2089
2090 /* Pop if */
2091 acpigen_pop_len();
2092
2093 /* If (LGreater (Local0, length - 4096)) */
Felix Held383a06e2023-02-09 16:25:38 +01002094 acpigen_write_if_lgreater_op_int(LOCAL0_OP, length - 4096);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002095
2096 /* Subtract (length, Local0, Local2) */
2097 acpigen_emit_byte(SUBTRACT_OP);
2098 acpigen_write_integer(length);
2099 acpigen_emit_byte(LOCAL0_OP);
2100 acpigen_emit_byte(LOCAL2_OP);
2101
2102 /* If (LGreater (Local1, Local2)) */
Felix Held383a06e2023-02-09 16:25:38 +01002103 acpigen_write_if_lgreater_op_op(LOCAL1_OP, LOCAL2_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002104
2105 /* Store (Local2, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002106 acpigen_write_store_ops(LOCAL2_OP, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002107
2108 /* Pop if */
2109 acpigen_pop_len();
2110
2111 /* Pop if */
2112 acpigen_pop_len();
2113
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002114 /* Name (ROM1, Buffer (Local3) {0}) */
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002115 acpigen_write_name("ROM1");
2116 acpigen_emit_byte(BUFFER_OP);
2117 acpigen_write_len_f();
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002118 acpigen_emit_byte(LOCAL3_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002119 acpigen_emit_byte(0);
2120 acpigen_pop_len();
2121
2122 /* Multiply (Local1, 0x08, Local1) */
2123 acpigen_emit_byte(MULTIPLY_OP);
2124 acpigen_emit_byte(LOCAL1_OP);
2125 acpigen_write_integer(0x08);
2126 acpigen_emit_byte(LOCAL1_OP);
2127
2128 /* Multiply (Local0, 0x08, Local0) */
2129 acpigen_emit_byte(MULTIPLY_OP);
2130 acpigen_emit_byte(LOCAL0_OP);
2131 acpigen_write_integer(0x08);
2132 acpigen_emit_byte(LOCAL0_OP);
2133
2134 /* CreateField (RBF0, Local0, Local1, TMPB) */
2135 acpigen_emit_ext_op(CREATEFIELD_OP);
2136 acpigen_emit_namestring("RBF0");
2137 acpigen_emit_byte(LOCAL0_OP);
2138 acpigen_emit_byte(LOCAL1_OP);
2139 acpigen_emit_namestring("TMPB");
2140
2141 /* Store (TMPB, ROM1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002142 acpigen_write_store_namestr_to_namestr("TMPB", "ROM1");
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002143
2144 /* Return (ROM1) */
2145 acpigen_emit_byte(RETURN_OP);
2146 acpigen_emit_namestring("ROM1");
2147
2148 /* Pop method */
2149 acpigen_pop_len();
2150}
2151
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002152/*
2153 * Helper functions for enabling/disabling Tx GPIOs based on the GPIO
2154 * polarity. These functions end up calling acpigen_soc_{set,clear}_tx_gpio to
2155 * make callbacks into SoC acpigen code.
2156 *
2157 * Returns 0 on success and -1 on error.
2158 */
Duncan Laurie30c3f912020-10-09 04:48:53 +00002159int acpigen_enable_tx_gpio(const struct acpi_gpio *gpio)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002160{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002161 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002162 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002163 else
2164 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002165}
2166
Duncan Laurie30c3f912020-10-09 04:48:53 +00002167int acpigen_disable_tx_gpio(const struct acpi_gpio *gpio)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002168{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002169 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002170 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
2171 else
2172 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
2173}
Jonathan Zhang71299c22020-01-27 11:38:57 -08002174
Duncan Laurie30c3f912020-10-09 04:48:53 +00002175void acpigen_get_rx_gpio(const struct acpi_gpio *gpio)
Rajat Jain310623b2020-02-26 11:02:53 -08002176{
2177 acpigen_soc_read_rx_gpio(gpio->pins[0]);
2178
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002179 if (gpio->active_low)
Rajat Jain310623b2020-02-26 11:02:53 -08002180 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
2181}
2182
Duncan Laurie30c3f912020-10-09 04:48:53 +00002183void acpigen_get_tx_gpio(const struct acpi_gpio *gpio)
Duncan Laurie2fe74712020-06-01 17:36:56 -07002184{
2185 acpigen_soc_get_tx_gpio(gpio->pins[0]);
2186
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002187 if (gpio->active_low)
Duncan Laurie2fe74712020-06-01 17:36:56 -07002188 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
2189}
2190
Jonathan Zhang71299c22020-01-27 11:38:57 -08002191/* refer to ACPI 6.4.3.5.3 Word Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002192void acpigen_resource_word(u16 res_type, u16 gen_flags, u16 type_flags, u16 gran, u16 range_min,
2193 u16 range_max, u16 translation, u16 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002194{
Felix Heldb2f2b532023-05-11 22:22:06 +02002195 /* Byte 0: Type 1, Large Item Value 0x8: Word Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002196 acpigen_emit_byte(0x88);
2197 /* Byte 1+2: length (0x000d) */
2198 acpigen_emit_byte(0x0d);
2199 acpigen_emit_byte(0x00);
2200 /* resource type */
2201 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2202 /* general flags */
2203 acpigen_emit_byte(gen_flags);
2204 /* type flags */
2205 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2206 acpigen_emit_byte(type_flags);
2207 /* granularity, min, max, translation, length */
2208 acpigen_emit_word(gran);
2209 acpigen_emit_word(range_min);
2210 acpigen_emit_word(range_max);
2211 acpigen_emit_word(translation);
2212 acpigen_emit_word(length);
2213}
2214
2215/* refer to ACPI 6.4.3.5.2 DWord Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002216void acpigen_resource_dword(u16 res_type, u16 gen_flags, u16 type_flags, u32 gran,
2217 u32 range_min, u32 range_max, u32 translation, u32 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002218{
Felix Heldb2f2b532023-05-11 22:22:06 +02002219 /* Byte 0: Type 1, Large Item Value 0x7: DWord Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002220 acpigen_emit_byte(0x87);
2221 /* Byte 1+2: length (0023) */
2222 acpigen_emit_byte(23);
2223 acpigen_emit_byte(0x00);
2224 /* resource type */
2225 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2226 /* general flags */
2227 acpigen_emit_byte(gen_flags);
2228 /* type flags */
2229 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2230 acpigen_emit_byte(type_flags);
2231 /* granularity, min, max, translation, length */
2232 acpigen_emit_dword(gran);
2233 acpigen_emit_dword(range_min);
2234 acpigen_emit_dword(range_max);
2235 acpigen_emit_dword(translation);
2236 acpigen_emit_dword(length);
2237}
2238
2239static void acpigen_emit_qword(u64 data)
2240{
2241 acpigen_emit_dword(data & 0xffffffff);
2242 acpigen_emit_dword((data >> 32) & 0xffffffff);
2243}
2244
2245/* refer to ACPI 6.4.3.5.1 QWord Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002246void acpigen_resource_qword(u16 res_type, u16 gen_flags, u16 type_flags, u64 gran,
2247 u64 range_min, u64 range_max, u64 translation, u64 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002248{
Felix Heldb2f2b532023-05-11 22:22:06 +02002249 /* Byte 0: Type 1, Large Item Value 0xa: QWord Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002250 acpigen_emit_byte(0x8a);
2251 /* Byte 1+2: length (0x002b) */
2252 acpigen_emit_byte(0x2b);
2253 acpigen_emit_byte(0x00);
2254 /* resource type */
2255 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2256 /* general flags */
2257 acpigen_emit_byte(gen_flags);
2258 /* type flags */
2259 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2260 acpigen_emit_byte(type_flags);
2261 /* granularity, min, max, translation, length */
2262 acpigen_emit_qword(gran);
2263 acpigen_emit_qword(range_min);
2264 acpigen_emit_qword(range_max);
2265 acpigen_emit_qword(translation);
2266 acpigen_emit_qword(length);
2267}
Furquan Shaikh1a829232020-04-23 11:11:05 -07002268
Felix Held0fdede02023-05-27 01:02:37 +02002269void acpigen_resource_producer_bus_number(u16 bus_base, u16 bus_limit)
Felix Held5a82f0d2023-05-09 16:10:35 +02002270{
2271 acpigen_resource_word(RSRC_TYPE_BUS, /* res_type */
2272 ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2273 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
Felix Held0fdede02023-05-27 01:02:37 +02002274 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2275 | ADDR_SPACE_GENERAL_FLAG_PRODUCER, /* gen_flags */
Felix Held5a82f0d2023-05-09 16:10:35 +02002276 BUS_NUM_RANGE_RESOURCE_FLAG, /* type_flags */
2277 0, /* gran */
2278 bus_base, /* range_min */
2279 bus_limit, /* range_max */
2280 0x0, /* translation */
2281 bus_limit - bus_base + 1); /* length */
2282}
2283
Felix Held0fdede02023-05-27 01:02:37 +02002284void acpigen_resource_producer_io(u16 io_base, u16 io_limit)
Felix Held6695be62023-05-09 16:18:51 +02002285{
Felix Helde3c9a042023-06-05 19:59:25 +02002286 acpigen_resource_dword(RSRC_TYPE_IO, /* res_type */
Felix Held6695be62023-05-09 16:18:51 +02002287 ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2288 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
Felix Held0fdede02023-05-27 01:02:37 +02002289 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2290 | ADDR_SPACE_GENERAL_FLAG_PRODUCER, /* gen_flags */
Felix Held6695be62023-05-09 16:18:51 +02002291 IO_RSRC_FLAG_ENTIRE_RANGE, /* type_flags */
2292 0, /* gran */
2293 io_base, /* range_min */
2294 io_limit, /* range_max */
2295 0x0, /* translation */
2296 io_limit - io_base + 1); /* length */
2297}
2298
Arthur Heymans62f788e2023-11-21 18:49:33 +01002299static void acpigen_resource_mmio32(u32 mmio_base, u32 mmio_limit, u16 gen_flags,
2300 u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002301{
2302 acpigen_resource_dword(RSRC_TYPE_MEM, /* res_type */
Arthur Heymans62f788e2023-11-21 18:49:33 +01002303 gen_flags, /* gen_flags */
2304 type_flags, /* type_flags */
2305 0, /* gran */
2306 mmio_base, /* range_min */
2307 mmio_limit, /* range_max */
2308 0x0, /* translation */
2309 mmio_limit - mmio_base + 1); /* length */
Felix Held21594fd12023-05-09 16:39:57 +02002310}
2311
Arthur Heymans62f788e2023-11-21 18:49:33 +01002312static void acpigen_resource_mmio64(u64 mmio_base, u64 mmio_limit, u16 gen_flags,
2313 u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002314{
2315 acpigen_resource_qword(RSRC_TYPE_MEM, /* res_type */
Arthur Heymans62f788e2023-11-21 18:49:33 +01002316 gen_flags, /* gen_flags */
2317 type_flags, /* type_flags */
2318 0, /* gran */
2319 mmio_base, /* range_min */
2320 mmio_limit, /* range_max */
2321 0x0, /* translation */
2322 mmio_limit - mmio_base + 1); /* length */
2323}
2324
2325static void acpigen_resource_mmio(u64 mmio_base, u64 mmio_limit, bool is_producer, u16 type_flags)
2326{
2327 const u16 gen_flags = ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2328 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
2329 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2330 | (is_producer ? ADDR_SPACE_GENERAL_FLAG_PRODUCER
2331 : ADDR_SPACE_GENERAL_FLAG_CONSUMER);
2332
2333 if (mmio_base < 4ULL * GiB && mmio_limit < 4ULL * GiB)
2334 acpigen_resource_mmio32(mmio_base, mmio_limit, gen_flags, type_flags);
2335 else
2336 acpigen_resource_mmio64(mmio_base, mmio_limit, gen_flags, type_flags);
Felix Held21594fd12023-05-09 16:39:57 +02002337}
2338
Felix Held0fdede02023-05-27 01:02:37 +02002339void acpigen_resource_producer_mmio(u64 mmio_base, u64 mmio_limit, u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002340{
Arthur Heymans62f788e2023-11-21 18:49:33 +01002341 acpigen_resource_mmio(mmio_base, mmio_limit, true, type_flags);
2342}
2343
2344void acpigen_resource_consumer_mmio(u64 mmio_base, u64 mmio_limit, u16 type_flags)
2345{
2346 acpigen_resource_mmio(mmio_base, mmio_limit, false, type_flags);
Felix Held21594fd12023-05-09 16:39:57 +02002347}
2348
Furquan Shaikh1a829232020-04-23 11:11:05 -07002349void acpigen_write_ADR(uint64_t adr)
2350{
2351 acpigen_write_name_qword("_ADR", adr);
2352}
2353
Duncan Laurie08a942f2020-04-29 12:13:14 -07002354/**
2355 * acpigen_write_ADR_soundwire_device() - SoundWire ACPI Device Address Encoding.
2356 * @address: SoundWire device address properties.
2357 *
2358 * From SoundWire Discovery and Configuration Specification Version 1.0 Table 3.
2359 *
2360 * 63..52 - Reserved (0)
2361 * 51..48 - Zero-based SoundWire Link ID, relative to the immediate parent.
2362 * Used when a Controller has multiple master devices, each producing a
2363 * separate SoundWire Link. Set to 0 for single-link controllers.
2364 * 47..0 - SoundWire Device ID Encoding from specification version 1.2 table 88
2365 * 47..44 - SoundWire specification version that this device supports
2366 * 43..40 - Unique ID for multiple devices
2367 * 39..24 - MIPI standard manufacturer code
2368 * 23..08 - Vendor defined part ID
2369 * 07..00 - MIPI class encoding
2370 */
2371void acpigen_write_ADR_soundwire_device(const struct soundwire_address *address)
2372{
2373 acpigen_write_ADR((((uint64_t)address->link_id & 0xf) << 48) |
2374 (((uint64_t)address->version & 0xf) << 44) |
2375 (((uint64_t)address->unique_id & 0xf) << 40) |
2376 (((uint64_t)address->manufacturer_id & 0xffff) << 24) |
2377 (((uint64_t)address->part_id & 0xffff) << 8) |
2378 (((uint64_t)address->class & 0xff)));
2379}
Tim Wawrzynczakf6945022020-06-04 15:18:47 -06002380
2381void acpigen_notify(const char *namestr, int value)
2382{
2383 acpigen_emit_byte(NOTIFY_OP);
2384 acpigen_emit_namestring(namestr);
2385 acpigen_write_integer(value);
2386}
Aaron Durbin80bc0912020-08-19 23:17:42 -06002387
2388static void _create_field(uint8_t aml_op, uint8_t srcop, size_t byte_offset, const char *name)
2389{
2390 acpigen_emit_byte(aml_op);
2391 acpigen_emit_byte(srcop);
2392 acpigen_write_integer(byte_offset);
2393 acpigen_emit_namestring(name);
2394}
2395
2396void acpigen_write_create_byte_field(uint8_t op, size_t byte_offset, const char *name)
2397{
2398 _create_field(CREATE_BYTE_OP, op, byte_offset, name);
2399}
2400
2401void acpigen_write_create_word_field(uint8_t op, size_t byte_offset, const char *name)
2402{
2403 _create_field(CREATE_WORD_OP, op, byte_offset, name);
2404}
2405
2406void acpigen_write_create_dword_field(uint8_t op, size_t byte_offset, const char *name)
2407{
2408 _create_field(CREATE_DWORD_OP, op, byte_offset, name);
2409}
2410
2411void acpigen_write_create_qword_field(uint8_t op, size_t byte_offset, const char *name)
2412{
2413 _create_field(CREATE_QWORD_OP, op, byte_offset, name);
2414}
Jason Gleneskca36aed2020-09-15 21:01:57 -07002415
2416void acpigen_write_pct_package(const acpi_addr_t *perf_ctrl, const acpi_addr_t *perf_sts)
2417{
2418 acpigen_write_name("_PCT");
2419 acpigen_write_package(0x02);
2420 acpigen_write_register_resource(perf_ctrl);
2421 acpigen_write_register_resource(perf_sts);
2422
2423 acpigen_pop_len();
2424}
2425
2426void acpigen_write_xpss_package(const struct acpi_xpss_sw_pstate *pstate_value)
2427{
2428 acpigen_write_package(0x08);
2429 acpigen_write_dword(pstate_value->core_freq);
2430 acpigen_write_dword(pstate_value->power);
2431 acpigen_write_dword(pstate_value->transition_latency);
2432 acpigen_write_dword(pstate_value->bus_master_latency);
2433
2434 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_value, sizeof(uint64_t));
2435 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_value, sizeof(uint64_t));
2436 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_mask, sizeof(uint64_t));
2437 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_mask, sizeof(uint64_t));
2438
2439 acpigen_pop_len();
2440}
2441
2442void acpigen_write_xpss_object(const struct acpi_xpss_sw_pstate *pstate_values, size_t nentries)
2443{
2444 size_t pstate;
2445
2446 acpigen_write_name("XPSS");
2447 acpigen_write_package(nentries);
2448 for (pstate = 0; pstate < nentries; pstate++) {
2449 acpigen_write_xpss_package(pstate_values);
2450 pstate_values++;
2451 }
2452
2453 acpigen_pop_len();
2454}
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002455
2456/* Delay up to wait_ms until provided namestr matches expected value. */
2457void acpigen_write_delay_until_namestr_int(uint32_t wait_ms, const char *name, uint64_t value)
2458{
2459 uint32_t wait_ms_segment = 1;
2460 uint32_t segments = wait_ms;
2461
Sukumar Ghorai9b3c5af2023-12-07 18:33:43 -08002462 /* Sleep in 2ms segments if delay is more than 2ms. */
2463 if (wait_ms > 2) {
2464 wait_ms_segment = 2;
2465 segments = wait_ms / wait_ms_segment;
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002466 }
2467
2468 acpigen_write_store_int_to_op(segments, LOCAL7_OP);
2469 acpigen_emit_byte(WHILE_OP);
2470 acpigen_write_len_f();
2471 acpigen_emit_byte(LGREATER_OP);
2472 acpigen_emit_byte(LOCAL7_OP);
2473 acpigen_emit_byte(ZERO_OP);
2474
2475 /* If name is not provided then just delay in a loop. */
2476 if (name) {
2477 acpigen_write_if_lequal_namestr_int(name, value);
2478 acpigen_emit_byte(BREAK_OP);
2479 acpigen_pop_len(); /* If */
2480 }
2481
2482 acpigen_write_sleep(wait_ms_segment);
2483 acpigen_emit_byte(DECREMENT_OP);
2484 acpigen_emit_byte(LOCAL7_OP);
2485 acpigen_pop_len(); /* While */
Cliff Huangf97598f2023-03-01 14:30:41 -08002486
2487 if (name) {
2488 acpigen_write_if_lequal_op_op(LOCAL7_OP, ZERO_OP);
2489 acpigen_write_debug_sprintf("WARN: Wait loop timeout for variable %s",
2490 name);
2491 acpigen_pop_len(); /* If */
2492 }
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002493}
Arthur Heymans0eb59742023-04-25 16:23:37 +02002494
2495void acpigen_ssdt_override_sleep_states(bool enable_s1, bool enable_s2, bool enable_s3,
2496 bool enable_s4)
2497{
2498 assert(!(enable_s1 && CONFIG(ACPI_S1_NOT_SUPPORTED)));
2499 assert(!(enable_s3 && !CONFIG(HAVE_ACPI_RESUME)));
2500 assert(!(enable_s4 && CONFIG(DISABLE_ACPI_HIBERNATE)));
2501
2502 acpigen_write_scope("\\");
2503 uint32_t sleep_enable = (enable_s1 << 0) | (enable_s2 << 1)
2504 | (enable_s3 << 2) | (enable_s4 << 3);
2505 acpigen_write_name_dword("OSFG", sleep_enable);
2506 acpigen_pop_len();
2507}