blob: ee7c90cf01afe35067e5424f7c52601e395b439a [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
Paul Menzel0f4c0e22013-02-22 12:33:08 +01006/*
Timothy Pearson83abd812015-06-08 19:35:06 -05007 * If you need to change this, change acpigen_write_len_f and
Vladimir Serbinenko8104da72014-11-09 03:33:51 +01008 * acpigen_pop_len
Paul Menzel0f4c0e22013-02-22 12:33:08 +01009 */
Rudolf Marek293b5f52009-02-01 18:35:15 +000010
Timothy Pearson83abd812015-06-08 19:35:06 -050011#define ACPIGEN_MAXLEN 0xfffff
Rudolf Marek293b5f52009-02-01 18:35:15 +000012
Duncan Laurie3829f232016-05-09 11:08:46 -070013#include <lib.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000014#include <string.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -070015#include <acpi/acpigen.h>
Elyes HAOUAScd4fe0f2019-03-29 17:12:15 +010016#include <assert.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000017#include <console/console.h>
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +000018#include <device/device.h>
Furquan Shaikh1a829232020-04-23 11:11:05 -070019#include <device/pci_def.h>
20#include <device/pci_type.h>
Duncan Laurie08a942f2020-04-29 12:13:14 -070021#include <device/soundwire.h>
Rudolf Marek293b5f52009-02-01 18:35:15 +000022
23static char *gencurrent;
24
25char *len_stack[ACPIGEN_LENSTACK_SIZE];
26int ltop = 0;
27
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +010028void acpigen_write_len_f(void)
Rudolf Marek293b5f52009-02-01 18:35:15 +000029{
30 ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1))
Paul Menzel0f4c0e22013-02-22 12:33:08 +010031 len_stack[ltop++] = gencurrent;
Rudolf Marek293b5f52009-02-01 18:35:15 +000032 acpigen_emit_byte(0);
33 acpigen_emit_byte(0);
Timothy Pearson83abd812015-06-08 19:35:06 -050034 acpigen_emit_byte(0);
Rudolf Marek293b5f52009-02-01 18:35:15 +000035}
36
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010037void acpigen_pop_len(void)
38{
39 int len;
40 ASSERT(ltop > 0)
41 char *p = len_stack[--ltop];
42 len = gencurrent - p;
43 ASSERT(len <= ACPIGEN_MAXLEN)
Timothy Pearson83abd812015-06-08 19:35:06 -050044 /* generate store length for 0xfffff max */
45 p[0] = (0x80 | (len & 0xf));
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010046 p[1] = (len >> 4 & 0xff);
Timothy Pearson83abd812015-06-08 19:35:06 -050047 p[2] = (len >> 12 & 0xff);
Vladimir Serbinenko430363a2014-11-02 21:51:22 +010048
49}
50
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000051void acpigen_set_current(char *curr)
52{
53 gencurrent = curr;
Rudolf Marek293b5f52009-02-01 18:35:15 +000054}
55
Stefan Reinauerf96c2d92009-04-22 16:23:47 +000056char *acpigen_get_current(void)
57{
58 return gencurrent;
Rudolf Marek293b5f52009-02-01 18:35:15 +000059}
60
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +010061void acpigen_emit_byte(unsigned char b)
Rudolf Marek293b5f52009-02-01 18:35:15 +000062{
63 (*gencurrent++) = b;
Rudolf Marek293b5f52009-02-01 18:35:15 +000064}
65
Furquan Shaikhe4e9b942016-10-20 23:09:05 -070066void acpigen_emit_ext_op(uint8_t op)
67{
68 acpigen_emit_byte(EXT_OP_PREFIX);
69 acpigen_emit_byte(op);
70}
71
Duncan Laurie9ccae752016-05-09 07:43:19 -070072void acpigen_emit_word(unsigned int data)
73{
74 acpigen_emit_byte(data & 0xff);
75 acpigen_emit_byte((data >> 8) & 0xff);
76}
77
78void acpigen_emit_dword(unsigned int data)
79{
80 acpigen_emit_byte(data & 0xff);
81 acpigen_emit_byte((data >> 8) & 0xff);
82 acpigen_emit_byte((data >> 16) & 0xff);
83 acpigen_emit_byte((data >> 24) & 0xff);
84}
85
Duncan Laurie85d80272016-07-02 19:53:54 -070086char *acpigen_write_package(int nr_el)
Rudolf Marek293b5f52009-02-01 18:35:15 +000087{
Duncan Laurie85d80272016-07-02 19:53:54 -070088 char *p;
Furquan Shaikhe4e9b942016-10-20 23:09:05 -070089 acpigen_emit_byte(PACKAGE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +010090 acpigen_write_len_f();
Duncan Laurie85d80272016-07-02 19:53:54 -070091 p = acpigen_get_current();
Rudolf Marek293b5f52009-02-01 18:35:15 +000092 acpigen_emit_byte(nr_el);
Duncan Laurie85d80272016-07-02 19:53:54 -070093 return p;
Rudolf Marek293b5f52009-02-01 18:35:15 +000094}
95
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +010096void acpigen_write_byte(unsigned int data)
Rudolf Marek293b5f52009-02-01 18:35:15 +000097{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -070098 acpigen_emit_byte(BYTE_PREFIX);
Rudolf Marek293b5f52009-02-01 18:35:15 +000099 acpigen_emit_byte(data & 0xff);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000100}
101
Duncan Laurie9ccae752016-05-09 07:43:19 -0700102void acpigen_write_word(unsigned int data)
103{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700104 acpigen_emit_byte(WORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700105 acpigen_emit_word(data);
106}
107
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100108void acpigen_write_dword(unsigned int data)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000109{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700110 acpigen_emit_byte(DWORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700111 acpigen_emit_dword(data);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000112}
113
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100114void acpigen_write_qword(uint64_t data)
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000115{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700116 acpigen_emit_byte(QWORD_PREFIX);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700117 acpigen_emit_dword(data & 0xffffffff);
118 acpigen_emit_dword((data >> 32) & 0xffffffff);
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000119}
120
Duncan Laurief7c38762016-05-09 08:20:38 -0700121void acpigen_write_zero(void)
122{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700123 acpigen_emit_byte(ZERO_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700124}
125
126void acpigen_write_one(void)
127{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700128 acpigen_emit_byte(ONE_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700129}
130
131void acpigen_write_ones(void)
132{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700133 acpigen_emit_byte(ONES_OP);
Duncan Laurief7c38762016-05-09 08:20:38 -0700134}
135
136void acpigen_write_integer(uint64_t data)
137{
138 if (data == 0)
139 acpigen_write_zero();
140 else if (data == 1)
141 acpigen_write_one();
142 else if (data <= 0xff)
143 acpigen_write_byte((unsigned char)data);
144 else if (data <= 0xffff)
145 acpigen_write_word((unsigned int)data);
146 else if (data <= 0xffffffff)
147 acpigen_write_dword((unsigned int)data);
148 else
149 acpigen_write_qword(data);
150}
151
152void acpigen_write_name_zero(const char *name)
153{
154 acpigen_write_name(name);
155 acpigen_write_one();
156}
157
158void acpigen_write_name_one(const char *name)
159{
160 acpigen_write_name(name);
161 acpigen_write_zero();
162}
163
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100164void acpigen_write_name_byte(const char *name, uint8_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000165{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100166 acpigen_write_name(name);
167 acpigen_write_byte(val);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000168}
169
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100170void acpigen_write_name_dword(const char *name, uint32_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000171{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100172 acpigen_write_name(name);
173 acpigen_write_dword(val);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000174}
175
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100176void acpigen_write_name_qword(const char *name, uint64_t val)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000177{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100178 acpigen_write_name(name);
179 acpigen_write_qword(val);
Carl-Daniel Hailfingerd58671c2009-02-17 21:38:51 +0000180}
181
Duncan Laurief7c38762016-05-09 08:20:38 -0700182void acpigen_write_name_integer(const char *name, uint64_t val)
183{
184 acpigen_write_name(name);
185 acpigen_write_integer(val);
186}
187
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700188void acpigen_write_name_string(const char *name, const char *string)
189{
190 acpigen_write_name(name);
191 acpigen_write_string(string);
192}
193
Patrick Rudolph389c8272019-12-17 13:54:41 +0100194void acpigen_write_name_unicode(const char *name, const char *string)
195{
196 const size_t len = strlen(string) + 1;
197 acpigen_write_name(name);
198 acpigen_emit_byte(BUFFER_OP);
199 acpigen_write_len_f();
200 acpigen_write_integer(len);
201 for (size_t i = 0; i < len; i++) {
202 const char c = string[i];
203 /* Simple ASCII to UTF-16 conversion, replace non ASCII characters */
204 acpigen_emit_word(c >= 0 ? c : '?');
205 }
206 acpigen_pop_len();
207}
208
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100209void acpigen_emit_stream(const char *data, int size)
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000210{
Rudolf Marek293b5f52009-02-01 18:35:15 +0000211 int i;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700212 for (i = 0; i < size; i++)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000213 acpigen_emit_byte(data[i]);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000214}
215
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700216void acpigen_emit_string(const char *string)
217{
Jonathan Neuschäfer0ba307f2016-05-17 17:40:09 +0200218 acpigen_emit_stream(string, string ? strlen(string) : 0);
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700219 acpigen_emit_byte('\0'); /* NUL */
220}
221
222void acpigen_write_string(const char *string)
223{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700224 acpigen_emit_byte(STRING_PREFIX);
Duncan Laurie56b69aa2016-05-09 08:17:02 -0700225 acpigen_emit_string(string);
226}
227
Duncan Laurie37319032016-05-26 12:47:05 -0700228void acpigen_write_coreboot_hid(enum coreboot_acpi_ids id)
229{
Joel Kitching3ab36b842018-03-08 12:09:32 +0800230 char hid[9]; /* BOOTxxxx */
Duncan Laurie37319032016-05-26 12:47:05 -0700231
Duncan Laurie02fdb3e2016-09-22 14:08:33 -0700232 snprintf(hid, sizeof(hid), "%.4s%04X", COREBOOT_ACPI_ID, id);
Duncan Laurie37319032016-05-26 12:47:05 -0700233 acpigen_write_name_string("_HID", hid);
234}
235
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100236/*
237 * The naming conventions for ACPI namespace names are a bit tricky as
Martin Roth0cd338e2016-07-29 14:07:30 -0600238 * each element has to be 4 chars wide ("All names are a fixed 32 bits.")
239 * and "By convention, when an ASL compiler pads a name shorter than 4
240 * characters, it is done so with trailing underscores ('_')".
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100241 *
242 * Check sections 5.3, 18.2.2 and 18.4 of ACPI spec 3.0 for details.
243 */
Rudolf Marek3310d752009-06-21 20:26:13 +0000244
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700245static void acpigen_emit_simple_namestring(const char *name)
246{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100247 int i;
Rudolf Marek3310d752009-06-21 20:26:13 +0000248 char ud[] = "____";
249 for (i = 0; i < 4; i++) {
250 if ((name[i] == '\0') || (name[i] == '.')) {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100251 acpigen_emit_stream(ud, 4 - i);
Rudolf Marek3310d752009-06-21 20:26:13 +0000252 break;
Rudolf Marek3310d752009-06-21 20:26:13 +0000253 }
Lee Leahy0b5678f2017-03-16 16:01:40 -0700254 acpigen_emit_byte(name[i]);
Rudolf Marek3310d752009-06-21 20:26:13 +0000255 }
Rudolf Marek3310d752009-06-21 20:26:13 +0000256}
257
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700258static void acpigen_emit_double_namestring(const char *name, int dotpos)
259{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700260 acpigen_emit_byte(DUAL_NAME_PREFIX);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100261 acpigen_emit_simple_namestring(name);
262 acpigen_emit_simple_namestring(&name[dotpos + 1]);
Rudolf Marek3310d752009-06-21 20:26:13 +0000263}
264
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700265static void acpigen_emit_multi_namestring(const char *name)
266{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100267 int count = 0;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000268 unsigned char *pathlen;
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700269 acpigen_emit_byte(MULTI_NAME_PREFIX);
270 acpigen_emit_byte(ZERO_OP);
Rudolf Marek3310d752009-06-21 20:26:13 +0000271 pathlen = ((unsigned char *) acpigen_get_current()) - 1;
272
273 while (name[0] != '\0') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100274 acpigen_emit_simple_namestring(name);
Rudolf Marek3310d752009-06-21 20:26:13 +0000275 /* find end or next entity */
276 while ((name[0] != '.') && (name[0] != '\0'))
277 name++;
278 /* forward to next */
279 if (name[0] == '.')
280 name++;
281 count++;
282 }
283
284 pathlen[0] = count;
Rudolf Marek3310d752009-06-21 20:26:13 +0000285}
286
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700287void acpigen_emit_namestring(const char *namepath)
288{
Rudolf Marek3310d752009-06-21 20:26:13 +0000289 int dotcount = 0, i;
Myles Watson3fe6b702009-10-09 20:13:43 +0000290 int dotpos = 0;
Rudolf Marek3310d752009-06-21 20:26:13 +0000291
Ronald G. Minnichbe738eb2013-03-07 11:05:28 -0600292 /* We can start with a '\'. */
Rudolf Marek3310d752009-06-21 20:26:13 +0000293 if (namepath[0] == '\\') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100294 acpigen_emit_byte('\\');
Rudolf Marek3310d752009-06-21 20:26:13 +0000295 namepath++;
296 }
297
Ronald G. Minnichbe738eb2013-03-07 11:05:28 -0600298 /* And there can be any number of '^' */
Rudolf Marek3310d752009-06-21 20:26:13 +0000299 while (namepath[0] == '^') {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100300 acpigen_emit_byte('^');
Rudolf Marek3310d752009-06-21 20:26:13 +0000301 namepath++;
302 }
303
Vladimir Serbinenkod942ed92014-08-30 20:44:37 +0200304 /* If we have only \\ or only ^...^. Then we need to put a null
305 name (0x00). */
Elyes HAOUASdbf30672016-08-21 17:37:15 +0200306 if (namepath[0] == '\0') {
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700307 acpigen_emit_byte(ZERO_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100308 return;
Vladimir Serbinenkod942ed92014-08-30 20:44:37 +0200309 }
Rudolf Marek3310d752009-06-21 20:26:13 +0000310
311 i = 0;
312 while (namepath[i] != '\0') {
313 if (namepath[i] == '.') {
314 dotcount++;
315 dotpos = i;
316 }
317 i++;
318 }
319
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700320 if (dotcount == 0)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100321 acpigen_emit_simple_namestring(namepath);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700322 else if (dotcount == 1)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100323 acpigen_emit_double_namestring(namepath, dotpos);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700324 else
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100325 acpigen_emit_multi_namestring(namepath);
Rudolf Marek3310d752009-06-21 20:26:13 +0000326}
327
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100328void acpigen_write_name(const char *name)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000329{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700330 acpigen_emit_byte(NAME_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100331 acpigen_emit_namestring(name);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000332}
333
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100334void acpigen_write_scope(const char *name)
Rudolf Marek293b5f52009-02-01 18:35:15 +0000335{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700336 acpigen_emit_byte(SCOPE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100337 acpigen_write_len_f();
338 acpigen_emit_namestring(name);
Rudolf Marek293b5f52009-02-01 18:35:15 +0000339}
Rudolf Marekf997b552009-02-14 15:40:23 +0000340
Duncan Laurie2fe74712020-06-01 17:36:56 -0700341void acpigen_get_package_op_element(uint8_t package_op, unsigned int element, uint8_t dest_op)
342{
343 /* <dest_op> = DeRefOf (<package_op>[<element]) */
344 acpigen_write_store();
345 acpigen_emit_byte(DEREF_OP);
346 acpigen_emit_byte(INDEX_OP);
347 acpigen_emit_byte(package_op);
348 acpigen_write_integer(element);
349 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
350 acpigen_emit_byte(dest_op);
351}
352
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100353void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
Rudolf Marekf997b552009-02-14 15:40:23 +0000354{
355/*
Christian Walterbe3979c2019-12-18 15:07:59 +0100356 Processor (\_SB.CPcpuindex, cpuindex, pblock_addr, pblock_len)
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200357 {
Rudolf Marekf997b552009-02-14 15:40:23 +0000358*/
359 char pscope[16];
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700360 acpigen_emit_ext_op(PROCESSOR_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100361 acpigen_write_len_f();
Rudolf Marekf997b552009-02-14 15:40:23 +0000362
Elyes HAOUAS7d87e762016-10-03 22:11:07 +0200363 snprintf(pscope, sizeof(pscope),
Marc Jones7a2d4ea2017-08-25 18:54:23 -0600364 CONFIG_ACPI_CPU_STRING, (unsigned int) cpuindex);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100365 acpigen_emit_namestring(pscope);
Rudolf Marekf997b552009-02-14 15:40:23 +0000366 acpigen_emit_byte(cpuindex);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700367 acpigen_emit_dword(pblock_addr);
Rudolf Marekf997b552009-02-14 15:40:23 +0000368 acpigen_emit_byte(pblock_len);
Rudolf Marekf997b552009-02-14 15:40:23 +0000369}
370
Nico Huber4d211ac2017-09-01 21:14:36 +0200371void acpigen_write_processor_package(const char *const name,
372 const unsigned int first_core,
373 const unsigned int core_count)
374{
375 unsigned int i;
376 char pscope[16];
377
378 acpigen_write_name(name);
379 acpigen_write_package(core_count);
380 for (i = first_core; i < first_core + core_count; ++i) {
381 snprintf(pscope, sizeof(pscope), CONFIG_ACPI_CPU_STRING, i);
382 acpigen_emit_namestring(pscope);
383 }
384 acpigen_pop_len();
385}
386
Arthur Heymans8f055272018-11-28 13:18:57 +0100387/* Method to notify all CPU cores */
388void acpigen_write_processor_cnot(const unsigned int number_of_cores)
389{
390 int core_id;
391
Christian Walterbe3979c2019-12-18 15:07:59 +0100392 acpigen_write_method("\\_SB.CNOT", 1);
Arthur Heymans8f055272018-11-28 13:18:57 +0100393 for (core_id = 0; core_id < number_of_cores; core_id++) {
394 char buffer[DEVICE_PATH_MAX];
395 snprintf(buffer, sizeof(buffer), CONFIG_ACPI_CPU_STRING,
396 core_id);
397 acpigen_emit_byte(NOTIFY_OP);
398 acpigen_emit_namestring(buffer);
399 acpigen_emit_byte(ARG0_OP);
400 }
401 acpigen_pop_len();
402}
403
Naresh G Solanki8535c662016-10-25 00:51:24 +0530404/*
405 * Generate ACPI AML code for OperationRegion
406 * Arg0: Pointer to struct opregion opreg = OPREGION(rname, space, offset, len)
407 * where rname is region name, space is region space, offset is region offset &
408 * len is region length.
409 * OperationRegion(regionname, regionspace, regionoffset, regionlength)
410 */
411void acpigen_write_opregion(struct opregion *opreg)
412{
413 /* OpregionOp */
414 acpigen_emit_ext_op(OPREGION_OP);
415 /* NameString 4 chars only */
416 acpigen_emit_simple_namestring(opreg->name);
417 /* RegionSpace */
418 acpigen_emit_byte(opreg->regionspace);
419 /* RegionOffset & RegionLen, it can be byte word or double word */
420 acpigen_write_integer(opreg->regionoffset);
421 acpigen_write_integer(opreg->regionlen);
422}
423
Patrick Rudolph32bae492019-08-08 12:47:30 +0200424/*
425 * Generate ACPI AML code for Mutex
426 * Arg0: Pointer to name of mutex
427 * Arg1: Initial value of mutex
428 */
429void acpigen_write_mutex(const char *name, const uint8_t flags)
430{
431 /* MutexOp */
432 acpigen_emit_ext_op(MUTEX_OP);
433 /* NameString 4 chars only */
434 acpigen_emit_simple_namestring(name);
435 acpigen_emit_byte(flags);
436}
437
438void acpigen_write_acquire(const char *name, const uint16_t val)
439{
440 /* AcquireOp */
441 acpigen_emit_ext_op(ACQUIRE_OP);
442 /* NameString 4 chars only */
443 acpigen_emit_simple_namestring(name);
444 acpigen_emit_word(val);
445}
446
447void acpigen_write_release(const char *name)
448{
449 /* ReleaseOp */
450 acpigen_emit_ext_op(RELEASE_OP);
451 /* NameString 4 chars only */
452 acpigen_emit_simple_namestring(name);
453}
454
Patrick Rudolph894977b2017-07-01 16:15:05 +0200455static void acpigen_write_field_length(uint32_t len)
456{
457 uint8_t i, j;
458 uint8_t emit[4];
459
460 i = 1;
461 if (len < 0x40) {
462 emit[0] = len & 0x3F;
463 } else {
464 emit[0] = len & 0xF;
465 len >>= 4;
466 while (len) {
467 emit[i] = len & 0xFF;
468 i++;
469 len >>= 8;
470 }
471 }
472 /* Update bit 7:6 : Number of bytes followed by emit[0] */
473 emit[0] |= (i - 1) << 6;
474
475 for (j = 0; j < i; j++)
476 acpigen_emit_byte(emit[j]);
477}
478
Naresh G Solanki8535c662016-10-25 00:51:24 +0530479static void acpigen_write_field_offset(uint32_t offset,
480 uint32_t current_bit_pos)
481{
482 uint32_t diff_bits;
Naresh G Solanki8535c662016-10-25 00:51:24 +0530483
484 if (offset < current_bit_pos) {
485 printk(BIOS_WARNING, "%s: Cannot move offset backward",
486 __func__);
487 return;
488 }
489
490 diff_bits = offset - current_bit_pos;
491 /* Upper limit */
492 if (diff_bits > 0xFFFFFFF) {
493 printk(BIOS_WARNING, "%s: Offset very large to encode",
494 __func__);
495 return;
496 }
497
Naresh G Solanki8535c662016-10-25 00:51:24 +0530498 acpigen_emit_byte(0);
Patrick Rudolph894977b2017-07-01 16:15:05 +0200499 acpigen_write_field_length(diff_bits);
500}
501
502static void acpigen_write_field_name(const char *name, uint32_t size)
503{
504 acpigen_emit_simple_namestring(name);
505 acpigen_write_field_length(size);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530506}
507
Duncan Laurie095bbf92020-09-30 23:09:29 +0000508static void acpigen_write_field_reserved(uint32_t size)
509{
510 acpigen_emit_byte(0);
511 acpigen_write_field_length(size);
512}
513
Naresh G Solanki8535c662016-10-25 00:51:24 +0530514/*
515 * Generate ACPI AML code for Field
516 * Arg0: region name
517 * Arg1: Pointer to struct fieldlist.
518 * Arg2: no. of entries in Arg1
519 * Arg3: flags which indicate filed access type, lock rule & update rule.
520 * Example with fieldlist
521 * struct fieldlist l[] = {
522 * FIELDLIST_OFFSET(0x84),
523 * FIELDLIST_NAMESTR("PMCS", 2),
Duncan Laurie095bbf92020-09-30 23:09:29 +0000524 * FIELDLIST_RESERVED(6),
Naresh G Solanki8535c662016-10-25 00:51:24 +0530525 * };
Elyes HAOUASa342f392018-10-17 10:56:26 +0200526 * acpigen_write_field("UART", l, ARRAY_SIZE(l), FIELD_ANYACC | FIELD_NOLOCK |
Naresh G Solanki8535c662016-10-25 00:51:24 +0530527 * FIELD_PRESERVE);
528 * Output:
529 * Field (UART, AnyAcc, NoLock, Preserve)
530 * {
531 * Offset (0x84),
Duncan Laurie095bbf92020-09-30 23:09:29 +0000532 * PMCS, 2,
533 * , 6,
Naresh G Solanki8535c662016-10-25 00:51:24 +0530534 * }
535 */
Furquan Shaikhf9392992020-04-27 23:18:12 -0700536void acpigen_write_field(const char *name, const struct fieldlist *l, size_t count,
Naresh G Solanki8535c662016-10-25 00:51:24 +0530537 uint8_t flags)
538{
539 uint16_t i;
540 uint32_t current_bit_pos = 0;
541
542 /* FieldOp */
543 acpigen_emit_ext_op(FIELD_OP);
544 /* Package Length */
545 acpigen_write_len_f();
546 /* NameString 4 chars only */
547 acpigen_emit_simple_namestring(name);
548 /* Field Flag */
549 acpigen_emit_byte(flags);
550
551 for (i = 0; i < count; i++) {
552 switch (l[i].type) {
553 case NAME_STRING:
Patrick Rudolph894977b2017-07-01 16:15:05 +0200554 acpigen_write_field_name(l[i].name, l[i].bits);
Naresh G Solanki8535c662016-10-25 00:51:24 +0530555 current_bit_pos += l[i].bits;
556 break;
Duncan Laurie095bbf92020-09-30 23:09:29 +0000557 case RESERVED:
558 acpigen_write_field_reserved(l[i].bits);
559 current_bit_pos += l[i].bits;
560 break;
Naresh G Solanki8535c662016-10-25 00:51:24 +0530561 case OFFSET:
562 acpigen_write_field_offset(l[i].bits, current_bit_pos);
563 current_bit_pos = l[i].bits;
564 break;
565 default:
566 printk(BIOS_ERR, "%s: Invalid field type 0x%X\n"
567 , __func__, l[i].type);
568 break;
569 }
570 }
571 acpigen_pop_len();
572}
573
Patrick Rudolph34846ad2019-05-22 11:59:23 +0200574/*
575 * Generate ACPI AML code for IndexField
576 * Arg0: region name
577 * Arg1: Pointer to struct fieldlist.
578 * Arg2: no. of entries in Arg1
579 * Arg3: flags which indicate filed access type, lock rule & update rule.
580 * Example with fieldlist
581 * struct fieldlist l[] = {
582 * FIELDLIST_OFFSET(0x84),
583 * FIELDLIST_NAMESTR("PMCS", 2),
584 * };
585 * acpigen_write_field("IDX", "DATA" l, ARRAY_SIZE(l), FIELD_ANYACC |
586 * FIELD_NOLOCK |
587 * FIELD_PRESERVE);
588 * Output:
589 * IndexField (IDX, DATA, AnyAcc, NoLock, Preserve)
590 * {
591 * Offset (0x84),
592 * PMCS, 2
593 * }
594 */
595void acpigen_write_indexfield(const char *idx, const char *data,
596 struct fieldlist *l, size_t count, uint8_t flags)
597{
598 uint16_t i;
599 uint32_t current_bit_pos = 0;
600
601 /* FieldOp */
602 acpigen_emit_ext_op(INDEX_FIELD_OP);
603 /* Package Length */
604 acpigen_write_len_f();
605 /* NameString 4 chars only */
606 acpigen_emit_simple_namestring(idx);
607 /* NameString 4 chars only */
608 acpigen_emit_simple_namestring(data);
609 /* Field Flag */
610 acpigen_emit_byte(flags);
611
612 for (i = 0; i < count; i++) {
613 switch (l[i].type) {
614 case NAME_STRING:
615 acpigen_write_field_name(l[i].name, l[i].bits);
616 current_bit_pos += l[i].bits;
617 break;
618 case OFFSET:
619 acpigen_write_field_offset(l[i].bits, current_bit_pos);
620 current_bit_pos = l[i].bits;
621 break;
622 default:
623 printk(BIOS_ERR, "%s: Invalid field type 0x%X\n"
624 , __func__, l[i].type);
625 break;
626 }
627 }
628 acpigen_pop_len();
629}
630
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100631void acpigen_write_empty_PCT(void)
Rudolf Marekf997b552009-02-14 15:40:23 +0000632{
633/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200634 Name (_PCT, Package (0x02)
635 {
636 ResourceTemplate ()
637 {
638 Register (FFixedHW,
639 0x00, // Bit Width
640 0x00, // Bit Offset
641 0x0000000000000000, // Address
642 ,)
643 },
Rudolf Marekf997b552009-02-14 15:40:23 +0000644
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200645 ResourceTemplate ()
646 {
647 Register (FFixedHW,
648 0x00, // Bit Width
649 0x00, // Bit Offset
650 0x0000000000000000, // Address
651 ,)
652 }
653 })
Rudolf Marekf997b552009-02-14 15:40:23 +0000654*/
655 static char stream[] = {
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700656 /* 00000030 "0._PCT.," */
657 0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C,
658 /* 00000038 "........" */
659 0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00,
660 /* 00000040 "........" */
661 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662 /* 00000048 "....y..." */
663 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14,
664 /* 00000050 "........" */
665 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00,
666 /* 00000058 "........" */
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Rudolf Marekf997b552009-02-14 15:40:23 +0000668 0x00, 0x79, 0x00
669 };
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100670 acpigen_emit_stream(stream, ARRAY_SIZE(stream));
Rudolf Marekf997b552009-02-14 15:40:23 +0000671}
672
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100673void acpigen_write_empty_PTC(void)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200674{
675/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200676 Name (_PTC, Package (0x02)
677 {
678 ResourceTemplate ()
679 {
680 Register (FFixedHW,
681 0x00, // Bit Width
682 0x00, // Bit Offset
683 0x0000000000000000, // Address
684 ,)
685 },
Stefan Reinauer39205c62012-04-27 21:49:28 +0200686
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200687 ResourceTemplate ()
688 {
689 Register (FFixedHW,
690 0x00, // Bit Width
691 0x00, // Bit Offset
692 0x0000000000000000, // Address
693 ,)
694 }
695 })
Stefan Reinauer39205c62012-04-27 21:49:28 +0200696*/
Stefan Reinauer39205c62012-04-27 21:49:28 +0200697 acpi_addr_t addr = {
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100698 .space_id = ACPI_ADDRESS_SPACE_FIXED,
699 .bit_width = 0,
700 .bit_offset = 0,
Elyes HAOUAS721cb8a2020-06-23 09:13:42 +0200701 .access_size = ACPI_ACCESS_SIZE_UNDEFINED,
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100702 .addrl = 0,
703 .addrh = 0,
Stefan Reinauer39205c62012-04-27 21:49:28 +0200704 };
705
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100706 acpigen_write_name("_PTC");
707 acpigen_write_package(2);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200708
709 /* ControlRegister */
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700710 acpigen_write_register_resource(&addr);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200711
712 /* StatusRegister */
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700713 acpigen_write_register_resource(&addr);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200714
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100715 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200716}
717
Furquan Shaikhfcc7a042016-10-20 23:12:38 -0700718static void __acpigen_write_method(const char *name, uint8_t flags)
Vladimir Serbinenko80fb8ed2014-11-05 10:28:28 +0100719{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700720 acpigen_emit_byte(METHOD_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100721 acpigen_write_len_f();
722 acpigen_emit_namestring(name);
Furquan Shaikhfcc7a042016-10-20 23:12:38 -0700723 acpigen_emit_byte(flags);
724}
725
726/* Method (name, nargs, NotSerialized) */
727void acpigen_write_method(const char *name, int nargs)
728{
729 __acpigen_write_method(name, (nargs & 7));
730}
731
732/* Method (name, nargs, Serialized) */
733void acpigen_write_method_serialized(const char *name, int nargs)
734{
735 __acpigen_write_method(name, (nargs & 7) | (1 << 3));
Vladimir Serbinenko80fb8ed2014-11-05 10:28:28 +0100736}
737
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100738void acpigen_write_device(const char *name)
Vladimir Serbinenko663be6e2014-11-05 21:29:45 +0100739{
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700740 acpigen_emit_ext_op(DEVICE_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100741 acpigen_write_len_f();
742 acpigen_emit_namestring(name);
Vladimir Serbinenko663be6e2014-11-05 21:29:45 +0100743}
744
Duncan Laurieabe2de82016-05-09 11:08:46 -0700745void acpigen_write_STA(uint8_t status)
746{
747 /*
748 * Method (_STA, 0, NotSerialized) { Return (status) }
749 */
750 acpigen_write_method("_STA", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700751 acpigen_emit_byte(RETURN_OP);
Duncan Laurieabe2de82016-05-09 11:08:46 -0700752 acpigen_write_byte(status);
753 acpigen_pop_len();
754}
755
Sugnan Prabhu S4f77f612020-06-10 09:51:02 +0530756void acpigen_write_STA_ext(const char *namestring)
757{
758 /*
759 * Method (_STA, 0, NotSerialized) { Return (ext_val) }
760 */
761 acpigen_write_method("_STA", 0);
762 acpigen_emit_byte(RETURN_OP);
763 acpigen_emit_namestring(namestring);
764 acpigen_pop_len();
765}
766
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100767/*
768 * Generates a func with max supported P-states.
769 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100770void acpigen_write_PPC(u8 nr)
Rudolf Marekf997b552009-02-14 15:40:23 +0000771{
772/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200773 Method (_PPC, 0, NotSerialized)
774 {
775 Return (nr)
776 }
Rudolf Marekf997b552009-02-14 15:40:23 +0000777*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100778 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700779 acpigen_emit_byte(RETURN_OP);
Rudolf Marekf997b552009-02-14 15:40:23 +0000780 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100781 acpigen_write_byte(nr);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100782 acpigen_pop_len();
Rudolf Marekf997b552009-02-14 15:40:23 +0000783}
784
Paul Menzel0f4c0e22013-02-22 12:33:08 +0100785/*
786 * Generates a func with max supported P-states saved
787 * in the variable PPCM.
788 */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100789void acpigen_write_PPC_NVS(void)
Duncan Laurie0eefa002012-07-16 12:11:53 -0700790{
791/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200792 Method (_PPC, 0, NotSerialized)
793 {
794 Return (PPCM)
795 }
Duncan Laurie0eefa002012-07-16 12:11:53 -0700796*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100797 acpigen_write_method("_PPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700798 acpigen_emit_byte(RETURN_OP);
Duncan Laurie0eefa002012-07-16 12:11:53 -0700799 /* arg */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100800 acpigen_emit_namestring("PPCM");
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100801 acpigen_pop_len();
Duncan Laurie0eefa002012-07-16 12:11:53 -0700802}
803
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100804void acpigen_write_TPC(const char *gnvs_tpc_limit)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200805{
806/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200807 // Sample _TPC method
808 Method (_TPC, 0, NotSerialized)
809 {
810 Return (\TLVL)
811 }
812*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100813 acpigen_write_method("_TPC", 0);
Furquan Shaikhe4e9b942016-10-20 23:09:05 -0700814 acpigen_emit_byte(RETURN_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100815 acpigen_emit_namestring(gnvs_tpc_limit);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100816 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200817}
818
Duncan Laurieabe2de82016-05-09 11:08:46 -0700819void acpigen_write_PRW(u32 wake, u32 level)
820{
821 /*
822 * Name (_PRW, Package () { wake, level }
823 */
824 acpigen_write_name("_PRW");
825 acpigen_write_package(2);
826 acpigen_write_integer(wake);
827 acpigen_write_integer(level);
828 acpigen_pop_len();
829}
830
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100831void acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat,
Stefan Reinauerf96c2d92009-04-22 16:23:47 +0000832 u32 busmLat, u32 control, u32 status)
Rudolf Marekf997b552009-02-14 15:40:23 +0000833{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100834 acpigen_write_package(6);
835 acpigen_write_dword(coreFreq);
836 acpigen_write_dword(power);
837 acpigen_write_dword(transLat);
838 acpigen_write_dword(busmLat);
839 acpigen_write_dword(control);
840 acpigen_write_dword(status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100841 acpigen_pop_len();
Stefan Reinauerd4bacf92012-05-02 16:38:47 -0700842
843 printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n",
844 coreFreq, power, control, status);
Rudolf Marekf997b552009-02-14 15:40:23 +0000845}
Patrick Georgidf444bf2009-04-21 20:34:36 +0000846
Jason Gleneskca36aed2020-09-15 21:01:57 -0700847void acpigen_write_pss_object(const struct acpi_sw_pstate *pstate_values, size_t nentries)
848{
849 size_t pstate;
850
851 acpigen_write_name("_PSS");
852 acpigen_write_package(nentries);
853 for (pstate = 0; pstate < nentries; pstate++) {
854 acpigen_write_PSS_package(
855 pstate_values->core_freq, pstate_values->power,
856 pstate_values->transition_latency, pstate_values->bus_master_latency,
857 pstate_values->control_value, pstate_values->status_value);
858 pstate_values++;
859 }
860
861 acpigen_pop_len();
862}
863
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100864void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Patrick Georgidf444bf2009-04-21 20:34:36 +0000865{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100866 acpigen_write_name("_PSD");
867 acpigen_write_package(1);
868 acpigen_write_package(5);
869 acpigen_write_byte(5); // 5 values
870 acpigen_write_byte(0); // revision 0
871 acpigen_write_dword(domain);
872 acpigen_write_dword(coordtype);
873 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100874 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100875 acpigen_pop_len();
Patrick Georgidf444bf2009-04-21 20:34:36 +0000876}
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +0000877
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100878void acpigen_write_CST_package_entry(acpi_cstate_t *cstate)
Sven Schnelle0b86c762011-10-21 21:46:47 +0200879{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100880 acpigen_write_package(4);
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700881 acpigen_write_register_resource(&cstate->resource);
Jason Glenesk201acca2020-09-11 12:36:15 -0700882 acpigen_write_byte(cstate->ctype);
883 acpigen_write_word(cstate->latency);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100884 acpigen_write_dword(cstate->power);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100885 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +0200886}
887
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100888void acpigen_write_CST_package(acpi_cstate_t *cstate, int nentries)
Sven Schnelle0b86c762011-10-21 21:46:47 +0200889{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100890 int i;
891 acpigen_write_name("_CST");
892 acpigen_write_package(nentries+1);
Jason Glenesk201acca2020-09-11 12:36:15 -0700893 acpigen_write_integer(nentries);
Sven Schnelle0b86c762011-10-21 21:46:47 +0200894
895 for (i = 0; i < nentries; i++)
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100896 acpigen_write_CST_package_entry(cstate + i);
Sven Schnelle0b86c762011-10-21 21:46:47 +0200897
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100898 acpigen_pop_len();
Sven Schnelle0b86c762011-10-21 21:46:47 +0200899}
900
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700901void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype,
902 u32 index)
Timothy Pearson83abd812015-06-08 19:35:06 -0500903{
904 acpigen_write_name("_CSD");
905 acpigen_write_package(1);
906 acpigen_write_package(6);
Jason Glenesk201acca2020-09-11 12:36:15 -0700907 acpigen_write_integer(6); // 6 values
Timothy Pearson83abd812015-06-08 19:35:06 -0500908 acpigen_write_byte(0); // revision 0
909 acpigen_write_dword(domain);
910 acpigen_write_dword(coordtype);
911 acpigen_write_dword(numprocs);
912 acpigen_write_dword(index);
913 acpigen_pop_len();
914 acpigen_pop_len();
915}
916
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100917void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200918{
919/*
Elyes HAOUAS6b727872016-09-03 08:28:48 +0200920 Sample _TSS package with 100% and 50% duty cycles
921 Name (_TSS, Package (0x02)
922 {
923 Package(){100, 1000, 0, 0x00, 0)
924 Package(){50, 520, 0, 0x18, 0)
925 })
926*/
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100927 int i;
Stefan Reinauer39205c62012-04-27 21:49:28 +0200928 acpi_tstate_t *tstate = tstate_list;
929
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100930 acpigen_write_name("_TSS");
931 acpigen_write_package(entries);
Stefan Reinauer39205c62012-04-27 21:49:28 +0200932
933 for (i = 0; i < entries; i++) {
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100934 acpigen_write_package(5);
935 acpigen_write_dword(tstate->percent);
936 acpigen_write_dword(tstate->power);
937 acpigen_write_dword(tstate->latency);
938 acpigen_write_dword(tstate->control);
939 acpigen_write_dword(tstate->status);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100940 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200941 tstate++;
Stefan Reinauer39205c62012-04-27 21:49:28 +0200942 }
943
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100944 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200945}
946
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100947void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
Stefan Reinauer39205c62012-04-27 21:49:28 +0200948{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100949 acpigen_write_name("_TSD");
950 acpigen_write_package(1);
951 acpigen_write_package(5);
952 acpigen_write_byte(5); // 5 values
953 acpigen_write_byte(0); // revision 0
954 acpigen_write_dword(domain);
955 acpigen_write_dword(coordtype);
956 acpigen_write_dword(numprocs);
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100957 acpigen_pop_len();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +0100958 acpigen_pop_len();
Stefan Reinauer39205c62012-04-27 21:49:28 +0200959}
960
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100961void acpigen_write_mem32fixed(int readwrite, u32 base, u32 size)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +0000962{
963 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +0200964 * ACPI 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +0000965 * Byte 0:
966 * Bit7 : 1 => big item
967 * Bit6-0: 0000110 (0x6) => 32-bit fixed memory
968 */
969 acpigen_emit_byte(0x86);
970 /* Byte 1+2: length (0x0009) */
971 acpigen_emit_byte(0x09);
972 acpigen_emit_byte(0x00);
973 /* bit1-7 are ignored */
974 acpigen_emit_byte(readwrite ? 0x01 : 0x00);
Duncan Laurie9ccae752016-05-09 07:43:19 -0700975 acpigen_emit_dword(base);
976 acpigen_emit_dword(size);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +0000977}
978
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700979static void acpigen_write_register(const acpi_addr_t *addr)
Sven Schnelle0b86c762011-10-21 21:46:47 +0200980{
Stefan Reinauer4cc8c702012-04-27 21:34:16 +0200981 acpigen_emit_byte(0x82); /* Register Descriptor */
982 acpigen_emit_byte(0x0c); /* Register Length 7:0 */
983 acpigen_emit_byte(0x00); /* Register Length 15:8 */
984 acpigen_emit_byte(addr->space_id); /* Address Space ID */
985 acpigen_emit_byte(addr->bit_width); /* Register Bit Width */
986 acpigen_emit_byte(addr->bit_offset); /* Register Bit Offset */
Elyes HAOUAS8ee161d2019-03-03 12:49:56 +0100987 acpigen_emit_byte(addr->access_size); /* Register Access Size */
Duncan Laurie9ccae752016-05-09 07:43:19 -0700988 acpigen_emit_dword(addr->addrl); /* Register Address Low */
989 acpigen_emit_dword(addr->addrh); /* Register Address High */
Sven Schnelle0b86c762011-10-21 21:46:47 +0200990}
991
Matt Delcoc3f9d7a2018-07-27 14:01:05 -0700992void acpigen_write_register_resource(const acpi_addr_t *addr)
993{
994 acpigen_write_resourcetemplate_header();
995 acpigen_write_register(addr);
996 acpigen_write_resourcetemplate_footer();
997}
998
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +0100999void acpigen_write_irq(u16 mask)
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001000{
1001 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001002 * ACPI 3.0b section 6.4.2.1: IRQ Descriptor
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001003 * Byte 0:
1004 * Bit7 : 0 => small item
1005 * Bit6-3: 0100 (0x4) => IRQ port descriptor
1006 * Bit2-0: 010 (0x2) => 2 Bytes long
1007 */
1008 acpigen_emit_byte(0x22);
1009 acpigen_emit_byte(mask & 0xff);
1010 acpigen_emit_byte((mask >> 8) & 0xff);
Vladimir Serbinenko20ea0402014-02-15 18:57:17 +01001011}
1012
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001013void acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001014{
1015 /*
Elyes HAOUAS2078e752016-08-21 10:41:44 +02001016 * ACPI 4.0 section 6.4.2.6: I/O Port Descriptor
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001017 * Byte 0:
1018 * Bit7 : 0 => small item
1019 * Bit6-3: 1000 (0x8) => I/O port descriptor
1020 * Bit2-0: 111 (0x7) => 7 Bytes long
1021 */
1022 acpigen_emit_byte(0x47);
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001023 /* Does the device decode all 16 or just 10 bits? */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001024 /* bit1-7 are ignored */
1025 acpigen_emit_byte(decode16 ? 0x01 : 0x00);
1026 /* minimum base address the device may be configured for */
1027 acpigen_emit_byte(min & 0xff);
1028 acpigen_emit_byte((min >> 8) & 0xff);
1029 /* maximum base address the device may be configured for */
1030 acpigen_emit_byte(max & 0xff);
1031 acpigen_emit_byte((max >> 8) & 0xff);
1032 /* alignment for min base */
1033 acpigen_emit_byte(align & 0xff);
1034 acpigen_emit_byte(len & 0xff);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001035}
1036
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001037void acpigen_write_resourcetemplate_header(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001038{
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001039 /*
1040 * A ResourceTemplate() is a Buffer() with a
1041 * (Byte|Word|DWord) containing the length, followed by one or more
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001042 * resource items, terminated by the end tag.
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001043 * (small item 0xf, len 1)
1044 */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001045 acpigen_emit_byte(BUFFER_OP);
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001046 acpigen_write_len_f();
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001047 acpigen_emit_byte(WORD_PREFIX);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001048 len_stack[ltop++] = acpigen_get_current();
Nico Huber7d89ce32017-04-14 00:08:18 +02001049 /* Add 2 dummy bytes for the ACPI word (keep aligned with
Elyes HAOUAS6716bab2020-01-09 21:29:25 +01001050 the calculation in acpigen_write_resourcetemplate() below). */
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001051 acpigen_emit_byte(0x00);
1052 acpigen_emit_byte(0x00);
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001053}
1054
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001055void acpigen_write_resourcetemplate_footer(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001056{
1057 char *p = len_stack[--ltop];
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001058 int len;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001059 /*
1060 * end tag (acpi 4.0 Section 6.4.2.8)
1061 * 0x79 <checksum>
1062 * 0x00 is treated as a good checksum according to the spec
1063 * and is what iasl generates.
1064 */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001065 acpigen_emit_byte(0x79);
1066 acpigen_emit_byte(0x00);
1067
Nico Huber7d89ce32017-04-14 00:08:18 +02001068 /* Start counting past the 2-bytes length added in
1069 acpigen_write_resourcetemplate() above. */
1070 len = acpigen_get_current() - (p + 2);
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001071
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001072 /* patch len word */
Vladimir Serbinenko9acc1e82014-11-09 03:37:28 +01001073 p[0] = len & 0xff;
1074 p[1] = (len >> 8) & 0xff;
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001075 /* patch len field */
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001076 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001077}
1078
1079static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev,
1080 struct resource *res)
1081{
1082 acpigen_write_mem32fixed(0, res->base, res->size);
1083}
1084
1085static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev,
1086 struct resource *res)
1087{
1088 resource_t base = res->base;
1089 resource_t size = res->size;
1090 while (size > 0) {
1091 resource_t sz = size > 255 ? 255 : size;
1092 acpigen_write_io16(base, base, 0, sz, 1);
1093 size -= sz;
1094 base += sz;
1095 }
1096}
1097
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001098void acpigen_write_mainboard_resource_template(void)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001099{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001100 acpigen_write_resourcetemplate_header();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001101
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001102 /* Add reserved memory ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001103 search_global_resources(
1104 IORESOURCE_MEM | IORESOURCE_RESERVE,
1105 IORESOURCE_MEM | IORESOURCE_RESERVE,
1106 acpigen_add_mainboard_rsvd_mem32, 0);
1107
Paul Menzel0f4c0e22013-02-22 12:33:08 +01001108 /* Add reserved io ranges. */
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001109 search_global_resources(
1110 IORESOURCE_IO | IORESOURCE_RESERVE,
1111 IORESOURCE_IO | IORESOURCE_RESERVE,
1112 acpigen_add_mainboard_rsvd_io, 0);
1113
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001114 acpigen_write_resourcetemplate_footer();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001115}
1116
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001117void acpigen_write_mainboard_resources(const char *scope, const char *name)
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001118{
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001119 acpigen_write_scope(scope);
1120 acpigen_write_name(name);
1121 acpigen_write_mainboard_resource_template();
Vladimir Serbinenkoa09f4db2014-11-09 03:32:58 +01001122 acpigen_pop_len();
Tobias Diedrich0fe6e9a2010-11-17 16:27:06 +00001123}
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001124
1125static int hex2bin(const char c)
1126{
1127 if (c >= 'A' && c <= 'F')
1128 return c - 'A' + 10;
1129 if (c >= 'a' && c <= 'f')
1130 return c - 'a' + 10;
1131 return c - '0';
1132}
1133
Vladimir Serbinenko9bb5c5c2014-11-09 03:51:32 +01001134void acpigen_emit_eisaid(const char *eisaid)
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001135{
1136 u32 compact = 0;
1137
1138 /* Clamping individual values would be better but
1139 there is a disagreement over what is a valid
1140 EISA id, so accept anything and don't clamp,
1141 parent code should create a valid EISAid.
1142 */
1143 compact |= (eisaid[0] - 'A' + 1) << 26;
1144 compact |= (eisaid[1] - 'A' + 1) << 21;
1145 compact |= (eisaid[2] - 'A' + 1) << 16;
1146 compact |= hex2bin(eisaid[3]) << 12;
1147 compact |= hex2bin(eisaid[4]) << 8;
1148 compact |= hex2bin(eisaid[5]) << 4;
1149 compact |= hex2bin(eisaid[6]);
1150
1151 acpigen_emit_byte(0xc);
1152 acpigen_emit_byte((compact >> 24) & 0xff);
1153 acpigen_emit_byte((compact >> 16) & 0xff);
1154 acpigen_emit_byte((compact >> 8) & 0xff);
1155 acpigen_emit_byte(compact & 0xff);
Vladimir Serbinenko8ecdc9e2014-02-15 18:59:40 +01001156}
Duncan Laurie3829f232016-05-09 11:08:46 -07001157
1158/*
1159 * ToUUID(uuid)
1160 *
1161 * ACPI 6.1 Section 19.6.136 table 19-385 defines a special output
1162 * order for the bytes that make up a UUID Buffer object.
1163 * UUID byte order for input:
1164 * aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
1165 * UUID byte order for output:
1166 * ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp
1167 */
1168#define UUID_LEN 16
1169void acpigen_write_uuid(const char *uuid)
1170{
1171 uint8_t buf[UUID_LEN];
1172 size_t i, order[UUID_LEN] = { 3, 2, 1, 0, 5, 4, 7, 6,
1173 8, 9, 10, 11, 12, 13, 14, 15 };
1174
1175 /* Parse UUID string into bytes */
1176 if (hexstrtobin(uuid, buf, UUID_LEN) < UUID_LEN)
1177 return;
1178
1179 /* BufferOp */
Furquan Shaikhe4e9b942016-10-20 23:09:05 -07001180 acpigen_emit_byte(BUFFER_OP);
Duncan Laurie3829f232016-05-09 11:08:46 -07001181 acpigen_write_len_f();
1182
1183 /* Buffer length in bytes */
1184 acpigen_write_word(UUID_LEN);
1185
1186 /* Output UUID in expected order */
1187 for (i = 0; i < UUID_LEN; i++)
1188 acpigen_emit_byte(buf[order[i]]);
1189
1190 acpigen_pop_len();
1191}
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001192
1193/*
1194 * Name (_PRx, Package(One) { name })
1195 * ...
1196 * PowerResource (name, level, order)
1197 */
1198void acpigen_write_power_res(const char *name, uint8_t level, uint16_t order,
Furquan Shaikhdc782752020-04-30 22:49:39 -07001199 const char * const dev_states[], size_t dev_states_count)
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001200{
Elyes HAOUAScca6e002019-06-26 12:12:00 +02001201 size_t i;
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001202 for (i = 0; i < dev_states_count; i++) {
1203 acpigen_write_name(dev_states[i]);
1204 acpigen_write_package(1);
1205 acpigen_emit_simple_namestring(name);
1206 acpigen_pop_len(); /* Package */
1207 }
1208
1209 acpigen_emit_ext_op(POWER_RES_OP);
1210
1211 acpigen_write_len_f();
1212
1213 acpigen_emit_simple_namestring(name);
1214 acpigen_emit_byte(level);
1215 acpigen_emit_word(order);
1216}
1217
1218/* Sleep (ms) */
1219void acpigen_write_sleep(uint64_t sleep_ms)
1220{
1221 acpigen_emit_ext_op(SLEEP_OP);
1222 acpigen_write_integer(sleep_ms);
1223}
1224
1225void acpigen_write_store(void)
1226{
1227 acpigen_emit_byte(STORE_OP);
1228}
1229
1230/* Store (src, dst) */
1231void acpigen_write_store_ops(uint8_t src, uint8_t dst)
1232{
1233 acpigen_write_store();
1234 acpigen_emit_byte(src);
1235 acpigen_emit_byte(dst);
1236}
1237
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001238/* Store (src, "namestr") */
1239void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst)
1240{
1241 acpigen_write_store();
1242 acpigen_emit_byte(src);
1243 acpigen_emit_namestring(dst);
1244}
1245
Duncan Laurie8e391d32020-09-30 23:17:41 +00001246/* Store (src, "namestr") */
1247void acpigen_write_store_int_to_namestr(uint64_t src, const char *dst)
1248{
1249 acpigen_write_store();
1250 acpigen_write_integer(src);
1251 acpigen_emit_namestring(dst);
1252}
1253
1254/* Store (src, dst) */
1255void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
1256{
1257 acpigen_write_store();
1258 acpigen_write_integer(src);
1259 acpigen_emit_byte(dst);
1260}
1261
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001262/* Or (arg1, arg2, res) */
1263void acpigen_write_or(uint8_t arg1, uint8_t arg2, uint8_t res)
1264{
1265 acpigen_emit_byte(OR_OP);
1266 acpigen_emit_byte(arg1);
1267 acpigen_emit_byte(arg2);
1268 acpigen_emit_byte(res);
1269}
1270
Rajat Jain310623b2020-02-26 11:02:53 -08001271/* Xor (arg1, arg2, res) */
1272void acpigen_write_xor(uint8_t arg1, uint8_t arg2, uint8_t res)
1273{
1274 acpigen_emit_byte(XOR_OP);
1275 acpigen_emit_byte(arg1);
1276 acpigen_emit_byte(arg2);
1277 acpigen_emit_byte(res);
1278}
1279
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001280/* And (arg1, arg2, res) */
1281void acpigen_write_and(uint8_t arg1, uint8_t arg2, uint8_t res)
1282{
1283 acpigen_emit_byte(AND_OP);
1284 acpigen_emit_byte(arg1);
1285 acpigen_emit_byte(arg2);
1286 acpigen_emit_byte(res);
1287}
1288
1289/* Not (arg, res) */
1290void acpigen_write_not(uint8_t arg, uint8_t res)
1291{
1292 acpigen_emit_byte(NOT_OP);
1293 acpigen_emit_byte(arg);
1294 acpigen_emit_byte(res);
1295}
1296
1297/* Store (str, DEBUG) */
1298void acpigen_write_debug_string(const char *str)
1299{
1300 acpigen_write_store();
1301 acpigen_write_string(str);
1302 acpigen_emit_ext_op(DEBUG_OP);
1303}
1304
1305/* Store (val, DEBUG) */
1306void acpigen_write_debug_integer(uint64_t val)
1307{
1308 acpigen_write_store();
1309 acpigen_write_integer(val);
1310 acpigen_emit_ext_op(DEBUG_OP);
1311}
1312
1313/* Store (op, DEBUG) */
1314void acpigen_write_debug_op(uint8_t op)
1315{
1316 acpigen_write_store();
1317 acpigen_emit_byte(op);
1318 acpigen_emit_ext_op(DEBUG_OP);
1319}
1320
1321void acpigen_write_if(void)
1322{
1323 acpigen_emit_byte(IF_OP);
1324 acpigen_write_len_f();
1325}
1326
1327/* If (And (arg1, arg2)) */
1328void acpigen_write_if_and(uint8_t arg1, uint8_t arg2)
1329{
1330 acpigen_write_if();
1331 acpigen_emit_byte(AND_OP);
1332 acpigen_emit_byte(arg1);
1333 acpigen_emit_byte(arg2);
1334}
1335
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001336/*
Duncan Laurie2fe74712020-06-01 17:36:56 -07001337 * Generates ACPI code for checking if operand1 and operand2 are equal.
1338 * Both operand1 and operand2 are ACPI ops.
1339 *
1340 * If (Lequal (op,1 op2))
1341 */
1342void acpigen_write_if_lequal_op_op(uint8_t op1, uint8_t op2)
1343{
1344 acpigen_write_if();
1345 acpigen_emit_byte(LEQUAL_OP);
1346 acpigen_emit_byte(op1);
1347 acpigen_emit_byte(op2);
1348}
1349
1350/*
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001351 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1352 * operand1 is ACPI op and operand2 is an integer.
1353 *
1354 * If (Lequal (op, val))
1355 */
1356void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001357{
1358 acpigen_write_if();
1359 acpigen_emit_byte(LEQUAL_OP);
Furquan Shaikh1fc6bb92016-11-14 14:16:26 -08001360 acpigen_emit_byte(op);
1361 acpigen_write_integer(val);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001362}
1363
Furquan Shaikh2c213d32020-04-27 23:06:30 -07001364/*
1365 * Generates ACPI code for checking if operand1 and operand2 are equal, where,
1366 * operand1 is namestring and operand2 is an integer.
1367 *
1368 * If (Lequal ("namestr", val))
1369 */
1370void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val)
1371{
1372 acpigen_write_if();
1373 acpigen_emit_byte(LEQUAL_OP);
1374 acpigen_emit_namestring(namestr);
1375 acpigen_write_integer(val);
1376}
1377
Furquan Shaikhfcc7a042016-10-20 23:12:38 -07001378void acpigen_write_else(void)
1379{
1380 acpigen_emit_byte(ELSE_OP);
1381 acpigen_write_len_f();
1382}
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001383
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001384void acpigen_write_to_buffer(uint8_t src, uint8_t dst)
1385{
1386 acpigen_emit_byte(TO_BUFFER_OP);
1387 acpigen_emit_byte(src);
1388 acpigen_emit_byte(dst);
1389}
1390
1391void acpigen_write_to_integer(uint8_t src, uint8_t dst)
1392{
1393 acpigen_emit_byte(TO_INTEGER_OP);
1394 acpigen_emit_byte(src);
1395 acpigen_emit_byte(dst);
1396}
1397
Aaron Durbin80bc0912020-08-19 23:17:42 -06001398void acpigen_write_to_integer_from_namestring(const char *source, uint8_t dst_op)
1399{
1400 acpigen_emit_byte(TO_INTEGER_OP);
1401 acpigen_emit_namestring(source);
1402 acpigen_emit_byte(dst_op);
1403}
1404
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301405void acpigen_write_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001406{
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301407 size_t i;
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001408
1409 acpigen_emit_byte(BUFFER_OP);
1410 acpigen_write_len_f();
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301411 acpigen_write_integer(size);
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001412
1413 for (i = 0; i < size; i++)
1414 acpigen_emit_byte(arr[i]);
1415
1416 acpigen_pop_len();
1417}
1418
Rizwan Qureshiaca4c942017-03-06 21:50:26 +05301419void acpigen_write_return_byte_buffer(uint8_t *arr, size_t size)
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001420{
1421 acpigen_emit_byte(RETURN_OP);
1422 acpigen_write_byte_buffer(arr, size);
1423}
1424
1425void acpigen_write_return_singleton_buffer(uint8_t arg)
1426{
1427 acpigen_write_return_byte_buffer(&arg, 1);
1428}
1429
Duncan Laurie2fe74712020-06-01 17:36:56 -07001430void acpigen_write_return_op(uint8_t arg)
1431{
1432 acpigen_emit_byte(RETURN_OP);
1433 acpigen_emit_byte(arg);
1434}
1435
Furquan Shaikh9b39adb2016-10-21 16:21:07 -07001436void acpigen_write_return_byte(uint8_t arg)
1437{
1438 acpigen_emit_byte(RETURN_OP);
1439 acpigen_write_byte(arg);
1440}
1441
Naresh G Solanki05abe432016-11-17 00:16:29 +05301442void acpigen_write_return_integer(uint64_t arg)
1443{
1444 acpigen_emit_byte(RETURN_OP);
1445 acpigen_write_integer(arg);
1446}
1447
1448void acpigen_write_return_string(const char *arg)
1449{
1450 acpigen_emit_byte(RETURN_OP);
1451 acpigen_write_string(arg);
1452}
1453
Duncan Lauriebeb2af42018-05-07 14:26:59 -07001454void acpigen_write_upc(enum acpi_upc_type type)
1455{
1456 acpigen_write_name("_UPC");
1457 acpigen_write_package(4);
1458 /* Connectable */
1459 acpigen_write_byte(type == UPC_TYPE_UNUSED ? 0 : 0xff);
1460 /* Type */
1461 acpigen_write_byte(type);
1462 /* Reserved0 */
1463 acpigen_write_zero();
1464 /* Reserved1 */
1465 acpigen_write_zero();
1466 acpigen_pop_len();
1467}
1468
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001469void acpigen_write_pld(const struct acpi_pld *pld)
1470{
1471 uint8_t buf[20];
1472
1473 if (acpi_pld_to_buffer(pld, buf, ARRAY_SIZE(buf)) < 0)
1474 return;
1475
1476 acpigen_write_name("_PLD");
Matt Delco4929f432019-01-30 11:40:44 -08001477 acpigen_write_package(1);
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001478 acpigen_write_byte_buffer(buf, ARRAY_SIZE(buf));
Matt Delco4929f432019-01-30 11:40:44 -08001479 acpigen_pop_len();
Duncan Laurie3e7197a2018-05-07 14:18:13 -07001480}
1481
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301482void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *),
1483 size_t count, void *arg)
1484{
1485 struct dsm_uuid id = DSM_UUID(uuid, callbacks, count, arg);
1486 acpigen_write_dsm_uuid_arr(&id, 1);
1487}
1488
1489static void acpigen_write_dsm_uuid(struct dsm_uuid *id)
1490{
1491 size_t i;
1492
1493 /* If (LEqual (Local0, ToUUID(uuid))) */
1494 acpigen_write_if();
1495 acpigen_emit_byte(LEQUAL_OP);
1496 acpigen_emit_byte(LOCAL0_OP);
1497 acpigen_write_uuid(id->uuid);
1498
1499 /* ToInteger (Arg2, Local1) */
1500 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
1501
1502 for (i = 0; i < id->count; i++) {
1503 /* If (LEqual (Local1, i)) */
1504 acpigen_write_if_lequal_op_int(LOCAL1_OP, i);
1505
1506 /* Callback to write if handler. */
1507 if (id->callbacks[i])
1508 id->callbacks[i](id->arg);
1509
1510 acpigen_pop_len(); /* If */
1511 }
1512
1513 /* Default case: Return (Buffer (One) { 0x0 }) */
1514 acpigen_write_return_singleton_buffer(0x0);
1515
1516 acpigen_pop_len(); /* If (LEqual (Local0, ToUUID(uuid))) */
1517
1518}
1519
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001520/*
1521 * Generate ACPI AML code for _DSM method.
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301522 * This function takes as input array of uuid for the device, set of callbacks
1523 * and argument to pass into the callbacks. Callbacks should ensure that Local0
1524 * and Local1 are left untouched. Use of Local2-Local7 is permitted in
1525 * callbacks.
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001526 *
1527 * Arguments passed into _DSM method:
1528 * Arg0 = UUID
1529 * Arg1 = Revision
1530 * Arg2 = Function index
1531 * Arg3 = Function specific arguments
1532 *
1533 * AML code generated would look like:
1534 * Method (_DSM, 4, Serialized) {
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301535 * ToBuffer (Arg0, Local0)
1536 * If (LEqual (Local0, ToUUID(uuid))) {
1537 * ToInteger (Arg2, Local1)
1538 * If (LEqual (Local1, 0)) {
1539 * <acpigen by callback[0]>
1540 * }
1541 * ...
1542 * If (LEqual (Local1, n)) {
1543 * <acpigen by callback[n]>
1544 * }
1545 * Return (Buffer (One) { 0x0 })
1546 * }
1547 * ...
1548 * If (LEqual (Local0, ToUUID(uuidn))) {
1549 * ...
1550 * }
1551 * Return (Buffer (One) { 0x0 })
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001552 * }
1553 */
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301554void acpigen_write_dsm_uuid_arr(struct dsm_uuid *ids, size_t count)
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001555{
1556 size_t i;
1557
1558 /* Method (_DSM, 4, Serialized) */
1559 acpigen_write_method_serialized("_DSM", 0x4);
1560
1561 /* ToBuffer (Arg0, Local0) */
1562 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
1563
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001564 for (i = 0; i < count; i++)
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301565 acpigen_write_dsm_uuid(&ids[i]);
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001566
Naresh G Solankiab77cd42016-11-15 10:13:15 +05301567 /* Return (Buffer (One) { 0x0 }) */
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001568 acpigen_write_return_singleton_buffer(0x0);
1569
Furquan Shaikhc00bd182016-10-21 16:37:41 -07001570 acpigen_pop_len(); /* Method _DSM */
1571}
1572
Matt Delcob425bc82018-08-13 13:36:27 -07001573#define CPPC_PACKAGE_NAME "\\GCPC"
1574
1575void acpigen_write_CPPC_package(const struct cppc_config *config)
1576{
1577 u32 i;
1578 u32 max;
1579 switch (config->version) {
1580 case 1:
1581 max = CPPC_MAX_FIELDS_VER_1;
1582 break;
1583 case 2:
1584 max = CPPC_MAX_FIELDS_VER_2;
1585 break;
1586 case 3:
1587 max = CPPC_MAX_FIELDS_VER_3;
1588 break;
1589 default:
1590 printk(BIOS_ERR, "ERROR: CPPC version %u is not implemented\n",
1591 config->version);
1592 return;
1593 }
1594 acpigen_write_name(CPPC_PACKAGE_NAME);
1595
1596 /* Adding 2 to account for length and version fields */
1597 acpigen_write_package(max + 2);
1598 acpigen_write_dword(max + 2);
1599
1600 acpigen_write_byte(config->version);
1601
1602 for (i = 0; i < max; ++i) {
1603 const acpi_addr_t *reg = &(config->regs[i]);
1604 if (reg->space_id == ACPI_ADDRESS_SPACE_MEMORY &&
Elyes HAOUAS721cb8a2020-06-23 09:13:42 +02001605 reg->bit_width == 32 && reg->access_size == ACPI_ACCESS_SIZE_UNDEFINED) {
Matt Delcob425bc82018-08-13 13:36:27 -07001606 acpigen_write_dword(reg->addrl);
1607 } else {
1608 acpigen_write_register_resource(reg);
1609 }
1610 }
1611 acpigen_pop_len();
1612}
1613
1614void acpigen_write_CPPC_method(void)
1615{
1616 acpigen_write_method("_CPC", 0);
1617 acpigen_emit_byte(RETURN_OP);
1618 acpigen_emit_namestring(CPPC_PACKAGE_NAME);
1619 acpigen_pop_len();
1620}
1621
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001622/*
1623 * Generate ACPI AML code for _ROM method.
1624 * This function takes as input ROM data and ROM length.
1625 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001626 * The ACPI spec isn't clear about what should happen at the end of the
1627 * ROM. Tests showed that it shouldn't truncate, but fill the remaining
1628 * bytes in the returned buffer with zeros.
1629 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001630 * Arguments passed into _DSM method:
1631 * Arg0 = Offset in Bytes
1632 * Arg1 = Bytes to return
1633 *
1634 * Example:
1635 * acpigen_write_rom(0xdeadbeef, 0x10000)
1636 *
1637 * AML code generated would look like:
1638 * Method (_ROM, 2, NotSerialized) {
1639 *
1640 * OperationRegion("ROMS", SYSTEMMEMORY, 0xdeadbeef, 0x10000)
1641 * Field (ROMS, AnyAcc, NoLock, Preserve)
1642 * {
1643 * Offset (0),
1644 * RBF0, 0x80000
1645 * }
1646 *
1647 * Store (Arg0, Local0)
1648 * Store (Arg1, Local1)
1649 *
1650 * If (LGreater (Local1, 0x1000))
1651 * {
1652 * Store (0x1000, Local1)
1653 * }
1654 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001655 * Store (Local1, Local3)
1656 *
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001657 * If (LGreater (Local0, 0x10000))
1658 * {
1659 * Return(Buffer(Local1){0})
1660 * }
1661 *
1662 * If (LGreater (Local0, 0x0f000))
1663 * {
1664 * Subtract (0x10000, Local0, Local2)
1665 * If (LGreater (Local1, Local2))
1666 * {
1667 * Store (Local2, Local1)
1668 * }
1669 * }
1670 *
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001671 * Name (ROM1, Buffer (Local3) {0})
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001672 *
1673 * Multiply (Local0, 0x08, Local0)
1674 * Multiply (Local1, 0x08, Local1)
1675 *
1676 * CreateField (RBF0, Local0, Local1, TMPB)
1677 * Store (TMPB, ROM1)
1678 * Return (ROM1)
1679 * }
1680 */
1681
1682void acpigen_write_rom(void *bios, const size_t length)
1683{
1684 ASSERT(bios)
1685 ASSERT(length)
1686
Jonathan Neuschäfer6b0102d2018-09-12 12:26:45 +02001687 /* Method (_ROM, 2, Serialized) */
Marc Jones24462e62018-08-15 23:57:28 -06001688 acpigen_write_method_serialized("_ROM", 2);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001689
1690 /* OperationRegion("ROMS", SYSTEMMEMORY, current, length) */
1691 struct opregion opreg = OPREGION("ROMS", SYSTEMMEMORY,
1692 (uintptr_t)bios, length);
1693 acpigen_write_opregion(&opreg);
1694
1695 struct fieldlist l[] = {
1696 FIELDLIST_OFFSET(0),
1697 FIELDLIST_NAMESTR("RBF0", 8 * length),
1698 };
1699
1700 /* Field (ROMS, AnyAcc, NoLock, Preserve)
1701 * {
1702 * Offset (0),
1703 * RBF0, 0x80000
1704 * } */
1705 acpigen_write_field(opreg.name, l, 2, FIELD_ANYACC |
1706 FIELD_NOLOCK | FIELD_PRESERVE);
1707
1708 /* Store (Arg0, Local0) */
1709 acpigen_write_store();
1710 acpigen_emit_byte(ARG0_OP);
1711 acpigen_emit_byte(LOCAL0_OP);
1712
1713 /* Store (Arg1, Local1) */
1714 acpigen_write_store();
1715 acpigen_emit_byte(ARG1_OP);
1716 acpigen_emit_byte(LOCAL1_OP);
1717
1718 /* ACPI SPEC requires to return at maximum 4KiB */
1719 /* If (LGreater (Local1, 0x1000)) */
1720 acpigen_write_if();
1721 acpigen_emit_byte(LGREATER_OP);
1722 acpigen_emit_byte(LOCAL1_OP);
1723 acpigen_write_integer(0x1000);
1724
1725 /* Store (0x1000, Local1) */
1726 acpigen_write_store();
1727 acpigen_write_integer(0x1000);
1728 acpigen_emit_byte(LOCAL1_OP);
1729
1730 /* Pop if */
1731 acpigen_pop_len();
1732
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001733 /* Store (Local1, Local3) */
1734 acpigen_write_store();
1735 acpigen_emit_byte(LOCAL1_OP);
1736 acpigen_emit_byte(LOCAL3_OP);
1737
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001738 /* If (LGreater (Local0, length)) */
1739 acpigen_write_if();
1740 acpigen_emit_byte(LGREATER_OP);
1741 acpigen_emit_byte(LOCAL0_OP);
1742 acpigen_write_integer(length);
1743
1744 /* Return(Buffer(Local1){0}) */
1745 acpigen_emit_byte(RETURN_OP);
1746 acpigen_emit_byte(BUFFER_OP);
1747 acpigen_write_len_f();
1748 acpigen_emit_byte(LOCAL1_OP);
1749 acpigen_emit_byte(0);
1750 acpigen_pop_len();
1751
1752 /* Pop if */
1753 acpigen_pop_len();
1754
1755 /* If (LGreater (Local0, length - 4096)) */
1756 acpigen_write_if();
1757 acpigen_emit_byte(LGREATER_OP);
1758 acpigen_emit_byte(LOCAL0_OP);
1759 acpigen_write_integer(length - 4096);
1760
1761 /* Subtract (length, Local0, Local2) */
1762 acpigen_emit_byte(SUBTRACT_OP);
1763 acpigen_write_integer(length);
1764 acpigen_emit_byte(LOCAL0_OP);
1765 acpigen_emit_byte(LOCAL2_OP);
1766
1767 /* If (LGreater (Local1, Local2)) */
1768 acpigen_write_if();
1769 acpigen_emit_byte(LGREATER_OP);
1770 acpigen_emit_byte(LOCAL1_OP);
1771 acpigen_emit_byte(LOCAL2_OP);
1772
1773 /* Store (Local2, Local1) */
1774 acpigen_write_store();
1775 acpigen_emit_byte(LOCAL2_OP);
1776 acpigen_emit_byte(LOCAL1_OP);
1777
1778 /* Pop if */
1779 acpigen_pop_len();
1780
1781 /* Pop if */
1782 acpigen_pop_len();
1783
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001784 /* Name (ROM1, Buffer (Local3) {0}) */
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001785 acpigen_write_name("ROM1");
1786 acpigen_emit_byte(BUFFER_OP);
1787 acpigen_write_len_f();
Patrick Rudolph65cbbe72018-05-02 19:07:57 +02001788 acpigen_emit_byte(LOCAL3_OP);
Patrick Rudolph6be6df02017-04-28 16:34:26 +02001789 acpigen_emit_byte(0);
1790 acpigen_pop_len();
1791
1792 /* Multiply (Local1, 0x08, Local1) */
1793 acpigen_emit_byte(MULTIPLY_OP);
1794 acpigen_emit_byte(LOCAL1_OP);
1795 acpigen_write_integer(0x08);
1796 acpigen_emit_byte(LOCAL1_OP);
1797
1798 /* Multiply (Local0, 0x08, Local0) */
1799 acpigen_emit_byte(MULTIPLY_OP);
1800 acpigen_emit_byte(LOCAL0_OP);
1801 acpigen_write_integer(0x08);
1802 acpigen_emit_byte(LOCAL0_OP);
1803
1804 /* CreateField (RBF0, Local0, Local1, TMPB) */
1805 acpigen_emit_ext_op(CREATEFIELD_OP);
1806 acpigen_emit_namestring("RBF0");
1807 acpigen_emit_byte(LOCAL0_OP);
1808 acpigen_emit_byte(LOCAL1_OP);
1809 acpigen_emit_namestring("TMPB");
1810
1811 /* Store (TMPB, ROM1) */
1812 acpigen_write_store();
1813 acpigen_emit_namestring("TMPB");
1814 acpigen_emit_namestring("ROM1");
1815
1816 /* Return (ROM1) */
1817 acpigen_emit_byte(RETURN_OP);
1818 acpigen_emit_namestring("ROM1");
1819
1820 /* Pop method */
1821 acpigen_pop_len();
1822}
1823
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001824/* Soc-implemented functions -- weak definitions. */
Aaron Durbin64031672018-04-21 14:45:32 -06001825int __weak acpigen_soc_read_rx_gpio(unsigned int gpio_num)
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001826{
1827 printk(BIOS_ERR, "ERROR: %s not implemented\n", __func__);
1828 acpigen_write_debug_string("read_rx_gpio not available");
1829 return -1;
1830}
1831
Aaron Durbin64031672018-04-21 14:45:32 -06001832int __weak acpigen_soc_get_tx_gpio(unsigned int gpio_num)
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001833{
1834 printk(BIOS_ERR, "ERROR: %s not implemented\n", __func__);
1835 acpigen_write_debug_string("get_tx_gpio not available");
1836 return -1;
1837}
1838
Aaron Durbin64031672018-04-21 14:45:32 -06001839int __weak acpigen_soc_set_tx_gpio(unsigned int gpio_num)
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001840{
1841 printk(BIOS_ERR, "ERROR: %s not implemented\n", __func__);
1842 acpigen_write_debug_string("set_tx_gpio not available");
1843 return -1;
1844}
1845
Aaron Durbin64031672018-04-21 14:45:32 -06001846int __weak acpigen_soc_clear_tx_gpio(unsigned int gpio_num)
Furquan Shaikh0a48aee2016-10-20 07:12:49 -07001847{
1848 printk(BIOS_ERR, "ERROR: %s not implemented\n", __func__);
1849 acpigen_write_debug_string("clear_tx_gpio not available");
1850 return -1;
1851}
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08001852
1853/*
1854 * Helper functions for enabling/disabling Tx GPIOs based on the GPIO
1855 * polarity. These functions end up calling acpigen_soc_{set,clear}_tx_gpio to
1856 * make callbacks into SoC acpigen code.
1857 *
1858 * Returns 0 on success and -1 on error.
1859 */
1860int acpigen_enable_tx_gpio(struct acpi_gpio *gpio)
1861{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07001862 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08001863 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07001864 else
1865 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08001866}
1867
1868int acpigen_disable_tx_gpio(struct acpi_gpio *gpio)
1869{
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07001870 if (gpio->active_low)
Furquan Shaikhbf4845d2017-02-20 22:56:25 -08001871 return acpigen_soc_set_tx_gpio(gpio->pins[0]);
1872 else
1873 return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
1874}
Jonathan Zhang71299c22020-01-27 11:38:57 -08001875
Rajat Jain310623b2020-02-26 11:02:53 -08001876void acpigen_get_rx_gpio(struct acpi_gpio *gpio)
1877{
1878 acpigen_soc_read_rx_gpio(gpio->pins[0]);
1879
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07001880 if (gpio->active_low)
Rajat Jain310623b2020-02-26 11:02:53 -08001881 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
1882}
1883
Duncan Laurie2fe74712020-06-01 17:36:56 -07001884void acpigen_get_tx_gpio(struct acpi_gpio *gpio)
1885{
1886 acpigen_soc_get_tx_gpio(gpio->pins[0]);
1887
Furquan Shaikhd2d5e442020-07-01 01:37:13 -07001888 if (gpio->active_low)
Duncan Laurie2fe74712020-06-01 17:36:56 -07001889 acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
1890}
1891
Jonathan Zhang71299c22020-01-27 11:38:57 -08001892/* refer to ACPI 6.4.3.5.3 Word Address Space Descriptor section for details */
1893void acpigen_resource_word(u16 res_type, u16 gen_flags, u16 type_flags, u16 gran,
1894 u16 range_min, u16 range_max, u16 translation, u16 length)
1895{
1896 acpigen_emit_byte(0x88);
1897 /* Byte 1+2: length (0x000d) */
1898 acpigen_emit_byte(0x0d);
1899 acpigen_emit_byte(0x00);
1900 /* resource type */
1901 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
1902 /* general flags */
1903 acpigen_emit_byte(gen_flags);
1904 /* type flags */
1905 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
1906 acpigen_emit_byte(type_flags);
1907 /* granularity, min, max, translation, length */
1908 acpigen_emit_word(gran);
1909 acpigen_emit_word(range_min);
1910 acpigen_emit_word(range_max);
1911 acpigen_emit_word(translation);
1912 acpigen_emit_word(length);
1913}
1914
1915/* refer to ACPI 6.4.3.5.2 DWord Address Space Descriptor section for details */
1916void acpigen_resource_dword(u16 res_type, u16 gen_flags, u16 type_flags,
1917 u32 gran, u32 range_min, u32 range_max, u32 translation, u32 length)
1918{
1919 acpigen_emit_byte(0x87);
1920 /* Byte 1+2: length (0023) */
1921 acpigen_emit_byte(23);
1922 acpigen_emit_byte(0x00);
1923 /* resource type */
1924 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
1925 /* general flags */
1926 acpigen_emit_byte(gen_flags);
1927 /* type flags */
1928 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
1929 acpigen_emit_byte(type_flags);
1930 /* granularity, min, max, translation, length */
1931 acpigen_emit_dword(gran);
1932 acpigen_emit_dword(range_min);
1933 acpigen_emit_dword(range_max);
1934 acpigen_emit_dword(translation);
1935 acpigen_emit_dword(length);
1936}
1937
1938static void acpigen_emit_qword(u64 data)
1939{
1940 acpigen_emit_dword(data & 0xffffffff);
1941 acpigen_emit_dword((data >> 32) & 0xffffffff);
1942}
1943
1944/* refer to ACPI 6.4.3.5.1 QWord Address Space Descriptor section for details */
1945void acpigen_resource_qword(u16 res_type, u16 gen_flags, u16 type_flags,
1946 u64 gran, u64 range_min, u64 range_max, u64 translation, u64 length)
1947{
1948 acpigen_emit_byte(0x8a);
1949 /* Byte 1+2: length (0x002b) */
1950 acpigen_emit_byte(0x2b);
1951 acpigen_emit_byte(0x00);
1952 /* resource type */
1953 acpigen_emit_byte(res_type); // 0 - mem, 1 - io, 2 - bus
1954 /* general flags */
1955 acpigen_emit_byte(gen_flags);
1956 /* type flags */
1957 // refer to ACPI Table 6-234 (Memory), 6-235 (IO), 6-236 (Bus) for details
1958 acpigen_emit_byte(type_flags);
1959 /* granularity, min, max, translation, length */
1960 acpigen_emit_qword(gran);
1961 acpigen_emit_qword(range_min);
1962 acpigen_emit_qword(range_max);
1963 acpigen_emit_qword(translation);
1964 acpigen_emit_qword(length);
1965}
Furquan Shaikh1a829232020-04-23 11:11:05 -07001966
1967void acpigen_write_ADR(uint64_t adr)
1968{
1969 acpigen_write_name_qword("_ADR", adr);
1970}
1971
1972void acpigen_write_ADR_pci_devfn(pci_devfn_t devfn)
1973{
1974 /*
1975 * _ADR for PCI Bus is encoded as follows:
1976 * [63:32] - unused
1977 * [31:16] - device #
1978 * [15:0] - function #
1979 */
1980 acpigen_write_ADR(PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn));
1981}
1982
1983void acpigen_write_ADR_pci_device(const struct device *dev)
1984{
1985 assert(dev->path.type == DEVICE_PATH_PCI);
1986 acpigen_write_ADR_pci_devfn(dev->path.pci.devfn);
1987}
Duncan Laurie08a942f2020-04-29 12:13:14 -07001988
1989/**
1990 * acpigen_write_ADR_soundwire_device() - SoundWire ACPI Device Address Encoding.
1991 * @address: SoundWire device address properties.
1992 *
1993 * From SoundWire Discovery and Configuration Specification Version 1.0 Table 3.
1994 *
1995 * 63..52 - Reserved (0)
1996 * 51..48 - Zero-based SoundWire Link ID, relative to the immediate parent.
1997 * Used when a Controller has multiple master devices, each producing a
1998 * separate SoundWire Link. Set to 0 for single-link controllers.
1999 * 47..0 - SoundWire Device ID Encoding from specification version 1.2 table 88
2000 * 47..44 - SoundWire specification version that this device supports
2001 * 43..40 - Unique ID for multiple devices
2002 * 39..24 - MIPI standard manufacturer code
2003 * 23..08 - Vendor defined part ID
2004 * 07..00 - MIPI class encoding
2005 */
2006void acpigen_write_ADR_soundwire_device(const struct soundwire_address *address)
2007{
2008 acpigen_write_ADR((((uint64_t)address->link_id & 0xf) << 48) |
2009 (((uint64_t)address->version & 0xf) << 44) |
2010 (((uint64_t)address->unique_id & 0xf) << 40) |
2011 (((uint64_t)address->manufacturer_id & 0xffff) << 24) |
2012 (((uint64_t)address->part_id & 0xffff) << 8) |
2013 (((uint64_t)address->class & 0xff)));
2014}
Tim Wawrzynczakf6945022020-06-04 15:18:47 -06002015
2016void acpigen_notify(const char *namestr, int value)
2017{
2018 acpigen_emit_byte(NOTIFY_OP);
2019 acpigen_emit_namestring(namestr);
2020 acpigen_write_integer(value);
2021}
Aaron Durbin80bc0912020-08-19 23:17:42 -06002022
2023static void _create_field(uint8_t aml_op, uint8_t srcop, size_t byte_offset, const char *name)
2024{
2025 acpigen_emit_byte(aml_op);
2026 acpigen_emit_byte(srcop);
2027 acpigen_write_integer(byte_offset);
2028 acpigen_emit_namestring(name);
2029}
2030
2031void acpigen_write_create_byte_field(uint8_t op, size_t byte_offset, const char *name)
2032{
2033 _create_field(CREATE_BYTE_OP, op, byte_offset, name);
2034}
2035
2036void acpigen_write_create_word_field(uint8_t op, size_t byte_offset, const char *name)
2037{
2038 _create_field(CREATE_WORD_OP, op, byte_offset, name);
2039}
2040
2041void acpigen_write_create_dword_field(uint8_t op, size_t byte_offset, const char *name)
2042{
2043 _create_field(CREATE_DWORD_OP, op, byte_offset, name);
2044}
2045
2046void acpigen_write_create_qword_field(uint8_t op, size_t byte_offset, const char *name)
2047{
2048 _create_field(CREATE_QWORD_OP, op, byte_offset, name);
2049}
Jason Gleneskca36aed2020-09-15 21:01:57 -07002050
2051void acpigen_write_pct_package(const acpi_addr_t *perf_ctrl, const acpi_addr_t *perf_sts)
2052{
2053 acpigen_write_name("_PCT");
2054 acpigen_write_package(0x02);
2055 acpigen_write_register_resource(perf_ctrl);
2056 acpigen_write_register_resource(perf_sts);
2057
2058 acpigen_pop_len();
2059}
2060
2061void acpigen_write_xpss_package(const struct acpi_xpss_sw_pstate *pstate_value)
2062{
2063 acpigen_write_package(0x08);
2064 acpigen_write_dword(pstate_value->core_freq);
2065 acpigen_write_dword(pstate_value->power);
2066 acpigen_write_dword(pstate_value->transition_latency);
2067 acpigen_write_dword(pstate_value->bus_master_latency);
2068
2069 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_value, sizeof(uint64_t));
2070 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_value, sizeof(uint64_t));
2071 acpigen_write_byte_buffer((uint8_t *)&pstate_value->control_mask, sizeof(uint64_t));
2072 acpigen_write_byte_buffer((uint8_t *)&pstate_value->status_mask, sizeof(uint64_t));
2073
2074 acpigen_pop_len();
2075}
2076
2077void acpigen_write_xpss_object(const struct acpi_xpss_sw_pstate *pstate_values, size_t nentries)
2078{
2079 size_t pstate;
2080
2081 acpigen_write_name("XPSS");
2082 acpigen_write_package(nentries);
2083 for (pstate = 0; pstate < nentries; pstate++) {
2084 acpigen_write_xpss_package(pstate_values);
2085 pstate_values++;
2086 }
2087
2088 acpigen_pop_len();
2089}