blob: 9c04e84cd07b43666ccaee1c4e0380097db4c327 [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
Felix Held75c4d442024-01-11 23:57:38 +0100871void acpigen_write_SEG(uint8_t segment_group_number)
872{
873 /*
874 * Method (_SEG, 0, NotSerialized) { Return (status) }
875 */
876 acpigen_write_method("_SEG", 0);
877 acpigen_emit_byte(RETURN_OP);
878 acpigen_write_byte(segment_group_number);
879 acpigen_pop_len();
880}
881
Raul E Rangelc7048322021-04-19 15:58:25 -0600882void acpigen_write_LPI_package(u64 level, const struct acpi_lpi_state *states, u16 nentries)
883{
884 /*
885 * Name (_LPI, Package (0x06) // _LPI: Low Power Idle States
886 * {
887 * 0x0000,
888 * 0x0000000000000000,
889 * 0x0003,
890 * Package (0x0A)
891 * {
892 * 0x00000002,
893 * 0x00000001,
894 * 0x00000001,
895 * 0x00000000,
896 * 0x00000000,
897 * 0x00000000,
898 * ResourceTemplate ()
899 * {
900 * Register (FFixedHW,
901 * 0x02, // Bit Width
902 * 0x02, // Bit Offset
903 * 0x0000000000000000, // Address
904 * ,)
905 * },
906 *
907 * ResourceTemplate ()
908 * {
909 * Register (SystemMemory,
910 * 0x00, // Bit Width
911 * 0x00, // Bit Offset
912 * 0x0000000000000000, // Address
913 * ,)
914 * },
915 *
916 * ResourceTemplate ()
917 * {
918 * Register (SystemMemory,
919 * 0x00, // Bit Width
920 * 0x00, // Bit Offset
921 * 0x0000000000000000, // Address
922 * ,)
923 * },
924 *
925 * "C1"
926 * },
927 * ...
928 * }
929 */
930
931 acpigen_write_name("_LPI");
932 acpigen_write_package(3 + nentries);
933 acpigen_write_word(0); /* Revision */
934 acpigen_write_qword(level);
935 acpigen_write_word(nentries);
936
937 for (size_t i = 0; i < nentries; i++, states++) {
938 acpigen_write_package(0xA);
939 acpigen_write_dword(states->min_residency_us);
940 acpigen_write_dword(states->worst_case_wakeup_latency_us);
941 acpigen_write_dword(states->flags);
942 acpigen_write_dword(states->arch_context_lost_flags);
943 acpigen_write_dword(states->residency_counter_frequency_hz);
944 acpigen_write_dword(states->enabled_parent_state);
945 acpigen_write_register_resource(&states->entry_method);
946 acpigen_write_register_resource(&states->residency_counter_register);
947 acpigen_write_register_resource(&states->usage_counter_register);
948 acpigen_write_string(states->state_name);
949 acpigen_pop_len();
950 }
951 acpigen_pop_len();
952}
953
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100954/*
955 * Generates a func with max supported P-states.
956 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100957void acpigen_write_PPC(u8 nr)
Rudolf Marekf997b552009-02-14 15:40:23 +0000958{
959/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200960 Method (_PPC, 0, NotSerialized)
961 {
962 Return (nr)
963 }
Rudolf Marekf997b552009-02-14 15:40:23 +0000964*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100965 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700966 acpigen_emit_byte(RETURN_OP);
Rudolf Marekf997b552009-02-14 15:40:23 +0000967 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100968 acpigen_write_byte(nr);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100969 acpigen_pop_len();
Rudolf Marekf997b552009-02-14 15:40:23 +0000970}
971
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100972/*
973 * Generates a func with max supported P-states saved
974 * in the variable PPCM.
975 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100976void acpigen_write_PPC_NVS(void)
Duncan Laurie0eefa002012-07-16 12:11:53 -0700977{
978/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200979 Method (_PPC, 0, NotSerialized)
980 {
981 Return (PPCM)
982 }
Duncan Laurie0eefa002012-07-16 12:11:53 -0700983*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100984 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700985 acpigen_emit_byte(RETURN_OP);
Duncan Laurie0eefa002012-07-16 12:11:53 -0700986 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100987 acpigen_emit_namestring("PPCM");
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100988 acpigen_pop_len();
Duncan Laurie0eefa002012-07-16 12:11:53 -0700989}
990
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100991void acpigen_write_TPC(const char *gnvs_tpc_limit)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200992{
993/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200994 // Sample _TPC method
995 Method (_TPC, 0, NotSerialized)
996 {
997 Return (\TLVL)
998 }
999*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001000 acpigen_write_method("_TPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001001 acpigen_emit_byte(RETURN_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001002 acpigen_emit_namestring(gnvs_tpc_limit);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001003 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001004}
1005
Duncan Laurieabe2de82016-05-09 11:08:46 -07001006void acpigen_write_PRW(u32 wake, u32 level)
1007{
1008 /*
1009 * Name (_PRW, Package () { wake, level }
1010 */
1011 acpigen_write_name("_PRW");
1012 acpigen_write_package(2);
1013 acpigen_write_integer(wake);
1014 acpigen_write_integer(level);
1015 acpigen_pop_len();
1016}
1017
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001018void acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, u32 busmLat, u32 control,
1019 u32 status)
Rudolf Marekf997b552009-02-14 15:40:23 +00001020{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001021 acpigen_write_package(6);
1022 acpigen_write_dword(coreFreq);
1023 acpigen_write_dword(power);
1024 acpigen_write_dword(transLat);
1025 acpigen_write_dword(busmLat);
1026 acpigen_write_dword(control);
1027 acpigen_write_dword(status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001028 acpigen_pop_len();
Stefan Reinauerd4bacf92012-05-02 16:38:47 -07001029
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001030 printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n", coreFreq, power,
1031 control, status);
Rudolf Marekf997b552009-02-14 15:40:23 +00001032}
Patrick Georgidf444bf2009-04-21 20:34:36 +00001033
Jason Gleneskca36aed2020-09-15 21:01:57 -07001034void acpigen_write_pss_object(const struct acpi_sw_pstate *pstate_values, size_t nentries)
1035{
1036 size_t pstate;
1037
1038 acpigen_write_name("_PSS");
1039 acpigen_write_package(nentries);
1040 for (pstate = 0; pstate < nentries; pstate++) {
1041 acpigen_write_PSS_package(
1042 pstate_values->core_freq, pstate_values->power,
1043 pstate_values->transition_latency, pstate_values->bus_master_latency,
1044 pstate_values->control_value, pstate_values->status_value);
1045 pstate_values++;
1046 }
1047
1048 acpigen_pop_len();
1049}
1050
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001051void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Patrick Georgidf444bf2009-04-21 20:34:36 +00001052{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001053 acpigen_write_name("_PSD");
1054 acpigen_write_package(1);
1055 acpigen_write_package(5);
1056 acpigen_write_byte(5); // 5 values
1057 acpigen_write_byte(0); // revision 0
1058 acpigen_write_dword(domain);
1059 acpigen_write_dword(coordtype);
1060 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001061 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001062 acpigen_pop_len();
Patrick Georgidf444bf2009-04-21 20:34:36 +00001063}
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001064
Angel Ponsd2794ce2021-10-17 12:59:43 +02001065void acpigen_write_CST_package_entry(const acpi_cstate_t *cstate)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001066{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001067 acpigen_write_package(4);
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001068 acpigen_write_register_resource(&cstate->resource);
Jason Glenesk201acca2020-09-11 12:36:15 -07001069 acpigen_write_byte(cstate->ctype);
1070 acpigen_write_word(cstate->latency);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001071 acpigen_write_dword(cstate->power);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001072 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +02001073}
1074
Angel Ponsd2794ce2021-10-17 12:59:43 +02001075void acpigen_write_CST_package(const acpi_cstate_t *cstate, int nentries)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001076{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001077 int i;
1078 acpigen_write_name("_CST");
1079 acpigen_write_package(nentries+1);
Jason Glenesk201acca2020-09-11 12:36:15 -07001080 acpigen_write_integer(nentries);
Sven Schnelle0b86c762011-10-21 21:46:47 +02001081
1082 for (i = 0; i < nentries; i++)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001083 acpigen_write_CST_package_entry(cstate + i);
Sven Schnelle0b86c762011-10-21 21:46:47 +02001084
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001085 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +02001086}
1087
Lee Leahy6f80ccc2017-03-16 15:18:22 -07001088void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype,
1089 u32 index)
Timothy Pearson83abd812015-06-08 19:35:06 -05001090{
1091 acpigen_write_name("_CSD");
1092 acpigen_write_package(1);
1093 acpigen_write_package(6);
Jason Glenesk201acca2020-09-11 12:36:15 -07001094 acpigen_write_integer(6); // 6 values
Timothy Pearson83abd812015-06-08 19:35:06 -05001095 acpigen_write_byte(0); // revision 0
1096 acpigen_write_dword(domain);
1097 acpigen_write_dword(coordtype);
1098 acpigen_write_dword(numprocs);
1099 acpigen_write_dword(index);
1100 acpigen_pop_len();
1101 acpigen_pop_len();
1102}
1103
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001104void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
Stefan Reinauer39205c62012-04-27 21:49:28 +02001105{
1106/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +02001107 Sample _TSS package with 100% and 50% duty cycles
1108 Name (_TSS, Package (0x02)
1109 {
1110 Package(){100, 1000, 0, 0x00, 0)
1111 Package(){50, 520, 0, 0x18, 0)
1112 })
1113*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001114 int i;
Stefan Reinauer39205c62012-04-27 21:49:28 +02001115 acpi_tstate_t *tstate = tstate_list;
1116
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001117 acpigen_write_name("_TSS");
1118 acpigen_write_package(entries);
Stefan Reinauer39205c62012-04-27 21:49:28 +02001119
1120 for (i = 0; i < entries; i++) {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001121 acpigen_write_package(5);
1122 acpigen_write_dword(tstate->percent);
1123 acpigen_write_dword(tstate->power);
1124 acpigen_write_dword(tstate->latency);
1125 acpigen_write_dword(tstate->control);
1126 acpigen_write_dword(tstate->status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001127 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001128 tstate++;
Stefan Reinauer39205c62012-04-27 21:49:28 +02001129 }
1130
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001131 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001132}
1133
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001134void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Stefan Reinauer39205c62012-04-27 21:49:28 +02001135{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001136 acpigen_write_name("_TSD");
1137 acpigen_write_package(1);
1138 acpigen_write_package(5);
1139 acpigen_write_byte(5); // 5 values
1140 acpigen_write_byte(0); // revision 0
1141 acpigen_write_dword(domain);
1142 acpigen_write_dword(coordtype);
1143 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001144 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001145 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +02001146}
1147
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001148void acpigen_write_mem32fixed(int readwrite, u32 base, u32 size)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001149{
1150 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001151 * ACPI 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001152 * Byte 0:
1153 * Bit7 : 1 => big item
1154 * Bit6-0: 0000110 (0x6) => 32-bit fixed memory
1155 */
1156 acpigen_emit_byte(0x86);
1157 /* Byte 1+2: length (0x0009) */
1158 acpigen_emit_byte(0x09);
1159 acpigen_emit_byte(0x00);
1160 /* bit1-7 are ignored */
1161 acpigen_emit_byte(readwrite ? 0x01 : 0x00);
Duncan Laurie9ccae752016-05-09 07:43:19 -07001162 acpigen_emit_dword(base);
1163 acpigen_emit_dword(size);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001164}
1165
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001166static void acpigen_write_register(const acpi_addr_t *addr)
Sven Schnelle0b86c762011-10-21 21:46:47 +02001167{
Stefan Reinauer4cc8c702012-04-27 21:34:16 +02001168 acpigen_emit_byte(0x82); /* Register Descriptor */
1169 acpigen_emit_byte(0x0c); /* Register Length 7:0 */
1170 acpigen_emit_byte(0x00); /* Register Length 15:8 */
1171 acpigen_emit_byte(addr->space_id); /* Address Space ID */
1172 acpigen_emit_byte(addr->bit_width); /* Register Bit Width */
1173 acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +01001174 acpigen_emit_byte(addr->access_size); /* Register Access Size */
Duncan Laurie9ccae752016-05-09 07:43:19 -07001175 acpigen_emit_dword(addr->addrl); /* Register Address Low */
1176 acpigen_emit_dword(addr->addrh); /* Register Address High */
Sven Schnelle0b86c762011-10-21 21:46:47 +02001177}
1178
Matt Delcoc3f9d7a2018-07-27 14:01:05 -07001179void acpigen_write_register_resource(const acpi_addr_t *addr)
1180{
1181 acpigen_write_resourcetemplate_header();
1182 acpigen_write_register(addr);
1183 acpigen_write_resourcetemplate_footer();
1184}
1185
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001186void acpigen_write_irq(u16 mask)
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001187{
1188 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001189 * ACPI 3.0b section 6.4.2.1: IRQ Descriptor
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001190 * Byte 0:
1191 * Bit7 : 0 => small item
1192 * Bit6-3: 0100 (0x4) => IRQ port descriptor
1193 * Bit2-0: 010 (0x2) => 2 Bytes long
1194 */
1195 acpigen_emit_byte(0x22);
1196 acpigen_emit_byte(mask & 0xff);
1197 acpigen_emit_byte((mask >> 8) & 0xff);
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001198}
1199
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001200void acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001201{
1202 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001203 * ACPI 4.0 section 6.4.2.6: I/O Port Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001204 * Byte 0:
1205 * Bit7 : 0 => small item
1206 * Bit6-3: 1000 (0x8) => I/O port descriptor
1207 * Bit2-0: 111 (0x7) => 7 Bytes long
1208 */
1209 acpigen_emit_byte(0x47);
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001210 /* Does the device decode all 16 or just 10 bits? */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001211 /* bit1-7 are ignored */
1212 acpigen_emit_byte(decode16 ? 0x01 : 0x00);
1213 /* minimum base address the device may be configured for */
1214 acpigen_emit_byte(min & 0xff);
1215 acpigen_emit_byte((min >> 8) & 0xff);
1216 /* maximum base address the device may be configured for */
1217 acpigen_emit_byte(max & 0xff);
1218 acpigen_emit_byte((max >> 8) & 0xff);
1219 /* alignment for min base */
1220 acpigen_emit_byte(align & 0xff);
1221 acpigen_emit_byte(len & 0xff);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001222}
1223
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001224void acpigen_write_resourcetemplate_header(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001225{
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001226 /*
1227 * A ResourceTemplate() is a Buffer() with a
1228 * (Byte|Word|DWord) containing the length, followed by one or more
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001229 * resource items, terminated by the end tag.
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001230 * (small item 0xf, len 1)
1231 */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001232 acpigen_emit_byte(BUFFER_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001233 acpigen_write_len_f();
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001234 acpigen_emit_byte(WORD_PREFIX);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001235 len_stack[ltop++] = acpigen_get_current();
Nico Huber7d89ce32017-04-14 00:08:18 +02001236 /* Add 2 dummy bytes for the ACPI word (keep aligned with
Elyes HAOUAS6716bab2020-01-09 21:29:25 +01001237 the calculation in acpigen_write_resourcetemplate() below). */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001238 acpigen_emit_byte(0x00);
1239 acpigen_emit_byte(0x00);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001240}
1241
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001242void acpigen_write_resourcetemplate_footer(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001243{
1244 char *p = len_stack[--ltop];
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001245 int len;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001246 /*
1247 * end tag (acpi 4.0 Section 6.4.2.8)
1248 * 0x79 <checksum>
1249 * 0x00 is treated as a good checksum according to the spec
1250 * and is what iasl generates.
1251 */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001252 acpigen_emit_byte(0x79);
1253 acpigen_emit_byte(0x00);
1254
Nico Huber7d89ce32017-04-14 00:08:18 +02001255 /* Start counting past the 2-bytes length added in
1256 acpigen_write_resourcetemplate() above. */
1257 len = acpigen_get_current() - (p + 2);
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001258
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001259 /* patch len word */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001260 p[0] = len & 0xff;
1261 p[1] = (len >> 8) & 0xff;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001262 /* patch len field */
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001263 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001264}
1265
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001266static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev, struct resource *res)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001267{
1268 acpigen_write_mem32fixed(0, res->base, res->size);
1269}
1270
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001271static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev, struct resource *res)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001272{
1273 resource_t base = res->base;
1274 resource_t size = res->size;
1275 while (size > 0) {
1276 resource_t sz = size > 255 ? 255 : size;
1277 acpigen_write_io16(base, base, 0, sz, 1);
1278 size -= sz;
1279 base += sz;
1280 }
1281}
1282
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001283void acpigen_write_mainboard_resource_template(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001284{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001285 acpigen_write_resourcetemplate_header();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001286
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001287 /* Add reserved memory ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001288 search_global_resources(
1289 IORESOURCE_MEM | IORESOURCE_RESERVE,
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001290 IORESOURCE_MEM | IORESOURCE_RESERVE,
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001291 acpigen_add_mainboard_rsvd_mem32, 0);
1292
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001293 /* Add reserved io ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001294 search_global_resources(
1295 IORESOURCE_IO | IORESOURCE_RESERVE,
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001296 IORESOURCE_IO | IORESOURCE_RESERVE,
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001297 acpigen_add_mainboard_rsvd_io, 0);
1298
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001299 acpigen_write_resourcetemplate_footer();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001300}
1301
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001302void acpigen_write_mainboard_resources(const char *scope, const char *name)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001303{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001304 acpigen_write_scope(scope);
1305 acpigen_write_name(name);
1306 acpigen_write_mainboard_resource_template();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001307 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001308}
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001309
1310static int hex2bin(const char c)
1311{
1312 if (c >= 'A' && c <= 'F')
1313 return c - 'A' + 10;
1314 if (c >= 'a' && c <= 'f')
1315 return c - 'a' + 10;
1316 return c - '0';
1317}
1318
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001319void acpigen_emit_eisaid(const char *eisaid)
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001320{
1321 u32 compact = 0;
1322
1323 /* Clamping individual values would be better but
1324 there is a disagreement over what is a valid
1325 EISA id, so accept anything and don't clamp,
1326 parent code should create a valid EISAid.
1327 */
1328 compact |= (eisaid[0] - 'A' + 1) << 26;
1329 compact |= (eisaid[1] - 'A' + 1) << 21;
1330 compact |= (eisaid[2] - 'A' + 1) << 16;
1331 compact |= hex2bin(eisaid[3]) << 12;
1332 compact |= hex2bin(eisaid[4]) << 8;
1333 compact |= hex2bin(eisaid[5]) << 4;
1334 compact |= hex2bin(eisaid[6]);
1335
1336 acpigen_emit_byte(0xc);
1337 acpigen_emit_byte((compact >> 24) & 0xff);
1338 acpigen_emit_byte((compact >> 16) & 0xff);
1339 acpigen_emit_byte((compact >> 8) & 0xff);
1340 acpigen_emit_byte(compact & 0xff);
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001341}
Duncan Laurie3829f232016-05-09 11:08:46 -07001342
1343/*
1344 * ToUUID(uuid)
1345 *
1346 * ACPI 6.1 Section 19.6.136 table 19-385 defines a special output
1347 * order for the bytes that make up a UUID Buffer object.
1348 * UUID byte order for input:
1349 * aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
1350 * UUID byte order for output:
1351 * ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
1352 */
1353#define UUID_LEN 16
1354void acpigen_write_uuid(const char *uuid)
1355{
1356 uint8_t buf[UUID_LEN];
1357 size_t i, order[UUID_LEN] = { 3, 2, 1, 0, 5, 4, 7, 6,
1358 8, 9, 10, 11, 12, 13, 14, 15 };
1359
1360 /* Parse UUID string into bytes */
1361 if (hexstrtobin(uuid, buf, UUID_LEN) < UUID_LEN)
1362 return;
1363
1364 /* BufferOp */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001365 acpigen_emit_byte(BUFFER_OP);
Duncan Laurie3829f232016-05-09 11:08:46 -07001366 acpigen_write_len_f();
1367
1368 /* Buffer length in bytes */
1369 acpigen_write_word(UUID_LEN);
1370
1371 /* Output UUID in expected order */
1372 for (i = 0; i < UUID_LEN; i++)
1373 acpigen_emit_byte(buf[order[i]]);
1374
1375 acpigen_pop_len();
1376}
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001377
1378/*
1379 * Name (_PRx, Package(One) { name })
1380 * ...
1381 * PowerResource (name, level, order)
1382 */
1383void acpigen_write_power_res(const char *name, uint8_t level, uint16_t order,
Furquan Shaikhdc782752020-04-30 22:49:39 -07001384 const char * const dev_states[], size_t dev_states_count)
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001385{
Elyes HAOUAScca6e002019-06-26 12:12:00 +02001386 size_t i;
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001387 for (i = 0; i < dev_states_count; i++) {
1388 acpigen_write_name(dev_states[i]);
1389 acpigen_write_package(1);
1390 acpigen_emit_simple_namestring(name);
1391 acpigen_pop_len(); /* Package */
1392 }
1393
1394 acpigen_emit_ext_op(POWER_RES_OP);
1395
1396 acpigen_write_len_f();
1397
1398 acpigen_emit_simple_namestring(name);
1399 acpigen_emit_byte(level);
1400 acpigen_emit_word(order);
1401}
1402
1403/* Sleep (ms) */
1404void acpigen_write_sleep(uint64_t sleep_ms)
1405{
1406 acpigen_emit_ext_op(SLEEP_OP);
1407 acpigen_write_integer(sleep_ms);
1408}
1409
1410void acpigen_write_store(void)
1411{
1412 acpigen_emit_byte(STORE_OP);
1413}
1414
1415/* Store (src, dst) */
1416void acpigen_write_store_ops(uint8_t src, uint8_t dst)
1417{
1418 acpigen_write_store();
1419 acpigen_emit_byte(src);
1420 acpigen_emit_byte(dst);
1421}
1422
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001423/* Store (src, "namestr") */
1424void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst)
1425{
1426 acpigen_write_store();
1427 acpigen_emit_byte(src);
1428 acpigen_emit_namestring(dst);
1429}
1430
Duncan Laurie8e391d32020-09-30 23:17:41 +00001431/* Store (src, "namestr") */
1432void acpigen_write_store_int_to_namestr(uint64_t src, const char *dst)
1433{
1434 acpigen_write_store();
1435 acpigen_write_integer(src);
1436 acpigen_emit_namestring(dst);
1437}
1438
Cliff Huang24f3dc82023-02-04 21:11:51 -08001439/* Store ("namestr", dst) */
1440void acpigen_write_store_namestr_to_op(const char *src, uint8_t dst)
1441{
1442 acpigen_write_store();
1443 acpigen_emit_namestring(src);
1444 acpigen_emit_byte(dst);
1445}
1446
Duncan Laurie8e391d32020-09-30 23:17:41 +00001447/* Store (src, dst) */
1448void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
1449{
1450 acpigen_write_store();
1451 acpigen_write_integer(src);
1452 acpigen_emit_byte(dst);
1453}
1454
Felix Held178cf352023-02-09 16:29:46 +01001455/* Store ("namestr", "namestr") */
1456void acpigen_write_store_namestr_to_namestr(const char *src, const char *dst)
1457{
1458 acpigen_write_store();
1459 acpigen_emit_namestring(src);
1460 acpigen_emit_namestring(dst);
1461}
1462
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001463/* Or (arg1, arg2, res) */
1464void acpigen_write_or(uint8_t arg1, uint8_t arg2, uint8_t res)
1465{
1466 acpigen_emit_byte(OR_OP);
1467 acpigen_emit_byte(arg1);
1468 acpigen_emit_byte(arg2);
1469 acpigen_emit_byte(res);
1470}
1471
Rajat Jain310623b2020-02-26 11:02:53 -08001472/* Xor (arg1, arg2, res) */
1473void acpigen_write_xor(uint8_t arg1, uint8_t arg2, uint8_t res)
1474{
1475 acpigen_emit_byte(XOR_OP);
1476 acpigen_emit_byte(arg1);
1477 acpigen_emit_byte(arg2);
1478 acpigen_emit_byte(res);
1479}
1480
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001481/* And (arg1, arg2, res) */
1482void acpigen_write_and(uint8_t arg1, uint8_t arg2, uint8_t res)
1483{
1484 acpigen_emit_byte(AND_OP);
1485 acpigen_emit_byte(arg1);
1486 acpigen_emit_byte(arg2);
1487 acpigen_emit_byte(res);
1488}
1489
1490/* Not (arg, res) */
1491void acpigen_write_not(uint8_t arg, uint8_t res)
1492{
1493 acpigen_emit_byte(NOT_OP);
1494 acpigen_emit_byte(arg);
1495 acpigen_emit_byte(res);
1496}
1497
Cliff Huange6083082023-01-19 21:18:23 -08001498/* Concatenate (str, src_res, dest_res) */
1499void acpigen_concatenate_string_op(const char *str, uint8_t src_res, uint8_t dest_res)
1500{
1501 acpigen_emit_byte(CONCATENATE_OP);
1502 acpigen_write_string(str);
1503 acpigen_emit_byte(src_res);
1504 acpigen_emit_byte(dest_res);
1505}
1506
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001507/* Store (str, DEBUG) */
1508void acpigen_write_debug_string(const char *str)
1509{
1510 acpigen_write_store();
1511 acpigen_write_string(str);
1512 acpigen_emit_ext_op(DEBUG_OP);
1513}
1514
1515/* Store (val, DEBUG) */
1516void acpigen_write_debug_integer(uint64_t val)
1517{
1518 acpigen_write_store();
1519 acpigen_write_integer(val);
1520 acpigen_emit_ext_op(DEBUG_OP);
1521}
1522
1523/* Store (op, DEBUG) */
1524void acpigen_write_debug_op(uint8_t op)
1525{
1526 acpigen_write_store();
1527 acpigen_emit_byte(op);
1528 acpigen_emit_ext_op(DEBUG_OP);
1529}
1530
Duncan Laurieec2e3e42020-11-03 15:19:08 -08001531/* Store (str, DEBUG) */
1532void acpigen_write_debug_namestr(const char *str)
1533{
1534 acpigen_write_store();
1535 acpigen_emit_namestring(str);
1536 acpigen_emit_ext_op(DEBUG_OP);
1537}
1538
Cliff Huange6083082023-01-19 21:18:23 -08001539/* Concatenate (str1, res, tmp_res)
1540 Store(tmp_res, DEBUG) */
1541void acpigen_write_debug_concatenate_string_op(const char *str, uint8_t res,
1542 uint8_t tmp_res)
1543{
1544 acpigen_concatenate_string_op(str, res, tmp_res);
1545 acpigen_write_debug_op(tmp_res);
1546}
1547
Cliff Huang063a1b82023-02-18 00:17:26 -08001548static void acpigen_tx_byte(unsigned char byte, void *data)
1549{
1550 acpigen_emit_byte(byte);
1551}
1552
1553/* Store("formatted string", DEBUG) */
1554void acpigen_write_debug_sprintf(const char *fmt, ...)
1555{
1556 va_list args;
1557
1558 acpigen_write_store();
1559
1560 acpigen_emit_byte(STRING_PREFIX);
1561 va_start(args, fmt);
1562 vtxprintf(acpigen_tx_byte, fmt, args, NULL);
1563 va_end(args);
1564 acpigen_emit_byte('\0');
1565
1566 acpigen_emit_ext_op(DEBUG_OP);
1567}
1568
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001569void acpigen_write_if(void)
1570{
1571 acpigen_emit_byte(IF_OP);
1572 acpigen_write_len_f();
1573}
1574
1575/* If (And (arg1, arg2)) */
1576void acpigen_write_if_and(uint8_t arg1, uint8_t arg2)
1577{
1578 acpigen_write_if();
1579 acpigen_emit_byte(AND_OP);
1580 acpigen_emit_byte(arg1);
1581 acpigen_emit_byte(arg2);
1582}
1583
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001584/*
Duncan Laurie2fe74712020-06-01 17:36:56 -07001585 * Generates ACPI code for checking if operand1 and operand2 are equal.
1586 * Both operand1 and operand2 are ACPI ops.
1587 *
1588 * If (Lequal (op,1 op2))
1589 */
1590void acpigen_write_if_lequal_op_op(uint8_t op1, uint8_t op2)
1591{
1592 acpigen_write_if();
1593 acpigen_emit_byte(LEQUAL_OP);
1594 acpigen_emit_byte(op1);
1595 acpigen_emit_byte(op2);
1596}
1597
1598/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001599 * Generates ACPI code for checking if operand1 is greater than operand2.
1600 * Both operand1 and operand2 are ACPI ops.
1601 *
1602 * If (Lgreater (op1 op2))
1603 */
1604void acpigen_write_if_lgreater_op_op(uint8_t op1, uint8_t op2)
1605{
1606 acpigen_write_if();
1607 acpigen_emit_byte(LGREATER_OP);
1608 acpigen_emit_byte(op1);
1609 acpigen_emit_byte(op2);
1610}
1611
1612/*
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001613 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1614 * operand1 is ACPI op and operand2 is an integer.
1615 *
1616 * If (Lequal (op, val))
1617 */
1618void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001619{
1620 acpigen_write_if();
1621 acpigen_emit_byte(LEQUAL_OP);
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001622 acpigen_emit_byte(op);
1623 acpigen_write_integer(val);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001624}
1625
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001626/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001627 * Generates ACPI code for checking if operand is greater than the value, where,
1628 * operand is ACPI op and val is an integer.
1629 *
1630 * If (Lgreater (op, val))
1631 */
1632void acpigen_write_if_lgreater_op_int(uint8_t op, uint64_t val)
1633{
1634 acpigen_write_if();
1635 acpigen_emit_byte(LGREATER_OP);
1636 acpigen_emit_byte(op);
1637 acpigen_write_integer(val);
1638}
1639
1640/*
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001641 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1642 * operand1 is namestring and operand2 is an integer.
1643 *
1644 * If (Lequal ("namestr", val))
1645 */
1646void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val)
1647{
1648 acpigen_write_if();
1649 acpigen_emit_byte(LEQUAL_OP);
1650 acpigen_emit_namestring(namestr);
1651 acpigen_write_integer(val);
1652}
1653
Tim Wawrzynczakc4ca2f62021-07-01 11:18:50 -06001654/*
Cliff Huang24f3dc82023-02-04 21:11:51 -08001655 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1656 * operand1 is namestring and operand2 is an integer.
1657 *
1658 * If (Lgreater ("namestr", val))
1659 */
1660void acpigen_write_if_lgreater_namestr_int(const char *namestr, uint64_t val)
1661{
1662 acpigen_write_if();
1663 acpigen_emit_byte(LGREATER_OP);
1664 acpigen_emit_namestring(namestr);
1665 acpigen_write_integer(val);
1666}
1667
1668/*
Tim Wawrzynczakc4ca2f62021-07-01 11:18:50 -06001669 * Generates ACPI code to check at runtime if an object named `namestring`
1670 * exists, and leaves the If scope open to continue execute code when this
1671 * is true. NOTE: Requires matching acpigen_write_if_end().
1672 *
1673 * If (CondRefOf (NAME))
1674 */
1675void acpigen_write_if_cond_ref_of(const char *namestring)
1676{
1677 acpigen_write_if();
1678 acpigen_emit_ext_op(COND_REFOF_OP);
1679 acpigen_emit_namestring(namestring);
1680 acpigen_emit_byte(ZERO_OP); /* ignore COND_REFOF_OP destination */
1681}
1682
Jakub Czapiga61fcb7e2021-02-19 11:44:22 +01001683/* Closes previously opened if statement and generates ACPI code for else statement. */
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001684void acpigen_write_else(void)
1685{
Jakub Czapiga61fcb7e2021-02-19 11:44:22 +01001686 acpigen_pop_len();
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001687 acpigen_emit_byte(ELSE_OP);
1688 acpigen_write_len_f();
1689}
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001690
Duncan Laurie36858202020-10-06 21:01:51 +00001691void acpigen_write_shiftleft_op_int(uint8_t src_result, uint64_t count)
1692{
1693 acpigen_emit_byte(SHIFT_LEFT_OP);
1694 acpigen_emit_byte(src_result);
1695 acpigen_write_integer(count);
1696 acpigen_emit_byte(ZERO_OP);
1697}
1698
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001699void acpigen_write_to_buffer(uint8_t src, uint8_t dst)
1700{
1701 acpigen_emit_byte(TO_BUFFER_OP);
1702 acpigen_emit_byte(src);
1703 acpigen_emit_byte(dst);
1704}
1705
1706void acpigen_write_to_integer(uint8_t src, uint8_t dst)
1707{
1708 acpigen_emit_byte(TO_INTEGER_OP);
1709 acpigen_emit_byte(src);
1710 acpigen_emit_byte(dst);
1711}
1712
Aaron Durbin80bc0912020-08-19 23:17:42 -06001713void acpigen_write_to_integer_from_namestring(const char *source, uint8_t dst_op)
1714{
1715 acpigen_emit_byte(TO_INTEGER_OP);
1716 acpigen_emit_namestring(source);
1717 acpigen_emit_byte(dst_op);
1718}
1719
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301720void acpigen_write_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001721{
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301722 size_t i;
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001723
1724 acpigen_emit_byte(BUFFER_OP);
1725 acpigen_write_len_f();
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301726 acpigen_write_integer(size);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001727
1728 for (i = 0; i < size; i++)
1729 acpigen_emit_byte(arr[i]);
1730
1731 acpigen_pop_len();
1732}
1733
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301734void acpigen_write_return_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001735{
1736 acpigen_emit_byte(RETURN_OP);
1737 acpigen_write_byte_buffer(arr, size);
1738}
1739
1740void acpigen_write_return_singleton_buffer(uint8_t arg)
1741{
1742 acpigen_write_return_byte_buffer(&arg, 1);
1743}
1744
Duncan Laurie2fe74712020-06-01 17:36:56 -07001745void acpigen_write_return_op(uint8_t arg)
1746{
1747 acpigen_emit_byte(RETURN_OP);
1748 acpigen_emit_byte(arg);
1749}
1750
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001751void acpigen_write_return_byte(uint8_t arg)
1752{
1753 acpigen_emit_byte(RETURN_OP);
1754 acpigen_write_byte(arg);
1755}
1756
Naresh G Solanki05abe432016-11-17 00:16:29 +05301757void acpigen_write_return_integer(uint64_t arg)
1758{
1759 acpigen_emit_byte(RETURN_OP);
1760 acpigen_write_integer(arg);
1761}
1762
Duncan Laurieec2e3e42020-11-03 15:19:08 -08001763void acpigen_write_return_namestr(const char *arg)
1764{
1765 acpigen_emit_byte(RETURN_OP);
1766 acpigen_emit_namestring(arg);
1767}
1768
Naresh G Solanki05abe432016-11-17 00:16:29 +05301769void acpigen_write_return_string(const char *arg)
1770{
1771 acpigen_emit_byte(RETURN_OP);
1772 acpigen_write_string(arg);
1773}
1774
Duncan Lauriebeb2af42018-05-07 14:26:59 -07001775void acpigen_write_upc(enum acpi_upc_type type)
1776{
1777 acpigen_write_name("_UPC");
1778 acpigen_write_package(4);
1779 /* Connectable */
1780 acpigen_write_byte(type == UPC_TYPE_UNUSED ? 0 : 0xff);
1781 /* Type */
1782 acpigen_write_byte(type);
1783 /* Reserved0 */
1784 acpigen_write_zero();
1785 /* Reserved1 */
1786 acpigen_write_zero();
1787 acpigen_pop_len();
1788}
1789
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001790void acpigen_write_pld(const struct acpi_pld *pld)
1791{
1792 uint8_t buf[20];
1793
1794 if (acpi_pld_to_buffer(pld, buf, ARRAY_SIZE(buf)) < 0)
1795 return;
1796
1797 acpigen_write_name("_PLD");
Matt Delco4929f432019-01-30 11:40:44 -08001798 acpigen_write_package(1);
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001799 acpigen_write_byte_buffer(buf, ARRAY_SIZE(buf));
Matt Delco4929f432019-01-30 11:40:44 -08001800 acpigen_pop_len();
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001801}
1802
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001803void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *), size_t count, void *arg)
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301804{
1805 struct dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg);
1806 acpigen_write_dsm_uuid_arr(&id, 1);
1807}
1808
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001809/*
1810 * Create a supported functions bitmask
1811 * bit 0: other functions than 0 are supported
1812 * bits 1-x: function x supported
1813 */
Arthur Heymans9c1f78d2023-06-22 21:04:06 +02001814/* On GCC aarch64 the compiler is worried about alloca() having unbounded stack usage. */
1815#if defined(__GNUC__) && !defined(__clang__)
1816#pragma GCC diagnostic ignored "-Wstack-usage="
1817#endif
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001818static void acpigen_dsm_uuid_enum_functions(const struct dsm_uuid *id)
1819{
1820 const size_t bytes = DIV_ROUND_UP(id->count, BITS_PER_BYTE);
1821 uint8_t *buffer = alloca(bytes);
1822 bool set = false;
1823 size_t cb_idx = 0;
1824
1825 memset(buffer, 0, bytes);
1826
1827 for (size_t i = 0; i < bytes; i++) {
1828 for (size_t j = 0; j < BITS_PER_BYTE; j++) {
1829 if (cb_idx >= id->count)
1830 break;
1831
1832 if (id->callbacks[cb_idx++]) {
1833 set = true;
1834 buffer[i] |= BIT(j);
1835 }
1836 }
1837 }
1838
1839 if (set)
1840 buffer[0] |= BIT(0);
1841
1842 acpigen_write_return_byte_buffer(buffer, bytes);
1843}
1844
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301845static void acpigen_write_dsm_uuid(struct dsm_uuid *id)
1846{
1847 size_t i;
1848
1849 /* If (LEqual (Local0, ToUUID(uuid))) */
1850 acpigen_write_if();
1851 acpigen_emit_byte(LEQUAL_OP);
1852 acpigen_emit_byte(LOCAL0_OP);
1853 acpigen_write_uuid(id->uuid);
1854
1855 /* ToInteger (Arg2, Local1) */
1856 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
1857
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001858 /* If (LEqual(Local1, 0)) */
1859 {
1860 acpigen_write_if_lequal_op_int(LOCAL1_OP, 0);
1861 if (id->callbacks[0])
1862 id->callbacks[0](id->arg);
1863 else if (id->count)
1864 acpigen_dsm_uuid_enum_functions(id);
1865 acpigen_write_if_end();
1866 }
1867
1868 for (i = 1; i < id->count; i++) {
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301869 /* If (LEqual (Local1, i)) */
1870 acpigen_write_if_lequal_op_int(LOCAL1_OP, i);
1871
1872 /* Callback to write if handler. */
1873 if (id->callbacks[i])
1874 id->callbacks[i](id->arg);
1875
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001876 acpigen_write_if_end(); /* If */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301877 }
1878
1879 /* Default case: Return (Buffer (One) { 0x0 }) */
1880 acpigen_write_return_singleton_buffer(0x0);
1881
Tim Wawrzynczakd96f3a22021-07-14 15:56:57 -06001882 acpigen_write_if_end(); /* If (LEqual (Local0, ToUUID(uuid))) */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301883}
1884
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001885/*
1886 * Generate ACPI AML code for _DSM method.
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301887 * This function takes as input array of uuid for the device, set of callbacks
1888 * and argument to pass into the callbacks. Callbacks should ensure that Local0
1889 * and Local1 are left untouched. Use of Local2-Local7 is permitted in
1890 * callbacks.
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001891 *
1892 * Arguments passed into _DSM method:
1893 * Arg0 = UUID
1894 * Arg1 = Revision
1895 * Arg2 = Function index
1896 * Arg3 = Function specific arguments
1897 *
1898 * AML code generated would look like:
1899 * Method (_DSM, 4, Serialized) {
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301900 * ToBuffer (Arg0, Local0)
1901 * If (LEqual (Local0, ToUUID(uuid))) {
1902 * ToInteger (Arg2, Local1)
1903 * If (LEqual (Local1, 0)) {
1904 * <acpigen by callback[0]>
1905 * }
1906 * ...
1907 * If (LEqual (Local1, n)) {
1908 * <acpigen by callback[n]>
1909 * }
1910 * Return (Buffer (One) { 0x0 })
1911 * }
1912 * ...
1913 * If (LEqual (Local0, ToUUID(uuidn))) {
1914 * ...
1915 * }
1916 * Return (Buffer (One) { 0x0 })
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001917 * }
1918 */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301919void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count)
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001920{
1921 size_t i;
1922
1923 /* Method (_DSM, 4, Serialized) */
1924 acpigen_write_method_serialized("_DSM", 0x4);
1925
1926 /* ToBuffer (Arg0, Local0) */
1927 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
1928
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001929 for (i = 0; i < count; i++)
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301930 acpigen_write_dsm_uuid(&ids[i]);
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001931
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301932 /* Return (Buffer (One) { 0x0 }) */
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001933 acpigen_write_return_singleton_buffer(0x0);
1934
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001935 acpigen_pop_len(); /* Method _DSM */
1936}
1937
Matt Delcob425bc82018-08-13 13:36:27 -07001938void acpigen_write_CPPC_package(const struct cppc_config *config)
1939{
1940 u32 i;
1941 u32 max;
1942 switch (config->version) {
1943 case 1:
1944 max = CPPC_MAX_FIELDS_VER_1;
1945 break;
1946 case 2:
1947 max = CPPC_MAX_FIELDS_VER_2;
1948 break;
1949 case 3:
1950 max = CPPC_MAX_FIELDS_VER_3;
1951 break;
1952 default:
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01001953 printk(BIOS_ERR, "CPPC version %u is not implemented\n", config->version);
Matt Delcob425bc82018-08-13 13:36:27 -07001954 return;
1955 }
1956 acpigen_write_name(CPPC_PACKAGE_NAME);
1957
1958 /* Adding 2 to account for length and version fields */
1959 acpigen_write_package(max + 2);
1960 acpigen_write_dword(max + 2);
1961
1962 acpigen_write_byte(config->version);
1963
1964 for (i = 0; i < max; ++i) {
Michael Niewöhner38107fa2021-10-05 22:22:21 +02001965 const cppc_entry_t *entry = &config->entries[i];
1966 if (entry->type == CPPC_TYPE_DWORD)
1967 acpigen_write_dword(entry->dword);
1968 else
1969 acpigen_write_register_resource(&entry->reg);
Matt Delcob425bc82018-08-13 13:36:27 -07001970 }
1971 acpigen_pop_len();
1972}
1973
1974void acpigen_write_CPPC_method(void)
1975{
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001976 char pscope[16];
Felix Heldf0a8b042023-05-12 15:55:06 +02001977 snprintf(pscope, sizeof(pscope),
1978 "\\_SB." CONFIG_ACPI_CPU_STRING "." CPPC_PACKAGE_NAME, 0);
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001979
Matt Delcob425bc82018-08-13 13:36:27 -07001980 acpigen_write_method("_CPC", 0);
1981 acpigen_emit_byte(RETURN_OP);
Michael Niewöhnerb20aac02020-10-14 19:30:46 +02001982 acpigen_emit_namestring(pscope);
Matt Delcob425bc82018-08-13 13:36:27 -07001983 acpigen_pop_len();
1984}
1985
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001986/*
1987 * Generate ACPI AML code for _ROM method.
1988 * This function takes as input ROM data and ROM length.
1989 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001990 * The ACPI spec isn't clear about what should happen at the end of the
1991 * ROM. Tests showed that it shouldn't truncate, but fill the remaining
1992 * bytes in the returned buffer with zeros.
1993 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001994 * Arguments passed into _DSM method:
1995 * Arg0 = Offset in Bytes
1996 * Arg1 = Bytes to return
1997 *
1998 * Example:
1999 * acpigen_write_rom(0xdeadbeef, 0x10000)
2000 *
2001 * AML code generated would look like:
2002 * Method (_ROM, 2, NotSerialized) {
2003 *
2004 * OperationRegion("ROMS", SYSTEMMEMORY, 0xdeadbeef, 0x10000)
2005 * Field (ROMS, AnyAcc, NoLock, Preserve)
2006 * {
2007 * Offset (0),
2008 * RBF0, 0x80000
2009 * }
2010 *
2011 * Store (Arg0, Local0)
2012 * Store (Arg1, Local1)
2013 *
2014 * If (LGreater (Local1, 0x1000))
2015 * {
2016 * Store (0x1000, Local1)
2017 * }
2018 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002019 * Store (Local1, Local3)
2020 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002021 * If (LGreater (Local0, 0x10000))
2022 * {
2023 * Return(Buffer(Local1){0})
2024 * }
2025 *
2026 * If (LGreater (Local0, 0x0f000))
2027 * {
2028 * Subtract (0x10000, Local0, Local2)
2029 * If (LGreater (Local1, Local2))
2030 * {
2031 * Store (Local2, Local1)
2032 * }
2033 * }
2034 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002035 * Name (ROM1, Buffer (Local3) {0})
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002036 *
2037 * Multiply (Local0, 0x08, Local0)
2038 * Multiply (Local1, 0x08, Local1)
2039 *
2040 * CreateField (RBF0, Local0, Local1, TMPB)
2041 * Store (TMPB, ROM1)
2042 * Return (ROM1)
2043 * }
2044 */
2045
2046void acpigen_write_rom(void *bios, const size_t length)
2047{
2048 ASSERT(bios)
2049 ASSERT(length)
2050
Jonathan Neuschäfer6b0102d2018-09-12 12:26:45 +02002051 /* Method (_ROM, 2, Serialized) */
Marc Jones24462e62018-08-15 23:57:28 -06002052 acpigen_write_method_serialized("_ROM", 2);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002053
2054 /* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002055 struct opregion opreg = OPREGION("ROMS", SYSTEMMEMORY, (uintptr_t)bios, length);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002056 acpigen_write_opregion(&opreg);
2057
2058 struct fieldlist l[] = {
2059 FIELDLIST_OFFSET(0),
2060 FIELDLIST_NAMESTR("RBF0", 8 * length),
2061 };
2062
2063 /* Field (ROMS, AnyAcc, NoLock, Preserve)
2064 * {
2065 * Offset (0),
2066 * RBF0, 0x80000
2067 * } */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002068 acpigen_write_field(opreg.name, l, 2, FIELD_ANYACC | FIELD_NOLOCK | FIELD_PRESERVE);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002069
2070 /* Store (Arg0, Local0) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002071 acpigen_write_store_ops(ARG0_OP, LOCAL0_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002072
2073 /* Store (Arg1, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002074 acpigen_write_store_ops(ARG1_OP, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002075
2076 /* ACPI SPEC requires to return at maximum 4KiB */
2077 /* If (LGreater (Local1, 0x1000)) */
Felix Held383a06e2023-02-09 16:25:38 +01002078 acpigen_write_if_lgreater_op_int(LOCAL1_OP, 0x1000);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002079
2080 /* Store (0x1000, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002081 acpigen_write_store_int_to_op(0x1000, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002082
2083 /* Pop if */
2084 acpigen_pop_len();
2085
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002086 /* Store (Local1, Local3) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002087 acpigen_write_store_ops(LOCAL1_OP, LOCAL3_OP);
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002088
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002089 /* If (LGreater (Local0, length)) */
Felix Held383a06e2023-02-09 16:25:38 +01002090 acpigen_write_if_lgreater_op_int(LOCAL0_OP, length);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002091
2092 /* Return(Buffer(Local1){0}) */
2093 acpigen_emit_byte(RETURN_OP);
2094 acpigen_emit_byte(BUFFER_OP);
2095 acpigen_write_len_f();
2096 acpigen_emit_byte(LOCAL1_OP);
2097 acpigen_emit_byte(0);
2098 acpigen_pop_len();
2099
2100 /* Pop if */
2101 acpigen_pop_len();
2102
2103 /* If (LGreater (Local0, length - 4096)) */
Felix Held383a06e2023-02-09 16:25:38 +01002104 acpigen_write_if_lgreater_op_int(LOCAL0_OP, length - 4096);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002105
2106 /* Subtract (length, Local0, Local2) */
2107 acpigen_emit_byte(SUBTRACT_OP);
2108 acpigen_write_integer(length);
2109 acpigen_emit_byte(LOCAL0_OP);
2110 acpigen_emit_byte(LOCAL2_OP);
2111
2112 /* If (LGreater (Local1, Local2)) */
Felix Held383a06e2023-02-09 16:25:38 +01002113 acpigen_write_if_lgreater_op_op(LOCAL1_OP, LOCAL2_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002114
2115 /* Store (Local2, Local1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002116 acpigen_write_store_ops(LOCAL2_OP, LOCAL1_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002117
2118 /* Pop if */
2119 acpigen_pop_len();
2120
2121 /* Pop if */
2122 acpigen_pop_len();
2123
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002124 /* Name (ROM1, Buffer (Local3) {0}) */
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002125 acpigen_write_name("ROM1");
2126 acpigen_emit_byte(BUFFER_OP);
2127 acpigen_write_len_f();
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02002128 acpigen_emit_byte(LOCAL3_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002129 acpigen_emit_byte(0);
2130 acpigen_pop_len();
2131
2132 /* Multiply (Local1, 0x08, Local1) */
2133 acpigen_emit_byte(MULTIPLY_OP);
2134 acpigen_emit_byte(LOCAL1_OP);
2135 acpigen_write_integer(0x08);
2136 acpigen_emit_byte(LOCAL1_OP);
2137
2138 /* Multiply (Local0, 0x08, Local0) */
2139 acpigen_emit_byte(MULTIPLY_OP);
2140 acpigen_emit_byte(LOCAL0_OP);
2141 acpigen_write_integer(0x08);
2142 acpigen_emit_byte(LOCAL0_OP);
2143
2144 /* CreateField (RBF0, Local0, Local1, TMPB) */
2145 acpigen_emit_ext_op(CREATEFIELD_OP);
2146 acpigen_emit_namestring("RBF0");
2147 acpigen_emit_byte(LOCAL0_OP);
2148 acpigen_emit_byte(LOCAL1_OP);
2149 acpigen_emit_namestring("TMPB");
2150
2151 /* Store (TMPB, ROM1) */
Felix Heldf28f27b2023-02-09 16:26:26 +01002152 acpigen_write_store_namestr_to_namestr("TMPB", "ROM1");
Patrick Rudolph6be6df02017-04-28 16:34:26 +02002153
2154 /* Return (ROM1) */
2155 acpigen_emit_byte(RETURN_OP);
2156 acpigen_emit_namestring("ROM1");
2157
2158 /* Pop method */
2159 acpigen_pop_len();
2160}
2161
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002162/*
2163 * Helper functions for enabling/disabling Tx GPIOs based on the GPIO
2164 * polarity. These functions end up calling acpigen_soc_{set,clear}_tx_gpio to
2165 * make callbacks into SoC acpigen code.
2166 *
2167 * Returns 0 on success and -1 on error.
2168 */
Duncan Laurie30c3f912020-10-09 04:48:53 +00002169int acpigen_enable_tx_gpio(const struct acpi_gpio *gpio)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002170{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002171 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002172 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002173 else
2174 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002175}
2176
Duncan Laurie30c3f912020-10-09 04:48:53 +00002177int acpigen_disable_tx_gpio(const struct acpi_gpio *gpio)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002178{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002179 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08002180 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
2181 else
2182 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
2183}
Jonathan Zhang71299c22020-01-27 11:38:57 -08002184
Duncan Laurie30c3f912020-10-09 04:48:53 +00002185void acpigen_get_rx_gpio(const struct acpi_gpio *gpio)
Rajat Jain310623b2020-02-26 11:02:53 -08002186{
2187 acpigen_soc_read_rx_gpio(gpio->pins[0]);
2188
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002189 if (gpio->active_low)
Rajat Jain310623b2020-02-26 11:02:53 -08002190 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
2191}
2192
Duncan Laurie30c3f912020-10-09 04:48:53 +00002193void acpigen_get_tx_gpio(const struct acpi_gpio *gpio)
Duncan Laurie2fe74712020-06-01 17:36:56 -07002194{
2195 acpigen_soc_get_tx_gpio(gpio->pins[0]);
2196
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07002197 if (gpio->active_low)
Duncan Laurie2fe74712020-06-01 17:36:56 -07002198 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
2199}
2200
Jonathan Zhang71299c22020-01-27 11:38:57 -08002201/* refer to ACPI 6.4.3.5.3 Word Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002202void acpigen_resource_word(u16 res_type, u16 gen_flags, u16 type_flags, u16 gran, u16 range_min,
2203 u16 range_max, u16 translation, u16 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002204{
Felix Heldb2f2b532023-05-11 22:22:06 +02002205 /* Byte 0: Type 1, Large Item Value 0x8: Word Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002206 acpigen_emit_byte(0x88);
2207 /* Byte 1+2: length (0x000d) */
2208 acpigen_emit_byte(0x0d);
2209 acpigen_emit_byte(0x00);
2210 /* resource type */
2211 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2212 /* general flags */
2213 acpigen_emit_byte(gen_flags);
2214 /* type flags */
2215 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2216 acpigen_emit_byte(type_flags);
2217 /* granularity, min, max, translation, length */
2218 acpigen_emit_word(gran);
2219 acpigen_emit_word(range_min);
2220 acpigen_emit_word(range_max);
2221 acpigen_emit_word(translation);
2222 acpigen_emit_word(length);
2223}
2224
2225/* refer to ACPI 6.4.3.5.2 DWord Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002226void acpigen_resource_dword(u16 res_type, u16 gen_flags, u16 type_flags, u32 gran,
2227 u32 range_min, u32 range_max, u32 translation, u32 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002228{
Felix Heldb2f2b532023-05-11 22:22:06 +02002229 /* Byte 0: Type 1, Large Item Value 0x7: DWord Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002230 acpigen_emit_byte(0x87);
2231 /* Byte 1+2: length (0023) */
2232 acpigen_emit_byte(23);
2233 acpigen_emit_byte(0x00);
2234 /* resource type */
2235 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2236 /* general flags */
2237 acpigen_emit_byte(gen_flags);
2238 /* type flags */
2239 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2240 acpigen_emit_byte(type_flags);
2241 /* granularity, min, max, translation, length */
2242 acpigen_emit_dword(gran);
2243 acpigen_emit_dword(range_min);
2244 acpigen_emit_dword(range_max);
2245 acpigen_emit_dword(translation);
2246 acpigen_emit_dword(length);
2247}
2248
2249static void acpigen_emit_qword(u64 data)
2250{
2251 acpigen_emit_dword(data & 0xffffffff);
2252 acpigen_emit_dword((data >> 32) & 0xffffffff);
2253}
2254
2255/* refer to ACPI 6.4.3.5.1 QWord Address Space Descriptor section for details */
Elyes Haouas1f5e1b42022-02-17 17:44:07 +01002256void acpigen_resource_qword(u16 res_type, u16 gen_flags, u16 type_flags, u64 gran,
2257 u64 range_min, u64 range_max, u64 translation, u64 length)
Jonathan Zhang71299c22020-01-27 11:38:57 -08002258{
Felix Heldb2f2b532023-05-11 22:22:06 +02002259 /* Byte 0: Type 1, Large Item Value 0xa: QWord Address Space Descriptor */
Jonathan Zhang71299c22020-01-27 11:38:57 -08002260 acpigen_emit_byte(0x8a);
2261 /* Byte 1+2: length (0x002b) */
2262 acpigen_emit_byte(0x2b);
2263 acpigen_emit_byte(0x00);
2264 /* resource type */
2265 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
2266 /* general flags */
2267 acpigen_emit_byte(gen_flags);
2268 /* type flags */
2269 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
2270 acpigen_emit_byte(type_flags);
2271 /* granularity, min, max, translation, length */
2272 acpigen_emit_qword(gran);
2273 acpigen_emit_qword(range_min);
2274 acpigen_emit_qword(range_max);
2275 acpigen_emit_qword(translation);
2276 acpigen_emit_qword(length);
2277}
Furquan Shaikh1a829232020-04-23 11:11:05 -07002278
Felix Held0fdede02023-05-27 01:02:37 +02002279void acpigen_resource_producer_bus_number(u16 bus_base, u16 bus_limit)
Felix Held5a82f0d2023-05-09 16:10:35 +02002280{
2281 acpigen_resource_word(RSRC_TYPE_BUS, /* res_type */
2282 ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2283 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
Felix Held0fdede02023-05-27 01:02:37 +02002284 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2285 | ADDR_SPACE_GENERAL_FLAG_PRODUCER, /* gen_flags */
Felix Held5a82f0d2023-05-09 16:10:35 +02002286 BUS_NUM_RANGE_RESOURCE_FLAG, /* type_flags */
2287 0, /* gran */
2288 bus_base, /* range_min */
2289 bus_limit, /* range_max */
2290 0x0, /* translation */
2291 bus_limit - bus_base + 1); /* length */
2292}
2293
Felix Held0fdede02023-05-27 01:02:37 +02002294void acpigen_resource_producer_io(u16 io_base, u16 io_limit)
Felix Held6695be62023-05-09 16:18:51 +02002295{
Felix Helde3c9a042023-06-05 19:59:25 +02002296 acpigen_resource_dword(RSRC_TYPE_IO, /* res_type */
Felix Held6695be62023-05-09 16:18:51 +02002297 ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2298 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
Felix Held0fdede02023-05-27 01:02:37 +02002299 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2300 | ADDR_SPACE_GENERAL_FLAG_PRODUCER, /* gen_flags */
Felix Held6695be62023-05-09 16:18:51 +02002301 IO_RSRC_FLAG_ENTIRE_RANGE, /* type_flags */
2302 0, /* gran */
2303 io_base, /* range_min */
2304 io_limit, /* range_max */
2305 0x0, /* translation */
2306 io_limit - io_base + 1); /* length */
2307}
2308
Arthur Heymans62f788e2023-11-21 18:49:33 +01002309static void acpigen_resource_mmio32(u32 mmio_base, u32 mmio_limit, u16 gen_flags,
2310 u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002311{
2312 acpigen_resource_dword(RSRC_TYPE_MEM, /* res_type */
Arthur Heymans62f788e2023-11-21 18:49:33 +01002313 gen_flags, /* gen_flags */
2314 type_flags, /* type_flags */
2315 0, /* gran */
2316 mmio_base, /* range_min */
2317 mmio_limit, /* range_max */
2318 0x0, /* translation */
2319 mmio_limit - mmio_base + 1); /* length */
Felix Held21594fd12023-05-09 16:39:57 +02002320}
2321
Arthur Heymans62f788e2023-11-21 18:49:33 +01002322static void acpigen_resource_mmio64(u64 mmio_base, u64 mmio_limit, u16 gen_flags,
2323 u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002324{
2325 acpigen_resource_qword(RSRC_TYPE_MEM, /* res_type */
Arthur Heymans62f788e2023-11-21 18:49:33 +01002326 gen_flags, /* gen_flags */
2327 type_flags, /* type_flags */
2328 0, /* gran */
2329 mmio_base, /* range_min */
2330 mmio_limit, /* range_max */
2331 0x0, /* translation */
2332 mmio_limit - mmio_base + 1); /* length */
2333}
2334
2335static void acpigen_resource_mmio(u64 mmio_base, u64 mmio_limit, bool is_producer, u16 type_flags)
2336{
2337 const u16 gen_flags = ADDR_SPACE_GENERAL_FLAG_MAX_FIXED
2338 | ADDR_SPACE_GENERAL_FLAG_MIN_FIXED
2339 | ADDR_SPACE_GENERAL_FLAG_DEC_POS
2340 | (is_producer ? ADDR_SPACE_GENERAL_FLAG_PRODUCER
2341 : ADDR_SPACE_GENERAL_FLAG_CONSUMER);
2342
2343 if (mmio_base < 4ULL * GiB && mmio_limit < 4ULL * GiB)
2344 acpigen_resource_mmio32(mmio_base, mmio_limit, gen_flags, type_flags);
2345 else
2346 acpigen_resource_mmio64(mmio_base, mmio_limit, gen_flags, type_flags);
Felix Held21594fd12023-05-09 16:39:57 +02002347}
2348
Felix Held0fdede02023-05-27 01:02:37 +02002349void acpigen_resource_producer_mmio(u64 mmio_base, u64 mmio_limit, u16 type_flags)
Felix Held21594fd12023-05-09 16:39:57 +02002350{
Arthur Heymans62f788e2023-11-21 18:49:33 +01002351 acpigen_resource_mmio(mmio_base, mmio_limit, true, type_flags);
2352}
2353
2354void acpigen_resource_consumer_mmio(u64 mmio_base, u64 mmio_limit, u16 type_flags)
2355{
2356 acpigen_resource_mmio(mmio_base, mmio_limit, false, type_flags);
Felix Held21594fd12023-05-09 16:39:57 +02002357}
2358
Furquan Shaikh1a829232020-04-23 11:11:05 -07002359void acpigen_write_ADR(uint64_t adr)
2360{
2361 acpigen_write_name_qword("_ADR", adr);
2362}
2363
Duncan Laurie08a942f2020-04-29 12:13:14 -07002364/**
2365 * acpigen_write_ADR_soundwire_device() - SoundWire ACPI Device Address Encoding.
2366 * @address: SoundWire device address properties.
2367 *
2368 * From SoundWire Discovery and Configuration Specification Version 1.0 Table 3.
2369 *
2370 * 63..52 - Reserved (0)
2371 * 51..48 - Zero-based SoundWire Link ID, relative to the immediate parent.
2372 * Used when a Controller has multiple master devices, each producing a
2373 * separate SoundWire Link. Set to 0 for single-link controllers.
2374 * 47..0 - SoundWire Device ID Encoding from specification version 1.2 table 88
2375 * 47..44 - SoundWire specification version that this device supports
2376 * 43..40 - Unique ID for multiple devices
2377 * 39..24 - MIPI standard manufacturer code
2378 * 23..08 - Vendor defined part ID
2379 * 07..00 - MIPI class encoding
2380 */
2381void acpigen_write_ADR_soundwire_device(const struct soundwire_address *address)
2382{
2383 acpigen_write_ADR((((uint64_t)address->link_id & 0xf) << 48) |
2384 (((uint64_t)address->version & 0xf) << 44) |
2385 (((uint64_t)address->unique_id & 0xf) << 40) |
2386 (((uint64_t)address->manufacturer_id & 0xffff) << 24) |
2387 (((uint64_t)address->part_id & 0xffff) << 8) |
2388 (((uint64_t)address->class & 0xff)));
2389}
Tim Wawrzynczakf6945022020-06-04 15:18:47 -06002390
2391void acpigen_notify(const char *namestr, int value)
2392{
2393 acpigen_emit_byte(NOTIFY_OP);
2394 acpigen_emit_namestring(namestr);
2395 acpigen_write_integer(value);
2396}
Aaron Durbin80bc0912020-08-19 23:17:42 -06002397
2398static void _create_field(uint8_t aml_op, uint8_t srcop, size_t byte_offset, const char *name)
2399{
2400 acpigen_emit_byte(aml_op);
2401 acpigen_emit_byte(srcop);
2402 acpigen_write_integer(byte_offset);
2403 acpigen_emit_namestring(name);
2404}
2405
2406void acpigen_write_create_byte_field(uint8_t op, size_t byte_offset, const char *name)
2407{
2408 _create_field(CREATE_BYTE_OP, op, byte_offset, name);
2409}
2410
2411void acpigen_write_create_word_field(uint8_t op, size_t byte_offset, const char *name)
2412{
2413 _create_field(CREATE_WORD_OP, op, byte_offset, name);
2414}
2415
2416void acpigen_write_create_dword_field(uint8_t op, size_t byte_offset, const char *name)
2417{
2418 _create_field(CREATE_DWORD_OP, op, byte_offset, name);
2419}
2420
2421void acpigen_write_create_qword_field(uint8_t op, size_t byte_offset, const char *name)
2422{
2423 _create_field(CREATE_QWORD_OP, op, byte_offset, name);
2424}
Jason Gleneskca36aed2020-09-15 21:01:57 -07002425
2426void acpigen_write_pct_package(const acpi_addr_t *perf_ctrl, const acpi_addr_t *perf_sts)
2427{
2428 acpigen_write_name("_PCT");
2429 acpigen_write_package(0x02);
2430 acpigen_write_register_resource(perf_ctrl);
2431 acpigen_write_register_resource(perf_sts);
2432
2433 acpigen_pop_len();
2434}
2435
2436void acpigen_write_xpss_package(const struct acpi_xpss_sw_pstate *pstate_value)
2437{
2438 acpigen_write_package(0x08);
2439 acpigen_write_dword(pstate_value->core_freq);
2440 acpigen_write_dword(pstate_value->power);
2441 acpigen_write_dword(pstate_value->transition_latency);
2442 acpigen_write_dword(pstate_value->bus_master_latency);
2443
2444 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_value, sizeof(uint64_t));
2445 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_value, sizeof(uint64_t));
2446 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_mask, sizeof(uint64_t));
2447 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_mask, sizeof(uint64_t));
2448
2449 acpigen_pop_len();
2450}
2451
2452void acpigen_write_xpss_object(const struct acpi_xpss_sw_pstate *pstate_values, size_t nentries)
2453{
2454 size_t pstate;
2455
2456 acpigen_write_name("XPSS");
2457 acpigen_write_package(nentries);
2458 for (pstate = 0; pstate < nentries; pstate++) {
2459 acpigen_write_xpss_package(pstate_values);
2460 pstate_values++;
2461 }
2462
2463 acpigen_pop_len();
2464}
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002465
2466/* Delay up to wait_ms until provided namestr matches expected value. */
2467void acpigen_write_delay_until_namestr_int(uint32_t wait_ms, const char *name, uint64_t value)
2468{
2469 uint32_t wait_ms_segment = 1;
2470 uint32_t segments = wait_ms;
2471
Sukumar Ghorai9b3c5af2023-12-07 18:33:43 -08002472 /* Sleep in 2ms segments if delay is more than 2ms. */
2473 if (wait_ms > 2) {
2474 wait_ms_segment = 2;
2475 segments = wait_ms / wait_ms_segment;
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002476 }
2477
2478 acpigen_write_store_int_to_op(segments, LOCAL7_OP);
2479 acpigen_emit_byte(WHILE_OP);
2480 acpigen_write_len_f();
2481 acpigen_emit_byte(LGREATER_OP);
2482 acpigen_emit_byte(LOCAL7_OP);
2483 acpigen_emit_byte(ZERO_OP);
2484
2485 /* If name is not provided then just delay in a loop. */
2486 if (name) {
2487 acpigen_write_if_lequal_namestr_int(name, value);
2488 acpigen_emit_byte(BREAK_OP);
2489 acpigen_pop_len(); /* If */
2490 }
2491
2492 acpigen_write_sleep(wait_ms_segment);
2493 acpigen_emit_byte(DECREMENT_OP);
2494 acpigen_emit_byte(LOCAL7_OP);
2495 acpigen_pop_len(); /* While */
Cliff Huangf97598f2023-03-01 14:30:41 -08002496
2497 if (name) {
2498 acpigen_write_if_lequal_op_op(LOCAL7_OP, ZERO_OP);
2499 acpigen_write_debug_sprintf("WARN: Wait loop timeout for variable %s",
2500 name);
2501 acpigen_pop_len(); /* If */
2502 }
Duncan Laurieec2e3e42020-11-03 15:19:08 -08002503}
Arthur Heymans0eb59742023-04-25 16:23:37 +02002504
2505void acpigen_ssdt_override_sleep_states(bool enable_s1, bool enable_s2, bool enable_s3,
2506 bool enable_s4)
2507{
2508 assert(!(enable_s1 && CONFIG(ACPI_S1_NOT_SUPPORTED)));
2509 assert(!(enable_s3 && !CONFIG(HAVE_ACPI_RESUME)));
2510 assert(!(enable_s4 && CONFIG(DISABLE_ACPI_HIBERNATE)));
2511
2512 acpigen_write_scope("\\");
2513 uint32_t sleep_enable = (enable_s1 << 0) | (enable_s2 << 1)
2514 | (enable_s3 << 2) | (enable_s4 << 3);
2515 acpigen_write_name_dword("OSFG", sleep_enable);
2516 acpigen_pop_len();
2517}